# This is a BitKeeper generated patch for the following project: # Project Name: linux-arm-2.4-ds kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet linux-2.4.21-rmk1 -> 1.195 # drivers/mtd/maps/netsc520.c 1.1 -> 1.2 # include/asm-arm/mach/pci.h 1.1 -> 1.2 # drivers/mtd/maps/autcpu12-nvram.c 1.1 -> 1.2 # arch/arm/kernel/dma.c 1.1.1.1 -> 1.3 # include/linux/jffs2_fs_sb.h 1.2 -> 1.3 # include/asm-arm/assembler.h 1.1 -> 1.2 # arch/arm/mm/init.c 1.4.1.1 -> 1.6 # drivers/mtd/maps/tqm8xxl.c 1.2 -> 1.3 # drivers/serial/Makefile 1.1.1.2 -> 1.5 # drivers/mtd/maps/pcmciamtd.c 1.1 -> 1.2 # arch/arm/kernel/semaphore.c 1.3.1.1 -> 1.6 # drivers/mtd/maps/pb1xxx-flash.c 1.3 -> 1.4 # fs/Config.in 1.4 -> 1.5 # drivers/mtd/nand/edb7312.c 1.1 -> 1.2 # drivers/mtd/maps/cfi_flagadm.c 1.1 -> 1.2 # drivers/mtd/maps/elan-104nc.c 1.3 -> 1.4 # include/linux/serial.h 1.2.1.1 -> 1.5 # drivers/i2c/Config.in 1.4.1.2 -> 1.10 # arch/arm/lib/testclearbit.S 1.1 -> 1.2 # arch/arm/boot/Makefile 1.4.1.6 -> 1.19 # drivers/mtd/nand/autcpu12.c 1.2 -> 1.3 # arch/arm/mm/alignment.c 1.2.1.1 -> 1.4 # fs/jffs2/nodelist.h 1.4 -> 1.5 # drivers/mtd/Config.in 1.3 -> 1.4 # include/linux/mtd/doc2000.h 1.1 -> 1.2 # drivers/mtd/chips/cfi_cmdset_0001.c 1.4 -> 1.5 # drivers/mtd/devices/Config.in 1.2 -> 1.3 # fs/jffs2/compr.c 1.1 -> 1.2 # include/linux/serial_core.h 1.1.1.3 -> 1.5 # arch/arm/lib/csumpartialcopygeneric.S 1.1 -> 1.3 # arch/arm/nwfpe/fpa11_cpdt.c 1.2.1.1 -> 1.4 # drivers/mtd/maps/cdb89712.c 1.1 -> 1.2 # drivers/mtd/maps/impa7.c 1.2 -> 1.3 # drivers/serial/Config.in 1.1.1.3 -> 1.7 # drivers/mtd/maps/Makefile 1.3.1.3 -> 1.13 # fs/jffs2/file.c 1.3 -> 1.4 # include/linux/pci_ids.h 1.2.1.2 -> 1.8 # drivers/mtd/maps/integrator-flash.c 1.1 -> 1.2 # Makefile 1.10.1.9 -> 1.35 # drivers/mtd/chips/cfi_cmdset_0020.c 1.1 -> 1.2 # drivers/mtd/chips/jedec_probe.c 1.4 -> 1.5 # drivers/char/Makefile 1.6.1.1 -> 1.11 # drivers/mtd/maps/edb7312.c 1.2 -> 1.3 # include/asm-arm/proc-armv/system.h 1.1.1.2 -> 1.4 # arch/arm/mm/mm-armv.c 1.4.1.3 -> 1.11 # kernel/ksyms.c 1.4 -> 1.5 # drivers/mtd/maps/sun_uflash.c 1.1 -> 1.2 # drivers/mtd/devices/ms02-nv.c 1.1 -> 1.2 # fs/jffs2/build.c 1.3 -> 1.4 # arch/arm/lib/setbit.S 1.1 -> 1.2 # drivers/i2c/Makefile 1.4.1.2 -> 1.11 # drivers/net/wireless/Config.in 1.3 -> 1.4 # include/linux/mtd/cfi.h 1.3 -> 1.4 # drivers/mtd/maps/l440gx.c 1.2 -> 1.3 # include/asm-arm/unaligned.h 1.1 -> 1.2 # arch/arm/mm/Makefile 1.2.1.2 -> 1.5 # drivers/mtd/chips/sharp.c 1.3 -> 1.4 # fs/jffs2/compr_rubin.h 1.1 -> 1.2 # arch/arm/lib/changebit.S 1.1 -> 1.2 # arch/arm/lib/memcpy.S 1.1 -> 1.2 # include/linux/mtd/jedec.h 1.1 -> 1.2 # arch/arm/tools/mach-types 1.9.1.8 -> 1.23 # fs/jffs2/write.c 1.2 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx_osm.c 1.1.1.1 -> 1.5 # include/asm-arm/xor.h 1.2 -> 1.3 # arch/arm/lib/testsetbit.S 1.1 -> 1.2 # mm/vmalloc.c 1.2.1.2 -> 1.5 # drivers/mtd/devices/docecc.c 1.1 -> 1.2 # fs/jffs2/dir.c 1.4 -> 1.5 # drivers/char/sysrq.c 1.1.1.1 -> 1.3 # arch/arm/lib/io-readsb.S 1.1 -> 1.2 # drivers/mtd/devices/lart.c 1.1 -> 1.2 # include/asm-arm/proc-armv/pgtable.h 1.1 -> 1.2 # drivers/mtd/maps/epxa10db-flash.c 1.1 -> 1.2 # include/linux/fs.h 1.4 -> 1.5 # drivers/mtd/maps/dilnetpc.c 1.1 -> 1.2 # arch/arm/kernel/entry-armv.S 1.2.1.5 -> 1.21 # drivers/mtd/ftl.c 1.3 -> 1.4 # include/linux/rbtree.h 1.1 -> 1.2 # drivers/mtd/devices/docprobe.c 1.3 -> 1.4 # include/linux/sched.h 1.2.1.2 -> 1.6 # drivers/mtd/chips/map_ram.c 1.1 -> 1.2 # drivers/mtd/mtdcore.c 1.3 -> 1.4 # drivers/mtd/redboot.c 1.1 -> 1.2 # drivers/net/Makefile 1.2.1.3 -> 1.6 # drivers/mtd/maps/mbx860.c 1.1 -> 1.2 # drivers/mtd/nand/nand.c 1.4 -> 1.5 # include/asm-arm/proc-fns.h 1.1.1.1 -> 1.3 # drivers/mtd/maps/dc21285.c 1.2 -> 1.3 # drivers/mtd/maps/vmax301.c 1.1 -> 1.2 # drivers/mtd/chips/gen_probe.c 1.3 -> 1.4 # drivers/mtd/devices/blkmtd.c 1.4 -> 1.5 # drivers/mtd/nand/spia.c 1.2 -> 1.3 # drivers/mtd/maps/pci.c 1.2 -> 1.3 # drivers/mtd/maps/physmap.c 1.4 -> 1.5 # fs/jffs2/nodelist.c 1.4 -> 1.5 # drivers/mtd/nftlcore.c 1.3 -> 1.4 # drivers/mtd/chips/cfi_cmdset_0002.c 1.4 -> 1.5 # arch/arm/lib/uaccess.S 1.1 -> 1.2 # include/asm-arm/checksum.h 1.1 -> 1.2 # drivers/mtd/mtdblock_ro.c 1.4 -> 1.5 # drivers/mtd/maps/tsunami_flash.c 1.1 -> 1.2 # fs/jffs2/compr_rtime.c 1.1 -> 1.2 # fs/jffs2/crc32.h 1.1 -> 1.2 # drivers/mtd/devices/ms02-nv.h 1.1 -> 1.2 # drivers/mtd/afs.c 1.2 -> 1.3 # drivers/mtd/mtdchar.c 1.2 -> 1.3 # include/linux/mtd/mtd.h 1.3 -> 1.4 # drivers/mtd/maps/solutionengine.c 1.2 -> 1.3 # arch/arm/tools/getconstants.c 1.1 -> 1.2 # drivers/char/tty_io.c 1.2.1.3 -> 1.6 # drivers/mtd/devices/Makefile 1.2 -> 1.3 # fs/jffs2/readinode.c 1.3 -> 1.4 # drivers/mtd/mtdblock.c 1.6 -> 1.7 # include/linux/mtd/nand.h 1.4 -> 1.5 # drivers/mtd/mtdpart.c 1.4 -> 1.5 # fs/jffs2/super.c 1.3 -> 1.4 # fs/jffs2/pushpull.h 1.1 -> 1.2 # drivers/mtd/chips/map_rom.c 1.1 -> 1.2 # fs/jffs2/crc32.c 1.1 -> 1.2 # drivers/mtd/maps/sbc_gxx.c 1.4 -> 1.5 # fs/jffs2/read.c 1.2 -> 1.3 # arch/arm/config.in 1.6.1.8 -> 1.38 # drivers/ide/ide-cd.h 1.2.1.1 -> 1.4 # arch/arm/kernel/time.c 1.3 -> 1.4 # Documentation/Configure.help 1.4.1.3 -> 1.14 # include/linux/serial_reg.h 1.1.1.1 -> 1.3 # drivers/mtd/maps/dbox2-flash.c 1.1 -> 1.2 # drivers/mtd/maps/redwood.c 1.1 -> 1.2 # drivers/mtd/devices/mtdram.c 1.4 -> 1.5 # fs/jffs2/ioctl.c 1.1 -> 1.2 # drivers/mtd/maps/scb2_flash.c 1.1 -> 1.2 # arch/arm/Makefile 1.5.1.7 -> 1.24 # drivers/mtd/maps/iq80310.c 1.2 -> (deleted) # fs/jffs2/compr_rubin.c 1.1 -> 1.2 # drivers/char/Config.in 1.5.1.1 -> 1.10 # arch/arm/lib/getuser.S 1.1 -> 1.3 # drivers/mtd/maps/octagon-5066.c 1.2 -> 1.3 # drivers/mtd/maps/ocelot.c 1.1 -> 1.2 # drivers/mtd/maps/scx200_docflash.c 1.1 -> 1.2 # drivers/mtd/nftlmount.c 1.4 -> 1.5 # fs/jffs2/gc.c 1.4 -> 1.5 # include/linux/jffs2_fs_i.h 1.1 -> 1.2 # drivers/mtd/devices/pmc551.c 1.3 -> 1.4 # fs/jffs2/nodemgmt.c 1.2 -> 1.3 # include/linux/mtd/flashchip.h 1.2 -> 1.3 # include/linux/mtd/nand_ecc.h 1.1 -> 1.2 # CREDITS 1.3.1.2 -> 1.7 # drivers/mtd/cmdlinepart.c 1.1 -> 1.2 # drivers/net/Config.in 1.2.1.4 -> 1.6 # include/linux/crc32.h 1.1 -> 1.2 # fs/jffs2/erase.c 1.2 -> 1.3 # arch/arm/lib/putuser.S 1.1 -> 1.3 # drivers/mtd/chips/jedec.c 1.3 -> 1.4 # include/linux/mtd/map.h 1.3 -> 1.4 # fs/inode.c 1.3 -> 1.4 # arch/arm/kernel/bios32.c 1.1.1.1 -> 1.14 # include/asm-arm/proc-armv/processor.h 1.1.1.1 -> 1.3 # drivers/mtd/nand/Config.in 1.4 -> 1.5 # include/asm-arm/bitops.h 1.1.1.1 -> 1.3 # drivers/mtd/maps/pnc2000.c 1.1 -> 1.2 # arch/arm/kernel/Makefile 1.2.1.4 -> 1.12 # include/asm-arm/system.h 1.2.1.1 -> 1.4 # drivers/mtd/nand/Makefile 1.4 -> 1.5 # include/linux/jffs2.h 1.2 -> 1.3 # fs/jffs2/malloc.c 1.1 -> 1.2 # drivers/mtd/chips/map_absent.c 1.1 -> 1.2 # drivers/mtd/maps/rpxlite.c 1.1 -> 1.2 # drivers/mtd/maps/nettel.c 1.1 -> 1.2 # include/linux/i2c-id.h 1.4.1.1 -> 1.9 # include/asm-arm/uaccess.h 1.1 -> 1.2 # include/asm-arm/io.h 1.2.1.2 -> 1.5 # drivers/mtd/devices/doc2000.c 1.2 -> 1.3 # arch/arm/lib/io-writesb.S 1.1 -> 1.2 # arch/arm/boot/compressed/head.S 1.3.1.6 -> 1.14 # fs/jffs2/Makefile 1.2 -> 1.3 # arch/arm/mm/consistent.c 1.2.1.1 -> 1.5 # include/asm-arm/pci.h 1.2.1.2 -> 1.9 # include/linux/mtd/gen_probe.h 1.1 -> 1.2 # drivers/net/wireless/Makefile 1.2 -> 1.3 # arch/arm/kernel/setup.c 1.2.1.4 -> 1.8 # drivers/mtd/chips/amd_flash.c 1.3 -> 1.4 # arch/arm/kernel/armksyms.c 1.4.1.2 -> 1.7 # drivers/mtd/nand/nand_ecc.c 1.3 -> 1.4 # arch/arm/mm/fault-common.c 1.3.1.3 -> 1.8 # fs/jffs2/compr_zlib.c 1.2 -> 1.3 # include/linux/mtd/compatmac.h 1.5 -> 1.6 # drivers/mtd/Makefile 1.2.1.2 -> 1.6 # drivers/mtd/chips/cfi_probe.c 1.4 -> 1.5 # drivers/mtd/maps/amd76xrom.c 1.1 -> 1.2 # arch/arm/lib/findbit.S 1.1 -> 1.2 # arch/arm/mm/fault-armv.c 1.3.1.2 -> 1.8 # drivers/pci/pci.ids 1.2.1.2 -> 1.7 # drivers/scsi/Makefile 1.3.1.2 -> 1.6 # drivers/mtd/maps/Config.in 1.3.1.4 -> 1.15 # drivers/mtd/maps/ceiva.c 1.1 -> 1.2 # drivers/mtd/maps/cstm_mips_ixx.c 1.1 -> 1.2 # MAINTAINERS 1.6 -> 1.7 # include/asm-arm/memory.h 1.1.1.4 -> 1.6 # arch/arm/lib/io-writesw-armv4.S 1.1 -> 1.2 # drivers/mtd/devices/slram.c 1.3 -> 1.4 # arch/arm/lib/io-readsl-armv4.S 1.1 -> 1.2 # arch/arm/boot/compressed/Makefile 1.3.1.6 -> 1.10 # include/linux/mtd/partitions.h 1.2 -> 1.3 # drivers/mtd/maps/sc520cdp.c 1.2 -> 1.3 # arch/arm/lib/io-writesl.S 1.1 -> 1.2 # drivers/mtd/maps/lasat.c 1.1 -> 1.2 # arch/arm/kernel/head-armv.S 1.1.1.2 -> 1.4 # arch/arm/mm/proc-sa110.S 1.1.1.4 -> 1.7 # drivers/mtd/maps/fortunet.c 1.4 -> 1.5 # arch/arm/lib/testchangebit.S 1.1 -> 1.2 # drivers/char/serial.c 1.3.1.1 -> 1.9 # fs/jffs2/symlink.c 1.2 -> 1.3 # arch/arm/kernel/traps.c 1.4.1.2 -> 1.7 # drivers/mtd/devices/doc2001.c 1.2 -> 1.3 # include/linux/mtd/nftl.h 1.2 -> 1.3 # arch/arm/kernel/entry-common.S 1.2.1.1 -> 1.4 # drivers/mtd/nand/nand_ids.c 1.1 -> 1.2 # fs/jffs2/background.c 1.3 -> 1.4 # include/asm-arm/stat.h 1.1.1.1 -> 1.3 # drivers/mtd/chips/chipreg.c 1.2 -> 1.3 # include/asm-arm/proc-armv/uaccess.h 1.1 -> 1.2 # arch/arm/lib/clearbit.S 1.1 -> 1.2 # drivers/mtd/chips/Config.in 1.3 -> 1.4 # Rules.make 1.2.1.1 -> 1.4 # arch/arm/lib/csumpartial.S 1.1.1.1 -> 1.4 # drivers/mtd/mtdconcat.c 1.2 -> 1.3 # drivers/mtd/maps/uclinux.c 1.1 -> 1.2 # drivers/serial/core.c 1.1.1.3 -> 1.5 # init/main.c 1.2.1.1 -> 1.6 # arch/arm/lib/io-readsw-armv4.S 1.1 -> 1.2 # fs/jffs2/comprtest.c 1.1 -> 1.2 # drivers/mtd/chips/Makefile 1.3 -> 1.4 # arch/arm/kernel/debug-armv.S 1.3.1.4 -> 1.19 # fs/jffs2/scan.c 1.3 -> 1.4 # drivers/mtd/maps/sa1100-flash.c 1.9 -> 1.10 # (new) -> 1.7 arch/arm/mach-adifcc/brh-pci.c # (new) -> 1.1 drivers/net/wireless/hostap_compat.h # (new) -> 1.1 include/linux/rbtree-24.h # (new) -> 1.1 drivers/net/wireless/hostap_config.h # (new) -> 1.3 include/asm-arm/arch-ixp425/uncompress.h # (new) -> 1.1 include/asm-arm/arch-ixp425/irq.h # (new) -> 1.1 arch/arm/mach-iop3xx/dma.c # (new) -> 1.3 include/asm-arm/arch-iop3xx/iop321.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/system.h # (new) -> 1.1 include/asm-arm/arch-adifcc/io.h # (new) -> 1.1 drivers/net/wireless/hostap_80211.h # (new) -> 1.1 include/asm-arm/arch-adifcc/pci_auto.h # (new) -> 1.1 arch/arm/mach-ixp2000/ixp2000-kgdb.c # (new) -> 1.2 include/asm-arm/arch-adifcc/uncompress.h # (new) -> 1.1 include/asm-arm/arch-adifcc/system.h # (new) -> 1.1 include/asm-arm/arch-ixp425/memory.h # (new) -> 1.1 drivers/i2c/i2c-iop3xx.h # (new) -> 1.2 arch/arm/mach-iop3xx/iop321-irq.c # (new) -> 1.1 include/asm-arm/arch-ixp425/pci-bridge.h # (new) -> 1.13 include/asm-arm/arch-ixp2000/ixp2000.h # (new) -> 1.9 arch/arm/def-configs/iq80321 # (new) -> 1.2 arch/arm/mach-ixp2000/pci-auto.c # (new) -> 1.2 arch/arm/mach-iop3xx/iop310-irq.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/dma.h # (new) -> 1.1 arch/arm/mach-ixp425/prpmc1100-pci.c # (new) -> 1.6 include/asm-arm/arch-iop3xx/memory.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/vmalloc.h # (new) -> 1.4 include/asm-arm/arch-ixp2000/timex.h # (new) -> 1.1 include/asm-arm/arch-ixp425/time.h # (new) -> 1.1 include/asm-arm/arch-ixp425/pci_auto.h # (new) -> 1.3 drivers/mtd/maps/brh.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/pci.h # (new) -> 1.1 drivers/net/wireless/hostap_crypt_wep.c # (new) -> 1.2 include/asm-arm/arch-adifcc/timex.h # (new) -> 1.1 drivers/mtd/maps/h720x-flash.c # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/IQ80321 # (new) -> 1.4 include/asm-arm/arch-ixp2000/hardware.h # (new) -> 1.1 include/asm-arm/bitfield.h # (new) -> 1.1 drivers/net/wireless/hostap_crypt.c # (new) -> 1.1 Documentation/arm/XScale/IXP425/IXDP425 # (new) -> 1.1 include/asm-arm/arch-adifcc/irq.h # (new) -> 1.3 include/asm-arm/arch-ixp425/io.h # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/IQ80310 # (new) -> 1.5 include/asm-arm/arch-ixp425/ixp425.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/leds.h # (new) -> 1.1 include/asm-arm/kgdb.h # (new) -> 1.5 drivers/serial/ixp1200.c # (new) -> 1.1 include/asm-arm/arch-adifcc/param.h # (new) -> 1.1 arch/arm/mach-iop3xx/dma.h # (new) -> 1.6 include/asm-arm/arch-ixp2000/ixdp2800.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/param.h # (new) -> 1.1 drivers/mtd/maps/omap-toto-flash.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/vmalloc.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/serial_reg.h # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/aau.txt # (new) -> 1.3 arch/arm/mach-iop3xx/iq80310-irq.c # (new) -> 1.1 Documentation/arm/XScale/tlb-lock.txt # (new) -> 1.1 include/asm-arm/arch-ixp2000/memory.h # (new) -> 1.2 arch/arm/kernel/xscale-time.c # (new) -> 1.1 include/asm-arm/arch-adifcc/adi_evb.h # (new) -> 1.1 arch/arm/boot/compressed/big-endian.S # (new) -> 1.1 drivers/net/wireless/hostap_ioctl.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/irq.h # (new) -> 1.1 drivers/mtd/maps/lubbock-flash.c # (new) -> 1.1 arch/arm/mach-ixp425/ixdp425-pci.c # (new) -> 1.1 arch/arm/mach-adifcc/brh-time.c # (new) -> 1.1 drivers/net/wireless/hostap_proc.c # (new) -> 1.1 arch/arm/mach-adifcc/xs80200-irq.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/pci-bridge.h # (new) -> 1.6 arch/arm/mach-ixp2000/ixdp2400-pci.c # (new) -> 1.1 drivers/net/wireless/hostap_hw.c # (new) -> 1.1 arch/arm/mach-iop3xx/pci.c # (new) -> 1.1 drivers/mtd/maps/ebony.c # (new) -> 1.1 drivers/mtd/maps/ichxrom.c # (new) -> 1.1 arch/arm/mach-adifcc/pci.c # (new) -> 1.1 drivers/net/wireless/hostap_wext.h # (new) -> 1.1 Documentation/arm/IXP1200/README # (new) -> 1.1 drivers/char/ixp2000.h # (new) -> 1.1 arch/arm/mach-iop3xx/pmon.c # (new) -> 1.8 arch/arm/mach-ixp2000/ixdp2400-irq.c # (new) -> 1.1 arch/arm/mach-ixp425/gpio.c # (new) -> 1.1 drivers/net/wireless/hostap_80211_rx.c # (new) -> 1.1 drivers/char/pcf8594c-nvram.c # (new) -> 1.1 drivers/mtd/maps/iq80310.c # (new) -> 1.2 arch/arm/mach-iop3xx/message.c # (new) -> 1.3 arch/arm/mach-ixp2000/time.c # (new) -> 1.2 arch/arm/mach-iop3xx/iop321-time.c # (new) -> 1.1 drivers/mtd/devices/ixm1200.c # (new) -> 1.2 include/asm-arm/arch-adifcc/serial.h # (new) -> 1.1 include/asm-arm/arch-adifcc/time.h # (new) -> 1.3 include/asm-arm/arch-ixp425/serial.h # (new) -> 1.2 arch/arm/mach-ixp2000/slowport.c # (new) -> 1.15 arch/arm/mm/proc-xscale.S # (new) -> 1.2 include/asm-arm/arch-iop3xx/iop321-irqs.h # (new) -> 1.4 arch/arm/mach-ixp2000/mm.c # (new) -> 1.1 drivers/net/wireless/hostap_plx.c # (new) -> 1.6 arch/arm/def-configs/ixdp2400 # (new) -> 1.1 include/asm-arm/arch-ixp2000/time.h # (new) -> 1.1 arch/arm/mach-ixp425/pci-auto.c # (new) -> 1.4 include/asm-arm/arch-adifcc/memory.h # (new) -> 1.1 drivers/net/wireless/hostap_common.h # (new) -> 1.9 arch/arm/mach-iop3xx/arch.c # (new) -> 1.4 include/asm-arm/arch-iop3xx/hardware.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/slave.h # (new) -> 1.4 arch/arm/def-configs/ixdp2800 # (new) -> 1.3 include/asm-arm/arch-iop3xx/uncompress.h # (new) -> 1.9 arch/arm/mach-ixp2000/ixdp2800-pci.c # (new) -> 1.3 arch/arm/mach-iop3xx/aau.h # (new) -> 1.8 arch/arm/mach-ixp2000/ixp2000-irq.c # (new) -> 1.4 include/asm-arm/arch-ixp2000/gpio.h # (new) -> 1.1 arch/arm/mach-adifcc/pci-auto.c # (new) -> 1.5 arch/arm/mach-ixp2000/arch.c # (new) -> 1.2 drivers/mtd/maps/iop3xx.c # (new) -> 1.1 arch/arm/def-configs/ixp12eb # (new) -> 1.2 include/asm-arm/arch-ixp425/dma.h # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/pmon.txt # (new) -> 1.1 include/asm-arm/arch-iop3xx/xor.h # (new) -> 1.4 arch/arm/mach-iop3xx/iop321-pci.c # (new) -> 1.3 include/asm-arm/arch-iop3xx/serial.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/io.h # (new) -> 1.1 drivers/i2c/i2c-adap-ixdp2400.c # (new) -> 1.1 arch/arm/mm/xscale-lock.c # (new) -> 1.3 include/asm-arm/arch-ixp2000/serial.h # (new) -> 1.1 arch/arm/mach-adifcc/brh-irq.c # (new) -> 1.1 arch/arm/mach-iop3xx/mm.c # (new) -> 1.1 include/asm-arm/arch-ixp425/hardware.h # (new) -> 1.9 arch/arm/def-configs/iq80310 # (new) -> 1.1 include/asm-arm/arch-iop3xx/time.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/message.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/io.h # (new) -> 1.1 include/asm-arm/arch-adifcc/hardware.h # (new) -> 1.1 include/asm-arm/arch-ixp425/param.h # (new) -> 1.2 arch/arm/def-configs/adi_evb # (new) -> 1.5 drivers/mtd/maps/ixp2000.c # (new) -> 1.1 drivers/net/wireless/hostap_download.c # (new) -> 1.4 arch/arm/mach-iop3xx/aau.c # (new) -> 1.3 arch/arm/mach-adifcc/Makefile # (new) -> 1.1 drivers/mtd/maps/db1x00-flash.c # (new) -> 1.6 arch/arm/mach-ixp2000/ixp2000-pci.c # (new) -> 1.4 include/asm-arm/arch-ixp425/irqs.h # (new) -> 1.3 include/asm-arm/arch-adifcc/brh.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/pci_auto.h # (new) -> 1.4 arch/arm/mach-ixp425/arch.c # (new) -> 1.1 include/asm-arm/arch-adifcc/pci.h # (new) -> 1.1 drivers/mtd/maps/beech-mtd.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/iq80310.h # (new) -> 1.3 arch/arm/def-configs/ixdp425 # (new) -> 1.2 Documentation/arm/XScale/ADIFCC/BRH # (new) -> 1.1 include/asm-arm/arch-iop3xx/pmon.h # (new) -> 1.1 include/asm-arm/arch-ixp2000/pci-bridge.h # (new) -> 1.2 Documentation/arm/XScale/IXP2000/IXDP2400 # (new) -> 1.1 drivers/net/e1000/e1000_proc.c # (new) -> 1.1 drivers/mtd/chips/cfi_util.c # (new) -> 1.7 include/asm-arm/arch-ixp2000/irqs.h # (new) -> 1.3 drivers/i2c/i2c-adap-ixp425.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/irq.h # (new) -> 1.2 drivers/i2c/i2c-iop3xx.c # (new) -> 1.1 drivers/net/wireless/hostap_cs.c # (new) -> 1.11 arch/arm/boot/compressed/head-xscale.S # (new) -> 1.1 drivers/net/wireless/hostap_wlan.h # (new) -> 1.8 arch/arm/mach-ixp2000/Makefile # (new) -> 1.1 include/asm-arm/arch-iop3xx/pci_iop321.h # (new) -> 1.3 arch/arm/mach-iop3xx/iq80310-pci.c # (new) -> 1.1 Documentation/arm/XScale/cache-lock.txt # (new) -> 1.1 arch/arm/mach-ixp425/ixp425-irq.c # (new) -> 1.5 arch/arm/mach-adifcc/arch.c # (new) -> 1.1 arch/arm/mach-iop3xx/xs80200-irq.c # (new) -> 1.2 drivers/mtd/maps/adi_evb.c # (new) -> 1.1 drivers/net/wireless/hostap_pci.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/param.h # (new) -> 1.2 arch/arm/mach-ixp425/coyote-pci.c # (new) -> 1.2 arch/arm/mach-ixp2000/ixdp2800-leds.c # (new) -> 1.1 arch/arm/mach-ixp2000/pci.c # (new) -> 1.1 include/asm-arm/xscale-pmu.h # (new) -> 1.1 include/asm-arm/arch-ixp425/timex.h # (new) -> 1.2 arch/arm/def-configs/coyote # (new) -> 1.1 arch/arm/mach-ixp425/pci.c # (new) -> 1.4 arch/arm/mach-ixp425/mm.c # (new) -> 1.4 arch/arm/mach-ixp425/Makefile # (new) -> 1.1 drivers/net/wireless/hostap.c # (new) -> 1.3 arch/arm/def-configs/iq31244 # (new) -> 1.1 arch/arm/mach-iop3xx/iq80310-time.c # (new) -> 1.2 drivers/mtd/maps/ixp425.c # (new) -> 1.1 include/linux/workqueue.h # (new) -> 1.6 include/asm-arm/arch-ixp2000/ixdp2400.h # (new) -> 1.4 include/asm-arm/arch-ixp425/vmalloc.h # (new) -> 1.2 Documentation/arm/XScale/ADIFCC/80200EVB # (new) -> 1.1 include/asm-arm/arch-iop3xx/dma.h # (new) -> 1.6 arch/arm/def-configs/brh # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/dma.txt # (new) -> 1.3 drivers/i2c/i2c-adap-ixp2000.c # (new) -> 1.6 arch/arm/def-configs/ixm1200 # (new) -> 1.1 drivers/net/wireless/hostap_ap.c # (new) -> 1.2 include/asm-arm/arch-iop3xx/iop310-irqs.h # (new) -> 1.1 arch/arm/mach-iop3xx/iq31244-pci.c # (new) -> 1.2 arch/arm/mach-iop3xx/mm-321.c # (new) -> 1.2 arch/arm/mach-iop3xx/pci-auto.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/pci.h # (new) -> 1.1 include/asm-arm/arch-ixp425/system.h # (new) -> 1.1 drivers/mtd/maps/integrator-flash-v24.c # (new) -> 1.1 arch/arm/def-configs/prpmc1100 # (new) -> 1.1 arch/arm/kernel/xscale-pmu.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/iq80321.h # (new) -> 1.3 include/asm-arm/arch-ixp2000/uncompress.h # (new) -> 1.6 arch/arm/mach-ixp2000/ixdp2800-irq.c # (new) -> 1.4 arch/arm/mach-iop3xx/iop310-pci.c # (new) -> 1.2 arch/arm/mach-ixp425/pci-io.c # (new) -> 1.1 drivers/net/wireless/hostap_info.c # (new) -> 1.1 include/asm-arm/arch-ixp425/gpio.h # (new) -> 1.3 include/asm-arm/arch-iop3xx/timex.h # (new) -> 1.1 drivers/char/m41st85w.h # (new) -> 1.1 drivers/mtd/maps/arctic-mtd.c # (new) -> 1.1 include/asm-arm/arch-adifcc/irqs.h # (new) -> 1.5 arch/arm/mach-ixp2000/ixp2000-gpio.c # (new) -> 1.3 drivers/char/m41st85w.c # (new) -> 1.1 Documentation/arm/XScale/pmu.txt # (new) -> 1.2 Documentation/arm/XScale/IOP3XX/message.txt # (new) -> 1.1 include/asm-arm/arch-iop3xx/ide.h # (new) -> 1.1 drivers/mtd/maps/mpc1211.c # (new) -> 1.1 drivers/net/wireless/hostap.h # (new) -> 1.1 drivers/mtd/maps/sbc8240.c # (new) -> 1.1 include/asm-arm/arch-adifcc/pci-bridge.h # (new) -> 1.3 arch/arm/mach-iop3xx/iq80321-pci.c # (new) -> 1.1 include/asm-arm/arch-iop3xx/pci_iop310.h # (new) -> 1.1 Documentation/arm/kgdb # (new) -> 1.1 include/asm-arm/arch-adifcc/vmalloc.h # (new) -> 1.1 arch/arm/mach-adifcc/mm.c # (new) -> 1.1 include/asm-arm/xscale-lock.h # (new) -> 1.1 drivers/net/wireless/hostap_crypt.h # (new) -> 1.1 arch/arm/boot/endianswap.c # (new) -> 1.3 drivers/char/ixp2000.c # (new) -> 1.2 include/asm-arm/arch-iop3xx/iop310.h # (new) -> 1.1 arch/arm/mach-iop3xx/message.h # (new) -> 1.3 arch/arm/mach-ixp425/ixp425-time.c # (new) -> 1.1 drivers/mtd/maps/map_funcs.c # (new) -> 1.1 drivers/net/wireless/hostap_ap.h # (new) -> 1.5 include/asm-arm/arch-iop3xx/system.h # (new) -> 1.3 arch/arm/mach-ixp425/pcibuf.c # (new) -> 1.1 include/asm-arm/arch-ixp2000/pci_auto.h # (new) -> 1.1 include/asm-arm/arch-iop3xx/irqs.h # (new) -> 1.1 include/asm-arm/arch-adifcc/dma.h # (new) -> 1.1 include/asm-arm/arch-ixp425/ide.h # (new) -> 1.1 arch/arm/mach-ixp425/kgdb.c # (new) -> 1.3 arch/arm/mach-iop3xx/Makefile # (new) -> 1.4 arch/arm/mach-ixp425/ixp425-pci.c # (new) -> 1.1 include/asm-arm/arch-ixp425/pci.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/08/11 rmk@arm.linux.org.uk 1.11.1.10 # + Add 2.5 API for Acorn expansion cards Russell King # + Allow ioremap, read[bwl] and friends on Acorn platforms Russell King # + Convert Acorn ecard serial drivers to use new API Russell King # + Update drivers/serial with 2.5 fixes, etc Russell King # + Add ndelay() Russell King # + Fix udelay() for Bogomips overflow Russell King # + Remove "bogus breakpoint trap" message Russell King # + Fix args for RT signal handler Russell King # + Eliminate "reconnected" state in FAS216 driver Russell King # + Fix test_bit to return 0 or 1 Russell King # + Fix ELF fpregset_t for coredumps Russell King # + Backport the 2.5 data abort handling/hooking Russell King # + Backport 2.5 signed/unsigned fixes for proc-*.S Russell King # + Fix signal exit handling Russell King # + Fix "const" "__init" and "__initdata" in Acorn ether Russell King # drivers # + Fix ICSIDE DMA setup Russell King # + Fix __FUNCTION__ pasting in l3 driver Russell King # + Patch 1464/1 - NWFPE performance improvements [Part 1] Ralph Siemsen # + Patch 1465/1 - NWFPE performance improvements [Part 2] Ralph Siemsen # + Patch 1466/1 - NWFPE performance improvements [Part 3] Ralph Siemsen # + Patch 1467/1 - NWFPE performance improvements [Part 4] Ralph Siemsen # + Patch 1468/1 - NWFPE performance improvements [Part 5] Ralph Siemsen # + Patch 1469/1 - NWFPE performance improvements [Part 6] Ralph Siemsen # + Patch 1437/1 - A bug fix for acornfb.c 16bpp mode Richard Koch # + Patch 1451/1 - fix IRQ inheritance dependency cam mayor # + Patch 1453/1 - fix clps711x framebuffer "use SRAM?" range cam mayor # + Patch 1470/1 - Changes to uart00.c for epxa10db Dirk Behme # + Patch 1476/1 - bootpImage `bne taglist` results in run away George G. Davis # tagged list pointer # + Patch 1478/1 - zero wait states to GuideA07 NAND flash cam mayor # + Patch 1499/1 - correct LCD display inversion on Guide A07 cam mayor # + Patch 1452/1 - Add Framebuffer support for Guide A07 cam mayor # + Patch 1505/1 - Move pcipool.c to arch/arm/common SAN People # + Patch 1516/1 - Let the VIDC sound driver choose the closest Peter Teichmann # available samplerate. # + Patch 1524/1 - Fix multicast reception in cirrus.c CS8900 Andre McCurdy # ethernet driver # + Patch 1526/1 - init.S tag->hdr.size inconsistency Lutz J_nicke # + Patch 1534/1 - Add german umlauts to Acorn console font Peter Teichmann # V2.0 # + Patch 1541/1 - Atmel AT91RM9200 (Remove old files) SAN People # + Patch 1542/1 - Atmel AT91RM9200 (Base system) SAN People # + Patch 1543/1 - Atmel AT91RM9200 (Serial driver) SAN People # + Patch 1544/1 - Atmel AT91RM9200 (Ethernet driver) SAN People # + Patch 1521/1 - MX1: Framebuffer support Jon McClintock # + Patch 1523/1 - MX1: SyncFlash MTD driver Jon McClintock # + Patch 1522/1 - MX1: Touchscreen driver Jon McClintock # + Patch 1527/1 - Motorola MX1ADS serial debug macros George G. Davis # + Patch 1550/1 - Atmel AT91RM9200 (Watchdog driver) SAN People # + Patch 1535/1 - Add header file for Cirrus Logic ARM EP7312 Roland A.I. Rosier # + Patch 1551/1 - Atmel AT91RM9200 (RTC driver) SAN People # -------------------------------------------- # 03/09/04 dsaxena@xanadu.az.mvista.com 1.13.1.9 # Merge http://linux-arm.bkbits.net/linux-arm-2.4-georgn # into xanadu.az.mvista.com:/home/dsaxena/src/linux-arm-2.4-georgn # -------------------------------------------- # 03/09/04 dsaxena@xanadu.az.mvista.com 1.165 # Various IXP2000 changes # -------------------------------------------- # 03/09/05 dsaxena@xanadu.az.mvista.com 1.166 # Fixups from merging with 2.4.21-rmk1 # -------------------------------------------- # 03/09/09 djiang@retdev1.ch.intel.com 1.164.1.1 # IQ31244 updates # -------------------------------------------- # 03/09/09 dsaxena@xanadu.az.mvista.com 1.167 # Merge bk://arm24ds@source.mvista.com # into xanadu.az.mvista.com:/home/dsaxena/src/linux-arm-2.4-ds # -------------------------------------------- # 03/09/29 dsaxena@xanadu.az.mvista.com 1.168 # pci.ids: # Remove double 21154 entry # ixp2000.c: # Fix errata workaround # Many files: # Update to work with new abort model # arch.c: # Change maintainer of IQ31244 to nobody # brh-pci.c: # Fix to work with new abort model # ixdp2800, ixdp2400, iq80321, iq80310, brh: # Updated config # config.in: # Remove IXP12000 # head.S: # Cleanup # head-xscale.S: # Cleanup to use new redboot # Makefile: # Cleanup Xscale support # .del-vmalloc.h~58c91d001e7c679f: # Delete: include/asm-arm/arch-ixp1200/vmalloc.h # .del-uncompress.h~79b8320c7c6d17cb: # Delete: include/asm-arm/arch-ixp1200/uncompress.h # .del-timex.h~bc51501e2bd845b: # Delete: include/asm-arm/arch-ixp1200/timex.h # .del-time.h~e964d3f197ee9626: # Delete: include/asm-arm/arch-ixp1200/time.h # .del-system.h~239372d75b0bea75: # Delete: include/asm-arm/arch-ixp1200/system.h # .del-serial_reg.h~fa21c5c68bd05b7: # Delete: include/asm-arm/arch-ixp1200/serial_reg.h # .del-serial.h~8897ec3c234657b2: # Delete: include/asm-arm/arch-ixp1200/serial.h # .del-pci.h~dba74b9dd1943970: # Delete: include/asm-arm/arch-ixp1200/pci.h # .del-pci-bridge.h~4af0458b15c9a9c1: # Delete: include/asm-arm/arch-ixp1200/pci-bridge.h # .del-pci-auto.h~e16ed66aa0ff0405: # Delete: include/asm-arm/arch-ixp1200/pci-auto.h # .del-param.h~39f4010954f5ed70: # Delete: include/asm-arm/arch-ixp1200/param.h # .del-memory.h~6b12a02cb497f381: # Delete: include/asm-arm/arch-ixp1200/memory.h # .del-ixp1200.h~a27d293dcf46dedc: # Delete: include/asm-arm/arch-ixp1200/ixp1200.h # .del-irqs.h~f97367e0d048a97a: # Delete: include/asm-arm/arch-ixp1200/irqs.h # .del-irq.h~3547c24782d04d1a: # Delete: include/asm-arm/arch-ixp1200/irq.h # .del-io.h~6707d7a183c73f02: # Delete: include/asm-arm/arch-ixp1200/io.h # .del-ide.h~a47735508181b159: # Delete: include/asm-arm/arch-ixp1200/ide.h # .del-hardware.h~f28bb6855d2edade: # Delete: include/asm-arm/arch-ixp1200/hardware.h # .del-dma.h~a41f39b76733011a: # Delete: include/asm-arm/arch-ixp1200/dma.h # .del-pci.c~85779ebddbd38d6c: # Delete: arch/arm/mach-ixp1200/pci.c # .del-pci-auto.c~4cbaba0a6099582c: # Delete: arch/arm/mach-ixp1200/pci-auto.c # .del-mm.c~6f024496221c00d5: # Delete: arch/arm/mach-ixp1200/mm.c # .del-ixp-pci.c~47529fa8a7d8adb9: # Delete: arch/arm/mach-ixp1200/ixp-pci.c # .del-irq.c~2e80f4341d536e02: # Delete: arch/arm/mach-ixp1200/irq.c # .del-arch.c~bc4e687cd6519812: # Delete: arch/arm/mach-ixp1200/arch.c # .del-Makefile~998c3449ad4e5882: # Delete: arch/arm/mach-ixp1200/Makefile # -------------------------------------------- # 03/10/02 djiang@retdev1.ch.intel.com 1.169 # X-bit option # Turn frame pointers off # -------------------------------------------- # 03/10/06 djiang@retdev1.ch.intel.com 1.170 # Backported IOP321 I2C from 2.6 kernel # Added ST M41ST85W RTC driver support for IQ31244. Driver ripped from DS1307 code with mods to work with M41ST85W. # -------------------------------------------- # 03/10/06 root@retdev1.ch.intel.com 1.171 # Fixed clock stop running after halted. # -------------------------------------------- # 03/10/06 djiang@retdev1.ch.intel.com 1.172 # Added kernel time sync, lifted from RMK's acorn rtc driver # -------------------------------------------- # 03/10/16 dsaxena@xanadu.az.mvista.com 1.173 # Update brh defconfig # -------------------------------------------- # 03/10/16 dsaxena@xanadu.az.mvista.com 1.174 # i2c-adap-ixp425.c: # Fix IXP425 I2C driver to not leave line in high level # -------------------------------------------- # 03/10/17 dsaxena@xanadu.az.mvista.com 1.175 # Makefile: # patch-2.4.21-rmk1-ds1 # -------------------------------------------- # 03/10/20 djiang@ade-server2.ch.intel.com 1.172.1.1 # fix 5 source xor # -------------------------------------------- # 03/10/20 djiang@ade-server2.ch.intel.com 1.176 # Merge bk://arm24ds@source.mvista.com # into ade-server2.ch.intel.com:/opt/hardhat/devkit/lsp/ds_bktree/linux-arm-2.4-ds # -------------------------------------------- # 03/10/23 djiang@ade-server2.ch.intel.com 1.177 # timing skew on IOP321 fix # -------------------------------------------- # 03/11/06 dsaxena@xanadu.az.mvista.com 1.178 # i2c-iop3xx.c: # Fix issues with return codes # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.179 # # Add HOSTAP driver support # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.180 # # Add PCI IDE support for IXP425 # # ide.h: # new file # io.h, pci-io.c: # Cleanup PCI routines to work with IDE # # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.181 # # Updates from MTD CVS # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.182 # mm.c, config.in: # Cleanups # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.183 # ADI Coyote updates # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.184 # ksyms.c: # Export ilookup() # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.185 # pci.h: # Fix map_sg and unmap_sg to work with bounce-buffered systems # -------------------------------------------- # 03/11/26 dsaxena@xanadu.az.mvista.com 1.186 # ixp425-time.c: # Fix timer tick handling # -------------------------------------------- # 03/12/01 dsaxena@xanadu.az.mvista.com 1.187 # Deleted unused file # -------------------------------------------- # 03/12/01 dsaxena@xanadu.az.mvista.com 1.188 # Export do_leds() so that we can call it from timer code that is not in header files. # -------------------------------------------- # 03/12/01 dsaxena@xanadu.az.mvista.com 1.189 # Various IXP2000 updates # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.190 # rbtree-24.h: # new file # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.191 # workqueue.h: # new file # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.192 # cfi_util.c: # new file # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.193 # map_funcs.c: # new file # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.194 # Many files: # new file # -------------------------------------------- # 03/12/04 dsaxena@xanadu.az.mvista.com 1.195 # Makefile: # -ds3 # -------------------------------------------- # diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Thu Dec 4 16:24:25 2003 +++ b/CREDITS Thu Dec 4 16:24:25 2003 @@ -2695,6 +2695,14 @@ S: 03600 Karkkila S: Finland +N: Deepak Saxena +E: deepak@csociety.purdue.edu +D: I2O kernel layer (config, block, core, pci, net). I2O disk support for LILO +D: XScale(IOP310, IOP321, ADI chipsets) porting +D: IXP1200 porting +D: ARM KGDB +S: Tempe, Arizona + N: Eric Schenk E: Eric.Schenk@dna.lth.se D: Random kernel debugging. diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help Thu Dec 4 16:24:25 2003 +++ b/Documentation/Configure.help Thu Dec 4 16:24:25 2003 @@ -9447,6 +9447,53 @@ say M here and read . The module will be called orinoco_cs.o. +Host AP support for Prism2/2.5/3 IEEE 802.11b +CONFIG_HOSTAP + A driver for 802.11b wireless cards based on Intersil Prism2/2.5/3 + chipset. This driver supports so called Host AP mode that allows + the card to act as an IEEE 802.11 access point. + + See for more information about the + Host AP driver configuration and tools. + + This option includes the base Host AP driver code that is shared by + different hardware models. You will also need to enable support for + PLX/PCI/CS version of the driver to actually use the driver. + + The driver can be compiled as modules and they will be called + "hostap.o" and "hostap_crypt_wep.o". + +Host AP driver for Prism2/2.5/3 in PLX9052 based PCI adaptors +CONFIG_HOSTAP_PLX + Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based + PCI adaptors. + + "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this + driver and its help text includes more information about the Host AP + driver. + + The driver can be compiled as a module and will be named "hostap_plx.o". + +Host AP driver for Prism2.5 PCI adaptors +CONFIG_HOSTAP_PCI + Host AP driver's version for Prism2.5 PCI adaptors. + + "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this + driver and its help text includes more information about the Host AP + driver. + + The driver can be compiled as a module and will be named "hostap_pci.o". + +Host AP driver for Prism2/2.5/3 PC Cards +CONFIG_HOSTAP_CS + Host AP driver's version for Prism2/2.5/3 PC Cards. + + "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this + driver and its help text includes more information about the Host AP + driver. + + The driver can be compiled as a module and will be named "hostap_cs.o". + Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards CONFIG_AIRO This is the standard Linux driver to support Cisco/Aironet ISA and @@ -12527,6 +12574,30 @@ If you don't know what this all is, saying Y is a safe choice. +Workaround for buggy XScale cache +CONFIG_XSCALE_CACHE_ERRATA + There are couple errata that says that the cache may get confused + whether some cache lines are dirty or not, resulting in some memory + corruptions. The workaround (using the cache only in write through + mode) is performance impairing, and the bug _might_ just not be + that visible or critical to you depending on many esoteric + hardware factors. + + Not using the workaround makes Linux unreliable. If you're used + to some other OSes which requires to be rebooted once in a while + then this won't look so bad to you. On the other hand you may + stress test the system for hours without seeing any effect of this + bug. + + So this is configurable. Let's hope a future core revision will tell + this was just a bad dream. But in the mean time the risk and + trade-off is yours to decide. + + This should apply to all PXA250 up to rev B1 and possibly other + current XScale cores as well. + + If you don't know what to answer, say Y. + Support CD-ROM drives that are not SCSI or IDE/ATAPI CONFIG_CD_NO_IDESCSI If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y @@ -13287,6 +13358,13 @@ IQ80310 evaluation board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. +CFI Flash device mapped on the XScale IQ80321 board +CONFIG_MTD_IQ80321 + This enables access routines for the flash chips on the Intel XScale + IQ80321 evaluation board. If you have one of these boards and would + like to use the flash chips on it, say 'Y'. + + CFI Flash device mapped on AMD NetSc520 CONFIG_MTD_NETSC520 This enables access routines for the flash chips on the AMD NetSc520 @@ -24009,6 +24087,7 @@ Saying N will reduce the size of the Footbridge kernel. + EBSA285 (addin mode) CONFIG_ARCH_EBSA285_ADDIN Say Y here if you intend to run this kernel on the EBSA285 card @@ -24023,6 +24102,38 @@ Saying N will reduce the size of the Footbridge kernel. +IQ80310 +CONFIG_ARCH_IQ80310 + Say Y here if you want to run your kernel on the Intel IQ80310 + evaluation kit for the IOP310 chipset. + +IQ80321 +CONFIG_ARCH_IQ80321 + Say Y here if you want to run your kernel on the Intel IQ80321 + evaluation kit for the IOP321 chipset. + +IOP3XX RAID Acceleration +CONFIG_IOP3XX_AAU + Say Y here if you want to use the IOP3XX AAU to offload the RAID 5 XOR + computation for Linux soft RAID to hardware. You will see slower numbers + for the initialization checksum speed measuring. However, this is due to + the measuring function only uses 2 sources on very small quantities of + data that does not reflect the real world. The AAU setup overhead causes + the numbers to be low. However, in real world where RAID is done on 4 or + more disks it is very different. Also, more CPU cycles will be freed with + the XOR operation offloaded to hardware. Currently we only support up to + 5 sources for XOR operation. This is a Linux soft RAID limitation. The + AAU is capable of XOR up to 32 sources simultaneously. + +Run IQ80310 @ 733MHz +CONFIG_IQ80310_TURBO_CHARGE + Say Y here if you want to run your IQ80310 a 733MHz kernel. + Note that if you do so, you are doing at your own risk and + cannot hold anyone else liable for any hardware failures this + might cause. Having said that, this should not cause any + hardware failures as many people have been running their IQ80310 + boards at that speed for months. + LinkUp Systems L7200 SDB CONFIG_ARCH_L7200 Say Y here if you intend to run this kernel on a LinkUp Systems @@ -24378,6 +24489,25 @@ support booting in this mode. You almost surely want to say N here. + +Kernel Virtual Base Address +CONFIG_VM_SPLIT + + By default, Linux splits the 32-bit address space into 1G for + the kernel starting at 0xc0000000, and the lower 3G for user + space applications. This works fine on most system; however, + higher-end systems with lots of on board I/O devices that + need to be mapped in run out of VMALLOC space, so you need + to provide a larger area of the address space to the kernel. + If you choose 'yes' here, you will be able to choose the exact + VM split you want. The choices are: + + 3G User space/1G kernel (Default linux setup) + 2g User space/2G kernel + 1g User space/3G kernel + + If you don't think you need to change this or don't fully understand + what it means, it's best to leave this at 'no' Math emulation CONFIG_FPE_NWFPE diff -Nru a/Documentation/arm/IXP1200/README b/Documentation/arm/IXP1200/README --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/IXP1200/README Thu Dec 4 16:24:26 2003 @@ -0,0 +1,217 @@ + +Linux 2.4.x for IXP1200 Based Systems +-------------------------------------------------------------- + +This document describes building and using Linux on IXP1200 +based platforms. The IXP1200 is a Network Processor from Intel +based on an SA110 core with a set of six microgines around it. +For more information on the IXP1200, please see: + + http://developer.intel.com/design/network/products/npfamily/ixp1200.htm + +Supported Platforms +------------------- + +Linux has been tested on the Intel IXM1200 Network Processor Base +Board ("Spectacle Island) and the IXP12EB evaluation platform. Note +that on the IXP12EB, there are issues with the PCI bus and you will +get random bad packets on the network which will lead to things +like NFS timeouts and other nastyness. + +Linux will NOT run on silicon older then Rev C0 IXP1200. If you +have an IXP1240 or 1250 CPU, any Rev is OK as these are based +on newer cores. The IXP1200 B0 and A0 silicon do not have functional +byte lane swapping hardware and thus each driver needs to be modified +manually to work. + +Linux requires your board to be running Cygmon as the boot loader. +When you first get your board from Intel, it might be running the +VxWorks boot manager instead of the Cygmon boot manager. To change +this, you need to hit the space bar when the Boot Manager tells you +to do so and you will be given the Boot Manager prompt: + + [BootMgr]: + +At this point, type the letter 'c' and hit return. You should see +the following: + + [BootMgr]: c + BootMgr Version 2.0.83 + CPU Revision 6901C125 + OS list: + 0 Flash Utility + 1 Diagnostics + 2 VxWorks + 3 Cygmon + 4 Vmon + IO Type list: + 0 Serial + 1 HPC + Default OS: 2 + Countdown value: 5 + Disable initial display: 0 + Default IO type: 0 + SDRAM Window Size: 4K + SDRAM Window Offset: 06FFF000 + Upstream Window Size: 1M + Enter blank line to leave value unchanged + Default OS: + +Type in '3' and press return for the 'Default OS' option and leave +the other options blank. When you reboot your board, you should now +see a Cygmon prompt. If your board doesn't boot into cygmon, you +need to flash the cygmon image using the Intel provided futil.exe +program under Windows. If you're using the IXM1200 board, please +see your IXA SDK manual for information on how to do this. If +using the IXP12EB, you can download a flash image, the futil.exe +program, and directions on how to burn the flash @: + + ftp://ftp.netwinder.org/users/u/urnaik/public_html/ixp1200_howto.html + ftp://ftp.netwinder.org/users/u/urnaik/Futil.exe + ftp://ftp.netwinder.org/users/u/urnaik/flash.img + +Currently, the following devices on the boards are supported: + + - On board I82559/I82559ER ethernet + - On-chip serial port + + +The TODO list at the moment is: + + - Flash access (JFFS2) on IXM1200 + o The driver is in this patch for those feeling brave. Currently + you can eraseall /dev/mtd1 and them mount it at jffs2, but when + unmounting and remounting, all files with names > 3 bytes + dissapear due to some bizzare endian related bug. + + - Supporting all interrupt sources on IXP1200 + + - Getting rid of pci-auto library and using standard ARM PCI + + - Porting to 2.5.x tree + +Building the Kernel +------------------- + +To build the kernel, you need to make sure you have the latest +GCC and binutils with arm BE support. You can grab a set of older +binaries at: + + ftp://source.mvista.com/pub/ixp1200/ixa.arm-v4b-1.i386.rpm + +Note that these are somewhat old binaries from Intel and still have +a few big endian related issues that will show up if you use dynamic +loading of libraries. I'm working on building a newer toolchain +with more BE bug fixes and will have it on source.mvista.com ASAP. + +Once you have the toolchain installed, building a kernel is as easy as: + + make ixm1200_config + make oldconfig dep + make zImage + +If you want to build for the IXP12EB board instead, just replace +ixm1200_config with ixp12eb_config. + +The resulting kernel image will be in arch/arm/boot/zImage. + +Booting the Kernel +------------------ + +The default IXM1200 image is configure to boot from an NFS exported filesystem +on your host development machine and grab the IP address from DHCPD. You +can change this by editing the kernel command line option. The IXP12EB +default config is to boot from a ramdisk since there are PCI issues +which make NFS mostly unusable. + +You can grab a tarball of a big-endian busybox-based filesystem @: + + ftp://source.mvista.com/pub/ixp1200/root_fs.tar.gz + +A prebuilt ramdisk of the same fs is also available: + + ftp://source.mvista.com/pub/ixp1200/ramdisk_ixp.gz + +Also, cygmon only supports TFTP as a kernel download method, so you must +install and configure tftpd on your system if it is not already installed. + +If you are using a ramdisk instead of NFS as the root fs, you need +to tftp it to physical location 0xc1000000: + + cygmon> tftp /tftpboot/ramdisk_ixp.gz 0xc1000000 + +Note that you need to tftp the ramdisk image before you tftp the +kernel image. + +On the IXP12EB version of cygmon, the command is 'ftp', not tftp. + +Once everything is configured properly: + + cygmon> tftp /tftpboot/zImage 0xc0800000 + +Replace with your host's IP address and with the +IP address you've assigned to your development board. + + cygmon> go 0xc0800000 + + +Note that if your ramdisk image or kernel image length is a multiple of +512 bytes, cygmon will lock up after it receives the last packet as it +can't deal with such files. You need to add an extra byte of data at +the end of the files if this is the case: + + echo ' ' >> zImage + + +Migrating from Intel 2.3.99 Linux +--------------------------------- + +- Unlike the Intel Linux, this kernel does not reserve the lower 8MB + of SDRAM for use by the microengines. The ammount of RAM to be used by the + microengines is an application specific issue and thus the generic + port does not attempt to make a decision on how much to map in and + where in memory to map it in. + + Instead of pre-reserving memory by moving the kernel around, the 2.4 + kernel provides some capabilities that make this uneccessary. If you + need xMB of memory, you can hook into the kernel initilazition code + and call alloc_bootmem() to reserve a contigous physical region of + SDRAM. alloc_bootmem() returns a virtual address, but you can simply + do a virt_to_phys() to return a physical address for use by the uengines + and a virt_to_bus() to return a PCI accessible address. You should put + your call to alloc_bootmem() in arch/arm/mach-ixp1200/mm.c:ixp1200_map_io() + and have it initialize a global variable with the address of the region. + + If you still want to limit the RAM that Linux uses, just add a mem=xxxM + option to the command line and then __ioremap() the upper portion of + SDRAM into the kernel space. bootmem_alloc() is much preffered though. + +- The remainder of the devices on the IXP1200 are mapped into the kernel's + virtual address space in the same locations as they were in the Intel + 2.3.99-pre3 port. This is to allow easy migration of existing applications + from the Intel Linux to the community tree. Note that these mapping may + change in the future, so you should only use the pre-defined constants to + access the on-chip devices and not use the vaddr's directly. + +- The IRQ numbering scheme remains the same between the Intel 2.3.99-pre3 + and the new kernel at the moment. Again, please only use the #defined + constants instead of the IRQ number themselves as the IRQ code is going + to be drastically rewritten to support all IRQs on the CPU. + +- Note that there is no uEngine driver at the moment for the 2.4.x kernel + as the original Intel drivers are not under an open source license and + can't just be forward ported and released. If and when time permits, + I would love to write a separate open source driver, but I also don't + want to see two separate drivers floating around and have people trying + to use the Intel Developer's Workbench with the open source drivers and not + having them work, thus leading to headaches for end users, Intel, and + myself as we try to sort things out. Basically, until Intel releases a 2.4.x + based SDK or until I or someone else in the community has the time + to do our own open source drivers, you'll have to forward port the 2.4.x + drivers on your own time. Same goes for drivers for the devices on the + IX bus. + +------------------------------------------------------------------------------ +Please send all comments, corrections, suggestions, flames, etc to: +Deepak Saxena + diff -Nru a/Documentation/arm/XScale/ADIFCC/80200EVB b/Documentation/arm/XScale/ADIFCC/80200EVB --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/ADIFCC/80200EVB Thu Dec 4 16:24:26 2003 @@ -0,0 +1,101 @@ + +Board Overview +----------------------------- + +The 80200EVB is an evaluation platform for ADI Engineering's high-performance +80200FCC chipset for the Intel 80200 XScale CPU. The 80200FCC is an open +source FPGA based system that contains a PCI unit and a high performance +memory controller. + +In addition to the 80200FCC, the board also contains a 16C550 UART, and 4MB +of flash. + +For more information on the board, see http://www.adiengineering.com + +Port Status +----------------------------- + +Supported: + +- Onboard UART (Polled operation only) +- Cache/TLB locking on 80200 CPU + +Building the Kernel +----------------------------- +change Linux makefile +make adi_evb_config +make oldconfig +make dep +make zImage + +Loading Linux +----------------------------- + +Before you can use Linux on the ADI board, you need to grab the following: + +ADI 80200EVB Monitor: + ftp://source.mvista.com/pub/xscale/ADI_EVB/monitor.srec + +ADI JFFS2 Image: + ftp://source.mvista.com/pub/xscale/ADI_EVB/adi.jffs2 + +Once you've got the Cygnus prompt, type in the following command: + + load + +On another terminal window: + + cat monitor.srec > /dev/ttyS0 + +(replace ttyS0 with the serial port you are using) + +Once completed, just type 'go' at the cygmon prompt and you should see: + + MontaVista IQ80310 Monitor Version 0.1 + monitor> + +Type 'b 115200' at the prompt and change your terminal speed to 115200 + +The first thing to do is to upload and burn the jffs2 filesystem image +onto the boards 4MB of flash: + + monitor> u c1000000 + Uploading file at 0xc1000000 + Now send file with ymodem + +Do as the monitor says and transfer the file adi.jffs2. Once complete, +the following will copy the jffs2 image to location 0x80000 in the flash. + + monitor> f 8000 c1000000 200000 + Erasing sector 0x00080000 + Writing sector 0x00080000 with data at 0xC1000000 + Erasing sector 0x000A0000 + Writing sector 0x000A0000 with data at 0xC1020000 + Erasing sector 0x000C0000 + ... + +Now use the same command as above to upload your zImage to location c1000000. +When you've done that, type 'j c1000000' to run Linux. Login as +root and you're all set to go. + +Misc Notes +----------------------------- + +The current version of the HW does not have an onboard timer, so the 80200 +PMU is not available for general use as it is being used for a timer source. + +By default, the MTD driver reserves the first 512K for bootloaders and +the remaining 3.5MB for the filesystem. You can edit drivers/mtd/map/adi_evb.c +to change this as needed for your application. + +Contributors +----------------------------- + +Thanks to ADI Engineering for providing the hardware for development + +Deepak Saxena - Initial port + +----------------------------- +Enjoy. If you have any problem please contact Deepak Saxena +dsaxena@mvista.com + diff -Nru a/Documentation/arm/XScale/ADIFCC/BRH b/Documentation/arm/XScale/ADIFCC/BRH --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/ADIFCC/BRH Thu Dec 4 16:24:26 2003 @@ -0,0 +1,105 @@ + + +Board Overview +--------------------------------------------------------------------- + +This is an early release of the Linux port to the ADI BRH platform + +The BRH is an evaluation platform for ADI Engineering's 80200BECC +(Big-Endian Companion Chip) chipset for the Intel 80200 XScale CPU. +The 80200BECC is a follow on product to the 80200FCC and provides a +functioning PCI unit, high performance memory controller, DMA units, +and two timers. + +Port Status +--------------------------------------------------------------------- + +Supported: + + - Little and Big Endian operation + - Dual Ethernets + - Both serial ports + - Flash access to MTD + - On board PCI slot + - XScale PMU + - XScale cache locking + +Unsupported: + + - On Board DMA + +Building the Kernel +--------------------------------------------------------------------- + + make distclean + make brh_config oldconfig dep + make zImage + +When done, the new zImage will be in arch/arm/boot/zImage + +Loading Linux +--------------------------------------------------------------------- + +Configure your com program to 57600, N81 + +I'm assuming that you are using RedBoot as your bootloader, and not +anything else. Once redboot is started: + + RedBoot> load -r -b 0xc1008000 -m y + +Now start a y-modem transfer of the zImage file in your com program. + +Once completed: + + RedBoot> go 0xc1008000 + Uncompressing Linux.......booting kernel + Linux version 2.4.18-rmk6 (dsaxena@xanadu.az.mvista.com) (gcc version 2. 95.3 20010315 (release/MontaVista)) #8 Thu May 23 10:24:49 MST 2002 + CPU: Intel XScale-80200 revision 1 + Machine: ADI BRH + On node 0 totalpages: 8192 + zone(0): 8192 pages. + zone(1): 0 pages. + zone(2): 0 pages. + ... + +Notes/Issues +--------------------------------------------------------------------- + +PCI Windows and available RAM + + The current port only allows linux to use 32 out of the 128MB + available on the board. The reason for this is that the inbound + PCI windows on the BECC only allow for 2 separate 32MB windows, + not a single 128MB window. This put several limitations on + the way drivers can allocate buffers for use by PCI, so it is + much easier to limit linux than to hack all the drivers. It may + be possible to use the higmem stuff to use the upper 96MB of memory + only for user and vmalloc space, but I haven't had a chance to look + at that yet. + + Update: + + There is a new revision of the BRH EEPROM which adds a single 128MB + translation window. If you get this updated version from them + (v8), it will allow you to use all of RAM. + +MTD on the BRH board + + There are several different ways to use MTD on the BRH board. + If you turn on CONFIG_MTD_CONCAT (off in the default config), + the driver will concatanate all available flash banks into a + single contigous regions and create two partitions (firmware, + and user access). You can change the partioning scheme if you + wish by editing the file drivers/mtd/maps/brh.c. + + If you do not turn on MTD concatanation support, the driver will + split the boot flash device into two regions (firmware & user) + and then create a single partition on each user flash device. + +Network Timeouts + + If using an EEPROM < v8, you will see network timeouts during + high traffice due to an issue with the PCI unit on the BECC + not releasing the bus. + + diff -Nru a/Documentation/arm/XScale/IOP3XX/IQ80310 b/Documentation/arm/XScale/IOP3XX/IQ80310 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/IQ80310 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,216 @@ + +Board Overview +----------------------------- + +The Cyclone IQ80310 board is an evaluation platform for Intel's 80200 Xscale +CPU and 80312 Intelligent I/O chipset (collectively called IOP310 chipset). + +The 80312 contains dual PCI hoses (called the ATUs), a PCI-to-PCI bridge, +three DMA channels (1 on secondary PCI, one on primary PCI ), I2C, I2O +messaging unit, XOR unit for RAID operations, a bus performance monitoring +unit, and a memory controller with ECC features. + +For more information on the board, see http://developer.intel.com/iio + +Port Status +----------------------------- + +Supported: + +- MTD/JFFS/JFFS2 +- NFS root +- RAMDISK root +- 2ndary PCI slots +- Onboard ethernet +- Serial ports (ttyS0/S1) +- Cache/TLB locking on 80200 CPU +- Performance monitoring unit on 80200 CPU +- 80200 Performance Monitoring Unit +- Acting as a system controller on Cyclone 80303BP PCI backplane +- DMA engines (EXPERIMENTAL) +- 80312 Bus Performance Monitor (EXPERIMENTAL) +- Application Accelerator Unit (XOR engine for RAID) (EXPERIMENTAL) +- Messaging Unit (EXPERIMENTAL) + +TODO: +- I2C + +Building the Kernel +----------------------------- +make iq80310_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just run make menuconfig and disable nfs root or add a "root=" option. + +Preparing the Hardware +----------------------------- + +This document assumes you're using a Rev D or newer board running +Redboot as the bootloader. Note that the version of RedBoot provided +with the boards has a major issue and you need to replace it with the +latest RedBoot. You can grab the source from the ECOS CVS or you can +get a prebuilt image and burn it in using FRU at: + + ftp://source.mvista.com/pub/xscale/iq80310/redboot.bin + +Make sure you do an 'fis init' command once you boot with the new +RedBoot image. + + +Downloading Linux +----------------------------- + +Assuming you have your development system setup to act as a bootp/dhcp +server and running tftp: + + RedBoot> load -r -b 0xa1008000 /tftpboot/zImage.xs + Raw file loaded 0xa1008000-0xa1094bd8 + +If you're not using dhcp/tftp, you can use y-modem instead: + + RedBoot> load -r -b 0xa1008000 -m y + +Note that on Rev D. of the board, tftp does not work due to intermittent +interrupt issues, so you need to download using ymodem. + +Once the download is completed: + + RedBoot> go 0xa1008000 + +Root Devices +----------------------------- + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + +MTD on the IQ80310 +----------------------------- + +Linux on the IQ80310 supports RedBoot FIS paritioning if it is enabled. +Out of the box, once you've done 'fis init' on RedBoot, you will get +the following partitioning scheme: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 0075f000 00020000 "unallocated space" + mtd3: 00001000 00020000 "RedBoot config" + mtd4: 00020000 00020000 "FIS directory" + +To create an FIS directory, you need to use the fis command in RedBoot. +As an example, you can burn the kernel into the flash once it's downloaded: + + RedBoot> fis create -b 0xa1008000 -l 0x8CBAC -r 0xa1008000 -f 0x80000 kernel + ... Erase from 0x00080000-0x00120000: ..... + ... Program from 0xa1008000-0xa1094bac at 0x00080000: ..... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0x00000000 + +This leads to the following Linux MTD setup: + + mtroot@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 006bf000 00020000 "unallocated space" + mtd4: 00001000 00020000 "RedBoot config" + mtd5: 00020000 00020000 "FIS directory" + +Note that there is not a 1:1 mapping to the number of RedBoot paritions to +MTD partitions as unused space also gets allocated into MTD partitions. + +As an aside, the -r option when creating the Kernel entry allows you to +simply do an 'fis load kernel' to copy the image from flash into memory. +You can then do an 'fis go 0xa1008000' to start Linux. + +If you choose to use static partitioning instead of the RedBoot partioning: + + /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) + /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) + /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) + /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) + +To use a JFFS1/2 root FS, you need to donwload the JFFS image using either +tftp or ymodem, and then copy it to flash: + + RedBoot> load -r -b 0xa1000000 /tftpboot/jffs.img + Raw file loaded 0xa1000000-0xa1600000 + RedBoot> fis create -b 0xa1000000 -l 0x600000 -f 0x120000 jffs + ... Erase from 0x00120000-0x00720000: .................................. + ... Program from 0xa1000000-0xa1600000 at 0x00120000: .................. + ...................... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0xA1008000 + jffs 0x00120000 0x00120000 0x00600000 0x00000000 + +This looks like this in Linux: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 00600000 00020000 "jffs" + mtd4: 000bf000 00020000 "unallocated space" + mtd5: 00001000 00020000 "RedBoot config" + mtd6: 00020000 00020000 "FIS directory" + +You need to boot the kernel once and watch the boot messages to see how the +JFFS RedBoot partition mapped into the MTD partition scheme. + +You can grab a pre-built JFFS image to use as a root file system at: + + ftp://source.mvista.com/pub/xscale/iq80310/jffs.img + +For detailed info on using MTD and creating a JFFS image go to: + + http://www.linux-mtd.infradead.org. + +For details on using RedBoot's FIS commands, type 'fis help' or consult +your RedBoot manual. + +Contributors +----------------------------- + +Thanks to Intel Corporation for providing the hardware. + +John Clark - Initial discovery of RedBoot issues +Dave Jiang - IRQ demux fixes, AAU, DMA, MU +Nicolas Pitre - Initial port, cleanup, debugging +Matt Porter - PCI subsystem development, debugging +Tim Sanders - Initial PCI code +Mark Salter - RedBoot fixes +Deepak Saxena - Cleanup, debug, cache lock, PMU + +----------------------------- +Enjoy. + +If you have any problems please contact Deepak Saxena + diff -Nru a/Documentation/arm/XScale/IOP3XX/IQ80321 b/Documentation/arm/XScale/IOP3XX/IQ80321 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/IQ80321 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,224 @@ + +Board Overview +----------------------------- + +The Worcester IQ80321 board is an evaluation platform for Intel's 80321 Xscale +CPU (sometimes called IOP321 chipset). + +The 80321 contains a single PCI hose (called the ATUs), a PCI-to-PCI bridge, +two DMA channels, I2C, I2O messaging unit, XOR unit for RAID operations, +a bus performance monitoring unit, and a memory controller with ECC features. + +For more information on the board, see http://developer.intel.com/iio + +Port Status +----------------------------- + +Supported: + +- MTD/JFFS/JFFS2 root +- NFS root +- RAMDISK root +- Serial port (ttyS0) +- Cache/TLB locking on 80321 CPU +- Performance monitoring unit on 80321 CPU +- Application Accelerator Unit (XOR engine for RAID) + +TODO: + +- DMA engines +- I2C +- 80321 Bus Performance Monitor +- I2O Messaging Unit +- I2C unit +- SSP + +Building the Kernel +----------------------------- +make iq80321_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just run make menuconfig and disable nfs root or add a "root=" option. + +Preparing the Hardware +----------------------------- + +Make sure you do an 'fis init' command once you boot with the new +RedBoot image. + +Downloading Linux +----------------------------- + +Assuming you have your development system setup to act as a bootp/dhcp +server and running tftp: + +NOTE: The 80321 board uses a different default memory map than the 80310. + + RedBoot> load -r -b 0x01008000 -m y + +Once the download is completed: + + RedBoot> go 0x01008000 + +There is a version of RedBoot floating around that has DHCP support, but +I've never been able to cleanly transfer a kernel image and have it run. + +*Note: Instead of compiling a zImage, compile a zsrec. Unless you are one +of the few lucky ones that the board allows zImage to run without crashing, +this is a better alternative to using the serial cable for download. + + RedBoot> l -b 0x01008000 zsrec + + RedBoot> g + +Root Devices +----------------------------- + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + +MTD on the IQ80321 +----------------------------- + +Linux on the IQ80321 supports RedBoot FIS paritioning if it is enabled. +Out of the box, once you've done 'fis init' on RedBoot, you will get +the following partitioning scheme: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 0075f000 00020000 "unallocated space" + mtd3: 00001000 00020000 "RedBoot config" + mtd4: 00020000 00020000 "FIS directory" + +To create an FIS directory, you need to use the fis command in RedBoot. +As an example, you can burn the kernel into the flash once it's downloaded: + + RedBoot> fis create -b 0x01008000 -l 0x8CBAC -r 0x01008000 -f 0xF0080000 kernel + ... Erase from 0xF0080000-0xF0120000: ..... + ... Program from 0xF1008000-0xF1094bac at 0xF0080000: ..... + ... Unlock from 0xF07e0000-0xF0800000: . + ... Erase from 0xF07e0000-0xF0800000: . + ... Program from 0x01fdf000-0x01fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0xF0000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0xF0040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0xF07DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0xF07E0000 0x007E0000 0x00020000 0x00000000 + kernel 0xF0080000 0x01008000 0x000A0000 0x01008000 + +This leads to the following Linux MTD setup: + + mtroot@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 006bf000 00020000 "unallocated space" + mtd4: 00001000 00020000 "RedBoot config" + mtd5: 00020000 00020000 "FIS directory" + +Note that there is not a 1:1 mapping to the number of RedBoot paritions to +MTD partitions as unused space also gets allocated into MTD partitions. + +As an aside, the -r option when creating the Kernel entry allows you to +simply do an 'fis load kernel' to copy the image from flash into memory. +You can then do an 'fis go 0x01008000' to start Linux. + +If you choose to use static partitioning instead of the RedBoot partioning: + + /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) + /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) + /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) + /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) + +To use a JFFS1/2 root FS, you need to donwload the JFFS image using either +tftp or ymodem, and then copy it to flash: + + RedBoot> load -r -b 0x01000000 /tftpboot/jffs.img + Raw file loaded 0x01000000-0x01600000 + RedBoot> fis create -b 0x01000000 -l 0x600000 -f 0xF0120000 jffs + ... Erase from 0x00120000-0x00720000: .................................. + ... Program from 0x01000000-0x01600000 at 0x00120000: .................. + ...................... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0x01fdf000-0x01fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0xF0000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0xF0040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0xF07DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0xF07E0000 0x007E0000 0x00020000 0x00000000 + kernel 0xF0080000 0x01008000 0x000A0000 0x01008000 + jffs 0xF0120000 0x00120000 0x00600000 0x00000000 + +This looks like this in Linux: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 00600000 00020000 "jffs" + mtd4: 000bf000 00020000 "unallocated space" + mtd5: 00001000 00020000 "RedBoot config" + mtd6: 00020000 00020000 "FIS directory" + +You need to boot the kernel once and watch the boot messages to see how the +JFFS RedBoot partition mapped into the MTD partition scheme. + +You can grab a pre-built JFFS image to use as a root file system at: + + ftp://source.mvista.com/pub/xscale/iq80310/jffs.img + +For detailed info on using MTD and creating a JFFS image go to: + + http://www.linux-mtd.infradead.org. + +For details on using RedBoot's FIS commands, type 'fis help' or consult +your RedBoot manual. + +BUGS and ISSUES +----------------------------- + +* As shipped from Intel, pre-production boards have two issues: + +- The on board ethernet is disabled S8E1-2 is off. You will need to turn it on. + +- The PCIXCAPs are configured for a 100Mhz clock, but the clock selected is + actually only 66Mhz. This causes the wrong PPL multiplier to be used and the + board only runs at 400Mhz instead of 600Mhz. The way to observe this is to + use a independent clock to time a "sleep 10" command from the prompt. If it + takes 15 seconds instead of 10, you are running at 400Mhz. + +- The experimental IOP310 drivers for the AAU, DMA, etc. are not supported yet. + +Contributors +----------------------------- +The port to the IQ80321 was performed by: + +Rory Bolt - Initial port, debugging. + +This port was based on the IQ80310 port with the following contributors: + +Nicolas Pitre - Initial port, cleanup, debugging +Matt Porter - PCI subsystem development, debugging +Tim Sanders - Initial PCI code +Deepak Saxena - Cleanup, debug, cache lock, PMU + +The port is currently maintained by Deepak Saxena + +----------------------------- +Enjoy. diff -Nru a/Documentation/arm/XScale/IOP3XX/aau.txt b/Documentation/arm/XScale/IOP3XX/aau.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/aau.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,178 @@ +Support functions for the Intel 80310 AAU +=========================================== + +Dave Jiang +Last updated: 09/18/2001 + +The Intel 80312 companion chip in the 80310 chipset contains an AAU. The +AAU is capable of processing up to 8 data block sources and perform XOR +operations on them. This unit is typically used to accelerated XOR +operations utilized by RAID storage device drivers such as RAID 5. This +API is designed to provide a set of functions to take adventage of the +AAU. The AAU can also be used to transfer data blocks and used as a memory +copier. The AAU transfer the memory faster than the operation performed by +using CPU copy therefore it is recommended to use the AAU for memory copy. + +------------------ +int aau_request(u32 *aau_context, const char *device_id); +This function allows the user the acquire the control of the the AAU. The +function will return a context of AAU to the user and allocate +an interrupt for the AAU. The user must pass the context as a parameter to +various AAU API calls. + +int aau_queue_buffer(u32 aau_context, aau_head_t *listhead); +This function starts the AAU operation. The user must create a SGL +header with a SGL attached. The format is presented below. The SGL is +built from kernel memory. + +/* hardware descriptor */ +typedef struct _aau_desc +{ + u32 NDA; /* next descriptor address [READONLY] */ + u32 SAR[AAU_SAR_GROUP]; /* src addrs */ + u32 DAR; /* destination addr */ + u32 BC; /* byte count */ + u32 DC; /* descriptor control */ + u32 SARE[AAU_SAR_GROUP]; /* extended src addrs */ +} aau_desc_t; + +/* user SGL format */ +typedef struct _aau_sgl +{ + aau_desc_t aau_desc; /* AAU HW Desc */ + u32 status; /* status of SGL [READONLY] */ + struct _aau_sgl *next; /* pointer to next SG [READONLY] */ + void *dest; /* destination addr */ + void *src[AAU_SAR_GROUP]; /* source addr[4] */ + void *ext_src[AAU_SAR_GROUP]; /* ext src addr[4] */ + u32 total_src; /* total number of source */ +} aau_sgl_t; + +/* header for user SGL */ +typedef struct _aau_head +{ + u32 total; /* total descriptors allocated */ + u32 status; /* SGL status */ + aau_sgl_t *list; /* ptr to head of list */ + aau_callback_t callback; /* callback func ptr */ +} aau_head_t; + + +The function will call aau_start() and start the AAU after it queues +the SGL to the processing queue. When the function will either +a. Sleep on the wait queue aau->wait_q if no callback has been provided, or +b. Continue and then call the provided callback function when DMA interrupt + has been triggered. + +int aau_suspend(u32 aau_context); +Stops/Suspends the AAU operation + +int aau_free(u32 aau_context); +Frees the ownership of AAU. Called when no longer need AAU service. + +aau_sgl_t * aau_get_buffer(u32 aau_context, int num_buf); +This function obtains an AAU SGL for the user. User must specify the number +of descriptors to be allocated in the chain that is returned. + +void aau_return_buffer(u32 aau_context, aau_sgl_t *list); +This function returns all SGL back to the API after user is done. + +int aau_memcpy(void *dest, void *src, u32 size); +This function is a short cut for user to do memory copy utilizing the AAU for +better large block memory copy vs using the CPU. This is similar to using +typical memcpy() call. + +* User is responsible for the source address(es) and the destination address. + The source and destination should all be cached memory. + + + +void aau_test() +{ + u32 aau; + char dev_id[] = "AAU"; + int size = 2; + int err = 0; + aau_head_t *head; + aau_sgl_t *list; + u32 i; + u32 result = 0; + void *src, *dest; + + printk("Starting AAU test\n"); + if((err = aau_request(&aau, dev_id))<0) + { + printk("test - AAU request failed: %d\n", err); + return; + } + else + { + printk("test - AAU request successful\n"); + } + + head = kmalloc(sizeof(aau_head_t), GFP_KERNEL); + head->total = size; + head->status = 0; + head->callback = NULL; + + list = aau_get_buffer(aau, size); + if(!list) + { + printk("Can't get buffers\n"); + return; + } + head->list = list; + + src = kmalloc(1024, GFP_KERNEL); + dest = kmalloc(1024, GFP_KERNEL); + + while(list) + { + list->status = 0; + list->aau_desc->SAR[0] = (u32)src; + list->aau_desc->DAR = (u32)dest; + list->aau_desc->BC = 1024; + + /* see iop310-aau.h for more DCR commands */ + list->aau_desc->DC = AAU_DCR_WRITE | AAU_DCR_BLKCTRL_1_DF; + if(!list->next) + { + list->aau_desc->DC = AAU_DCR_IE; + break; + } + list = list->next; + } + + printk("test- Queueing buffer for AAU operation\n"); + err = aau_queue_buffer(aau, head); + if(err >= 0) + { + printk("AAU Queue Buffer is done...\n"); + } + else + { + printk("AAU Queue Buffer failed...: %d\n", err); + } + + + +#if 1 + printk("freeing the AAU\n"); + aau_return_buffer(aau, head->list); + aau_free(aau); + kfree(src); + kfree(dest); + kfree((void *)head); +#endif +} + +All Disclaimers apply. Use this at your own discretion. Neither Intel nor I +will be responsible if anything goes wrong. =) + + +TODO +____ +* Testing +* Do zero-size AAU transfer/channel at init + so all we have to do is chainining + diff -Nru a/Documentation/arm/XScale/IOP3XX/dma.txt b/Documentation/arm/XScale/IOP3XX/dma.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/dma.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,214 @@ +Support functions forthe Intel 80310 DMA channels +================================================== + +Dave Jiang +Last updated: 09/18/2001 + +The Intel 80310 XScale chipset provides 3 DMA channels via the 80312 I/O +companion chip. Two of them resides on the primary PCI bus and one on the +secondary PCI bus. + +The DMA API provided is not compatible with the generic interface in the +ARM tree unfortunately due to how the 80312 DMACs work. Hopefully some time +in the near future a software interface can be done to bridge the differences. +The DMA API has been modeled after Nicholas Pitre's SA11x0 DMA API therefore +they will look somewhat similar. + + +80310 DMA API +------------- + +int dma_request(dmach_t channel, const char *device_id); + +This function will attempt to allocate the channel depending on what the +user requests: + +IOP310_DMA_P0: PCI Primary 1 +IOP310_DMA_P1: PCI Primary 2 +IOP310_DMA_S0: PCI Secondary 1 +/*EOF*/ + +Once the user allocates the DMA channel it is owned until released. Although +other users can also use the same DMA channel, but no new resources will be +allocated. The function will return the allocated channel number if successful. + +int dma_queue_buffer(dmach_t channel, dma_sghead_t *listhead); + +The user will construct a SGL in the form of below: +/* + * Scattered Gather DMA List for user + */ +typedef struct _dma_desc +{ + u32 NDAR; /* next descriptor adress [READONLY] */ + u32 PDAR; /* PCI address */ + u32 PUADR; /* upper PCI address */ + u32 LADR; /* local address */ + u32 BC; /* byte count */ + u32 DC; /* descriptor control */ +} dma_desc_t; + +typedef struct _dma_sgl +{ + dma_desc_t dma_desc; /* DMA descriptor */ + u32 status; /* descriptor status [READONLY] */ + u32 data; /* user defined data */ + struct _dma_sgl *next; /* next descriptor [READONLY] */ +} dma_sgl_t; + +/* dma sgl head */ +typedef struct _dma_head +{ + u32 total; /* total elements in SGL */ + u32 status; /* status of sgl */ + u32 mode; /* read or write mode */ + dma_sgl_t *list; /* pointer to list */ + dma_callback_t callback; /* callback function */ +} dma_head_t; + + +The user shall allocate user SGL elements by calling the function: +dma_get_buffer(). This function will give the user an SGL element. The user +is responsible for creating the SGL head however. The user is also +responsible for allocating the memory for DMA data. The following code segment +shows how a DMA operation can be performed: + +#include + +void dma_test(void) +{ + char dev_id[] = "Primary 0"; + dma_head_t *sgl_head = NULL; + dma_sgl_t *sgl = NULL; + int err = 0; + int channel = -1; + u32 *test_ptr = 0; + DECLARE_WAIT_QUEUE_HEAD(wait_q); + + + *(IOP310_ATUCR) = (IOP310_ATUCR_PRIM_OUT_ENAB | + IOP310_ATUCR_DIR_ADDR_ENAB); + + channel = dma_request(IOP310_DMA_P0, dev_id); + + sgl_head = (dma_head_t *)kmalloc(sizeof(dma_head_t), GFP_KERNEL); + sgl_head->callback = NULL; /* no callback created */ + sgl_head->total = 2; /* allocating 2 DMA descriptors */ + sgl_head->mode = (DMA_MOD_WRITE); + sgl_head->status = 0; + + /* now we get the two descriptors */ + sgl = dma_get_buffer(channel, 2); + + /* we set the header to point to the list we allocated */ + sgl_head->list = sgl; + + /* allocate 1k of DMA data */ + sgl->data = (u32)kmalloc(1024, GFP_KERNEL); + + /* Local address is physical */ + sgl->dma_desc.LADR = (u32)virt_to_phys(sgl->data); + + /* write to arbitrary location over the PCI bus */ + sgl->dma_desc.PDAR = 0x00600000; + sgl->dma_desc.PUADR = 0; + sgl->dma_desc.BC = 1024; + + /* set write & invalidate PCI command */ + sgl->dma_desc.DC = DMA_DCR_PCI_MWI; + sgl->status = 0; + + /* set a pattern */ + memset(sgl->data, 0xFF, 1024); + + /* User's responsibility to keep buffers cached coherent */ + cpu_dcache_clean(sgl->data, sgl->data + 1024); + + sgl = sgl->next; + + sgl->data = (u32)kmalloc(1024, GFP_KERNEL); + sgl->dma_desc.LADR = (u32)virt_to_phys(sgl->data); + sgl->dma_desc.PDAR = 0x00610000; + sgl->dma_desc.PUADR = 0; + sgl->dma_desc.BC = 1024; + + /* second descriptor has interrupt flag enabled */ + sgl->dma_desc.DC = (DMA_DCR_PCI_MWI | DMA_DCR_IE); + + /* must set end of chain flag */ + sgl->status = DMA_END_CHAIN; /* DO NOT FORGET THIS!!!! */ + + memset(sgl->data, 0x0f, 1024); + /* User's responsibility to keep buffers cached coherent */ + cpu_dcache_clean(sgl->data, sgl->data + 1024); + + /* queing the buffer, this function will sleep since no callback */ + err = dma_queue_buffer(channel, sgl_head); + + /* now we are woken from DMA complete */ + + /* do data operations here */ + + /* free DMA data if necessary */ + + /* return the descriptors */ + dma_return_buffer(channel, sgl_head->list); + + /* free the DMA */ + dma_free(channel); + + kfree((void *)sgl_head); +} + + +dma_sgl_t * dma_get_buffer(dmach_t channel, int buf_num); + +This call allocates DMA descriptors for the user. + + +void dma_return_buffer(dmach_t channel, dma_sgl_t *list); + +This call returns the allocated descriptors back to the API. + + +int dma_suspend(dmach_t channel); + +This call suspends any DMA transfer on the given channel. + + + +int dma_resume(dmach_t channel); + +This call resumes a DMA transfer which would have been stopped through +dma_suspend(). + + +int dma_flush_all(dmach_t channel); + +This completely flushes all queued buffers and on-going DMA transfers on a +given channel. This is called when DMA channel errors have occured. + + +void dma_free(dmach_t channel); + +This clears all activities on a given DMA channel and releases it for future +requests. + + + +Buffer Allocation +----------------- +It is the user's responsibility to allocate, free, and keep track of the +allocated DMA data memory. Upon calling dma_queue_buffer() the user must +relinquish the control of the buffers to the kernel and not change the +state of the buffers that it has passed to the kernel. The user will regain +the control of the buffers when it has been woken up by the bottom half of +the DMA interrupt handler. The user can allocate cached buffers or non-cached +via pci_alloc_consistent(). It is the user's responsibility to ensure that +the data is cache coherent. + +*Reminder* +The user is responsble to ensure the ATU is setup properly for DMA transfers. + +All Disclaimers apply. Use this at your own discretion. Neither Intel nor I +will be responsible ifanything goes wrong. diff -Nru a/Documentation/arm/XScale/IOP3XX/message.txt b/Documentation/arm/XScale/IOP3XX/message.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/message.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,110 @@ +Support functions for the Intel 80310 MU +=========================================== + +Dave Jiang +Last updated: 10/11/2001 + +The messaging unit of the IOP310 contains 4 components and is utilized for +passing messages between the PCI agents on the primary bus and the Intel(R) +80200 CPU. The four components are: +Messaging Component +Doorbell Component +Circular Queues Component +Index Registers Component + +Messaging Component: +Contains 4 32bit registers, 2 in and 2 out. Writing to the registers assert +interrupt on the PCI bus or to the 80200 depend on incoming or outgoing. + +int mu_msg_request(u32 *mu_context); +Request the usage of Messaging Component. mu_context is written back by the +API. The MU context is passed to other Messaging calls as a parameter. + +int mu_msg_set_callback(u32 mu_context, u8 reg, mu_msg_cb_t func); +Setup the callback function for incoming messages. Callback can be setup for +outbound 0, 1, or both outbound registers. + +int mu_msg_post(u32 mu_context, u32 val, u8 reg); +Posting a message in the val parameter. The reg parameter denotes whether +to use register 0, 1. + +int mu_msg_free(u32 mu_context, u8 mode); +Free the usage of messaging component. mode can be specified soft or hard. In +hardmode all resources are unallocated. + +Doorbell Component: +The doorbell registers contains 1 inbound and 1 outbound. Depending on the bits +being set different interrupts are asserted. + +int mu_db_request(u32 *mu_context); +Request the usage of the doorbell register. + +int mu_db_set_callback(u32 mu_context, mu_db_cb_t func); +Setting up the inbound callback. + +void mu_db_ring(u32 mu_context, u32 mask); +Write to the outbound db register with mask. + +int mu_db_free(u32 mu_context); +Free the usage of doorbell component. + +Circular Queues Component: +The circular queue component has 4 circular queues. Inbound post, inbound free, +outbound post, outbound free. These queues are used to pass messages. + +int mu_cq_request(u32 *mu_context, u32 q_size); +Request the usage of the queue. See code comment header for q_size. It tells +the API how big of queues to setup. + +int mu_cq_inbound_init(u32 mu_context, mfa_list_t *list, u32 size, + mu_cq_cb_t func); +Init inbound queues. The user must provide a list of free message frames to +be put in inbound free queue and the callback function to handle the inbound +messages. + +int mu_cq_enable(u32 mu_context); +Enables the circular queues mechanism. Called once all the setup functions +are called. + +u32 mu_cq_get_frame(u32 mu_context); +Obtain the address of an outbound free frame for the user. + +int mu_cq_post_frame(u32 mu_context, u32 mfa); +The user can post the frame once getting the frame and put information in the +frame. + +int mu_cq_free(u32 mu_context); +Free the usage of circular queues mechanism. + +Index Registers Component: +The index register provides the mechanism to receive inbound messages. + +int mu_ir_request(u32 *mu_context); +Request of Index Register component usage. + +int mu_ir_set_callback(u32 mu_context, mu_ir_cb_t callback); +Setting up callback for inbound messages. The callback will receive the +value of the register that IAR offsets to. + +int mu_ir_free(u32 mu_context); +Free the usage of Index Registers component. + +void mu_set_irq_threshold(u32 mu_context, int thresh); +Setup the IRQ threshold before relinquish processing in IRQ space. Default +is set at 10 loops. + + +*NOTE: Example of host driver that utilize the MU can be found in the Linux I2O +driver. Specifically i2o_pci and some functions of i2o_core. The I2O driver +only utilize the circular queues mechanism. The other 3 components are simple +enough that they can be easily setup. The MU API provides no flow control for +the messaging mechanism. Flow control of the messaging needs to be established +by a higher layer of software on the IOP or the host driver. + +All Disclaimers apply. Use this at your own discretion. Neither Intel nor I +will be responsible if anything goes wrong. =) + + +TODO +____ + diff -Nru a/Documentation/arm/XScale/IOP3XX/pmon.txt b/Documentation/arm/XScale/IOP3XX/pmon.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP3XX/pmon.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,71 @@ + +Intel's XScale Microarchitecture 80312 companion processor provides a +Performance Monitoring Unit (PMON) that can be utilized to provide +information that can be useful for fine tuning of code. This text +file describes the API that's been developed for use by Linux kernel +programmers. Note that to get the most usage out of the PMON, +I highly reccomend getting the XScale reference manual from Intel[1] +and looking at chapter 12. + +To use the PMON, you must #include in your +source file. + +Since there's only one PMON, only one user can currently use the PMON +at a given time. To claim the PMON for usage, call iop310_pmon_claim() which +returns an identifier. When you are done using the PMON, call +iop310_pmon_release() with the id you were given earlier. + +The PMON consists of 14 registers that can be used for performance measurements. +By combining different statistics, you can derive complex performance metrics. + +To start the PMON, just call iop310_pmon_start(mode). Mode tells the PMON what +statistics to capture and can each be one of: + + IOP310_PMU_MODE0 + Performance Monitoring Disabled + + IOP310_PMU_MODE1 + Primary PCI bus and internal agents (bridge, dma Ch0, dam Ch1, patu) + + IOP310_PMU_MODE2 + Secondary PCI bus and internal agents (bridge, dma Ch0, dam Ch1, patu) + + IOP310_PMU_MODE3 + Secondary PCI bus and internal agents (external masters 0..2 and Intel + 80312 I/O companion chip) + + IOP310_PMU_MODE4 + Secondary PCI bus and internal agents (external masters 3..5 and Intel + 80312 I/O companion chip) + + IOP310_PMU_MODE5 + Intel 80312 I/O companion chip internal bus, DMA Channels and Application + Accelerator + + IOP310_PMU_MODE6 + Intel 80312 I/O companion chip internal bus, PATU, SATU and Intel 80200 + processor + + IOP310_PMU_MODE7 + Intel 80312 I/O companion chip internal bus, Primary PCI bus, Secondary + PCI bus and Secondary PCI agents (external masters 0..5 & Intel 80312 I/O + companion chip) + +To get the results back, call iop310_pmon_stop(&results) where results is +defined as follows: + +typedef struct _iop310_pmon_result +{ + u32 timestamp; /* Global Time Stamp Register */ + u32 timestamp_overflow; /* Time Stamp overflow count */ + u32 event_count[14]; /* Programmable Event Counter + Registers 1-14 */ + u32 event_overflow[14]; /* Overflow counter for PECR1-14 */ +} iop310_pmon_res_t; + + +-- +This code is still under development, so please feel free to send patches, +questions, comments, etc to me. + +Deepak Saxena diff -Nru a/Documentation/arm/XScale/IXP2000/IXDP2400 b/Documentation/arm/XScale/IXP2000/IXDP2400 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IXP2000/IXDP2400 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,130 @@ + +Board Overview +-------------- + +The IXDP2400 is an evaluation platform for Intel's IXP2400 network +processor. The IXP2400 is a high-speed network proccessor that contains +8 Microengines for network applications, built in 16550 UART, GPIO, +and a built in PCI host/slave bridge. + +The IXDP2400 is a dual NPU board in which both processors are sitting +on the PCI bus. Each one has it's own network interface (82559) and serial +console. The Master NPU handles Egress operations and the slave NPU handles +Ingress operations. In addition, the master NPU has a TVM sensor connected +to it over two GPIO lines that are being used as an I2C interface. + +Port Status +----------- + +Supported: + +- MTD/JFFS2 access of on board flash +- NFS root +- RAMDISK root +- Serial console on ttyS0 +- PCI E100 card + +Not Supported/Coming Soon: + +- TVM -- I have code but working on cleaning it up +- Slave Driver to load kernel image over PCI -- Need to do some more testing + +Not Planned: + +- Microengines: To make use of the microengines, you need a third party + stack such as the intel IXASDK or Teja. + +Building the Kernel +------------------- + +Note: You will need a toolchain that has proper support for big endian builds. + +make ixdp2400_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just change the "root=" option on the commandline. + +Preparing the Hardware +---------------------- + +Make sure you do an 'fis init' command once you boot up to intialize +RedBoot's flash filesystem. + +Connect the serial port on +your board to the serial port on your host. + +Configure minicom for 57600N81. + +Note that you must be using a version of RedBoot from Intel that supports the +'exec' command or Linux will not work on the 2400. The version I am using is: + + +RedBoot(tm) bootstrap and debug environment, version R1.24 - built 16:00:39, Dec + 12 2002 + +Please contact Intel regarding how to get an updated RedBoot image. + + +Loading the Kernel +------------------ + +Master-RedBoot> load -r -v -b 0x1d008000 zImage.ixp2000 +Raw file loaded 0x1d008000-0x1d0a812c +Master-RedBoot> exec 0x1d008000 + + +Now do the same on the slave side. + +Root Devices +------------ + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + +To use a ramdisk, load it to location 0x1c600000 + +MTD on the IXDP2400 +------------------ + +Please read the file Documentation/arm/XScale/IOP3xx/IQ80310 for information +on mapping RedBoot FIS partitions to MTD partitions. + +NOTES +----- + +Each NPU on the board has memory from physical 0x00000000 to 0x2000000; +however, Linux by default is configure to run only in the top 64MB of +RAM. The reasoning for this is b/c the lower portion of memory is meant +to be used by the microengines libraries in the Intel SDK. If you want +to use all 512MB of memory, you need to change the ZRELADDR value in +arch/arm/boot/Makefile, and change the PHYS_OFFSET variable in +include/asm/arch/memory.h. At some point in the future this might be +made into a configuration variable. + +If you plan to use the slowport on the IXP2400 in your board, please read +the notes in include/asm-arm/arch-ixp2000/ixp2000.h on the proper way +to access it. Since you will probably be multiplexing several different +devices on the port, you need to follow the instructions there for things +to work properly. + +If you are designing a custom board with dual NPUs: DO NOT PUT TWO NPUs +ON THE SAME BUS EACH WITH IT'S OWN ETHERNET. The PCI bus is a single +master bus and all interrupts should be routed to a single device on the +board. The IXDP2400 is breaking this and requires some ugly hacks in +the code to make things work. Please do not do this. If you need multiple +PCI domains, use a non-transparent P2P bridge on your board between the +egress and ingress sides. Please. + +Contributors +------------ + +Original porting done by Naeem M. Afzal (Intel Corporation) + +Maintained by Deepak Saxena + diff -Nru a/Documentation/arm/XScale/IXP425/IXDP425 b/Documentation/arm/XScale/IXP425/IXDP425 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IXP425/IXDP425 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,97 @@ + +Board Overview +-------------- + +The IXDP425 is an evaluation platform for Intel's IXP425 network processor. + +The IXP425 contains on chip dual-UARTs, PCI host bridge, USB endpoint, +two 10/100 NPEs (Network Programmable Engines) and 1 WAN NPE, and 16 GPIOs. + +The IXDP425 contains four PCI slots, a set of 7 segment LEDs, 16MB +of flash, and a serial PROM connected to two GPIO lines. + +Port Status +----------- + +Supported: + +- MTD/JFFS2 access of on board flash +- NFS root +- RAMDISK root +- Serial console on ttyS0 +- PCI E100 card + +Not Supported: + +- NPEs +- USB endpoint +- I2C access + +Building the Kernel +------------------- + +Note: You will need a toolchain that has proper support for big endian builds. + +make ixdp425_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just change the "root=" option on the commandline. + +Preparing the Hardware +---------------------- + +Make sure you do an 'fis init' command once you boot up to intialize +RedBoot's flash filesystem. + +Connect the serial port on your host to the serial port labeled UART0 +on the board. + +Configure minicom for 115200N81 + +Loading the Kernel +------------------ + + RedBoot> load -r -v -b 0x11608000 zImage + RedBoot> go 0x11608000 + + +Root Devices +------------ + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + + +MTD on the IXDP425 +------------------ + +Please read the file Documentation/arm/XScale/IOP3xx/IQ80310 for information +on mapping RedBoot FIS partitions to MTD partitions. + + +Using >64MB RAM +--------------- + +By default, the kernel is configure to only use 64MB of memory. There +is a very good reason for this. The inbound PCI window on the IXP425 +is only 64MB in size, so if you are using more memory than this, all +PCI DMA buffers above 64MB need to be bounced down to the 64MB +GFP_DMA area. This is very expensive and will lead to performance +degradation. To use more then 64MB of memory, you need to turn on +CONFIG_IXP425_LARGE_SDRAM and then updated the "mem=" portion +of the command line appropriately. + +Contributors +------------ + +Original porting done by Jungo Software + +Cleanedup and maintained by Deepak Saxena + + diff -Nru a/Documentation/arm/XScale/cache-lock.txt b/Documentation/arm/XScale/cache-lock.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/cache-lock.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,123 @@ + +Intel's XScale Microarchitecture provides support for locking of data +and instructions into the appropriate caches. This file provides +an overview of the API that has been developed to take advantage of this +feature from kernel space. Note that there is NO support for user space +cache locking. + +For example usage of this code, grab: + + ftp://source.mvista.com/pub/xscale/cache-test.c + +If you have any questions, comments, patches, etc, please contact me. + +Deepak Saxena + +API DESCRIPTION + + +I. Header File + + #include + +II. Cache Capability Discovery + + SYNOPSIS + + int cache_query(u8 cache_type, + struct cache_capabilities *pcache); + + struct cache_capabilities + { + u32 flags; /* Flags defining capabilities */ + u32 cache_size; /* Cache size in K (1024 bytes) */ + u32 max_lock; /* Maximum lockable region in K */ + } + + /* + * Flags + */ + + /* + * Bit 0: Cache lockability + * Bits 1-31: Reserved for future use + */ + #define CACHE_LOCKABLE 0x00000001 /* Cache can be locked */ + + /* + * Cache Types + */ + #define ICACHE 0x00 + #define DCACHE 0x01 + + DESCRIPTION + + This function fills out the pcache capability identifier for the + requested cache. cache_type is either DCACHE or ICACHE. This + function is not very useful at the moment as all XScale CPU's + have the same size Cache, but is is provided for future XScale + based processors that may have larger cache sizes. + + RETURN VALUE + + This function returns 0 if no error occurs, otherwise it returns + a negative, errno compatible value. + + -EIO Unknown hardware error + +III. Cache Locking + + SYNOPSIS + + int cache_lock(void *addr, u32 len, u8 cache_type, const char *desc); + + DESCRIPTION + + This function locks a physically contigous portion of memory starting + at the virtual address pointed to by addr into the cache referenced + by cache_type. + + The address of the data/instruction that is to be locked must be + aligned on a cache line boundary (L1_CACHE_ALIGNEMENT). + + The desc parameter is an optional (pass NULL if not used) human readable + descriptor of the locked memory region that is used by the cache + management code to build the /proc/cache_locks table. + + Note that this function does not check whether the address is valid + or not before locking it into the cache. That duty is up to the + caller. Also, it does not check for duplicate or overlaping + entries. + + RETURN VALUE + + If the function is successful in locking the entry into cache, a + zero is returned. + + If an error occurs, an appropriate error value is returned. + + -EINVAL The memory address provided was not cache line aligned + -ENOMEM Could not allocate memory to complete operation + -ENOSPC Not enough space left on cache to lock in requested region + -EIO Unknown error + +III. Cache Unlocking + + SYNOPSIS + + int cache_unlock(void *addr) + + DESCRIPTION + + This function unlocks a portion of memory that was previously locked + into either the I or D cache. + + RETURN VALUE + + If the entry is cleanly unlocked from the cache, a 0 is returned. + In the case of an error, an appropriate error is returned. + + -ENOENT No entry with given address associated with this cache + -EIO Unknown error + + diff -Nru a/Documentation/arm/XScale/pmu.txt b/Documentation/arm/XScale/pmu.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/pmu.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,168 @@ + +Intel's XScale Microarchitecture processors provide a Performance +Monitoring Unit (PMU) that can be utilized to provide information +that can be useful for fine tuning of code. This text file describes +the API that's been developed for use by Linux kernel programmers. +When I have some extra time on my hand, I will extend the code to +provide support for user mode performance monitoring (which is +probably much more useful). Note that to get the most usage out +of the PMU, I highly reccomend getting the XScale reference manual +from Intel and looking at chapter 12. + +To use the PMU, you must #include in your source file. + +Since there's only one PMU, only one user can currently use the PMU +at a given time. To claim the PMU for usage, call pmu_claim() which +returns an identifier. When you are done using the PMU, call +pmu_release() with the identifier that you were given by pmu_claim. + +In addition, the PMU can only be used on XScale based systems that +provide an external timer. Systems that the PMU is currently supported +on are: + + - Cyclone IQ80310 + +Before delving into how to use the PMU code, let's do a quick overview +of the PMU itself. The PMU consists of three registers that can be +used for performance measurements. The first is the CCNT register with +provides the number of clock cycles elapsed since the PMU was started. +The next two register, PMN0 and PMN1, are eace user programmable to +provide 1 of 20 different performance statistics. By combining different +statistics, you can derive complex performance metrics. + +To start the PMU, just call pmu_start(pm0, pmn1). pmn0 and pmn1 tell +the PMU what statistics to capture and can each be one of: + +EVT_ICACHE_MISS + Instruction fetches requiring access to external memory + +EVT_ICACHE_NO_DELIVER + Instruction cache could not deliver an instruction. Either an + ICACHE miss or an instruction TLB miss. + +EVT_ICACHE_DATA_STALL + Stall in execution due to a data dependency. This counter is + incremented each cycle in which the condition is present. + +EVT_ITLB_MISS + Instruction TLB miss + +EVT_DTLB_MISS + Data TLB miss + +EVT_BRANCH + A branch instruction was executed and it may or may not have + changed program flow + +EVT_BRANCH_MISS + A branch (B or BL instructions only) was mispredicted + +EVT_INSTRUCTION + An instruction was executed + +EVT_DCACHE_FULL_STALL + Stall because data cache buffers are full. Incremented on every + cycle in which condition is present. + +EVT_DCACHE_FULL_STALL_CONTIG + Stall because data cache buffers are full. Incremented on every + cycle in which condition is contigous. + +EVT_DCACHE_ACCESS + Data cache access (data fetch) + +EVT_DCACHE_MISS + Data cache miss + +EVT_DCACHE_WRITE_BACK + Data cache write back. This counter is incremented for every + 1/2 line (four words) that are written back. + +EVT_PC_CHANGED + Software changed the PC. This is incremented only when the + software changes the PC and there is no mode change. For example, + a MOV instruction that targets the PC would increment the counter. + An SWI would not as it triggers a mode change. + +EVT_BCU_REQUEST + The Bus Control Unit(BCU) received a request from the core + +EVT_BCU_FULL + The BCU request queue if full. A high value for this event means + that the BCU is often waiting for to complete on the external bus. + +EVT_BCU_DRAIN + The BCU queues were drained due to either a Drain Write Buffer + command or an I/O transaction for a page that was marked as + uncacheable and unbufferable. + +EVT_BCU_ECC_NO_ELOG + The BCU detected an ECC error on the memory bus but noe ELOG + register was available to to log the errors. + +EVT_BCU_1_BIT_ERR + The BCU detected a 1-bit error while reading from the bus. + +EVT_RMW + An RMW cycle occurred due to narrow write on ECC protected memory. + +To get the results back, call pmu_stop(&results) where results is defined +as a struct pmu_results: + + struct pmu_results + { + u32 ccnt; /* Clock Counter Register */ + u32 ccnt_of; / + u32 pmn0; /* Performance Counter Register 0 */ + u32 pmn0_of; + u32 pmn1; /* Performance Counter Register 1 */ + u32 pmn1_of; + }; + +Pretty simple huh? Following are some examples of how to get some commonly +wanted numbers out of the PMU data. Note that since you will be dividing +things, this isn't super useful from the kernel and you need to printk the +data out to syslog. See [1] for more examples. + +Instruction Cache Efficiency + + pmu_start(EVT_INSTRUCTION, EVT_ICACHE_MISS); + ... + pmu_stop(&results); + + icache_miss_rage = results.pmn1 / results.pmn0; + cycles_per_instruction = results.ccnt / results.pmn0; + +Data Cache Efficiency + + pmu_start(EVT_DCACHE_ACCESS, EVT_DCACHE_MISS); + ... + pmu_stop(&results); + + dcache_miss_rage = results.pmn1 / results.pmn0; + +Instruction Fetch Latency + + pmu_start(EVT_ICACHE_NO_DELIVER, EVT_ICACHE_MISS); + ... + pmu_stop(&results); + + average_stall_waiting_for_instruction_fetch = + results.pmn0 / results.pmn1; + + percent_stall_cycles_due_to_instruction_fetch = + results.pmn0 / results.ccnt; + + +ToDo: + +- Add support for usermode PMU usage. This might require hooking into + the scheduler so that we pause the PMU when the task that requested + statistics is scheduled out. + +-- +This code is still under development, so please feel free to send patches, +questions, comments, etc to me. + +Deepak Saxena + diff -Nru a/Documentation/arm/XScale/tlb-lock.txt b/Documentation/arm/XScale/tlb-lock.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/tlb-lock.txt Thu Dec 4 16:24:26 2003 @@ -0,0 +1,64 @@ + +Intel's XScale Microarchitecture provides support for locking of TLB +entries in both the instruction and data TLBs. This file provides +an overview of the API that has been developed to take advantage of this +feature from kernel space. Note that there is NO support for user space. + +In general, this feature should be used in conjunction with locking +data or instructions into the appropriate caches. See the file +cache-lock.txt in this directory. + +If you have any questions, comments, patches, etc, please contact me. + +Deepak Saxena + + +API DESCRIPTION + +I. Header file + + #include + +II. Locking an entry into the TLB + + SYNOPSIS + + xscale_tlb_lock(u8 tlb_type, u32 addr); + + /* + * TLB types + */ + #define ITLB 0x0 + #define DTLB 0x1 + + DESCRIPTION + + This function locks the virtual to physical mapping for virtual + address addr into the requested TLB. + + RETURN VALUE + + If the entry is properly locked into the TLB, a 0 is returned. + In case of an error, an appropriate error is returned. + + -ENOSPC No more entries left in the TLB + -EIO Unknown error + +III. Unlocking an entry from a TLB + + SYNOPSIS + + xscale_tlb_unlock(u8 tlb_type, u32 addr); + + DESCRIPTION + + This function unlocks the entry for virtual address addr from the + specified cache. + + RETURN VALUE + + If the TLB entry is properly unlocked, a 0 is returned. + In case of an error, an appropriate error is returned. + + -ENOENT No entry for given address in specified TLB + diff -Nru a/Documentation/arm/kgdb b/Documentation/arm/kgdb --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/kgdb Thu Dec 4 16:24:26 2003 @@ -0,0 +1,82 @@ + +KGDB for ARM-Linux Usage Notes + +NOTE: This is an early access release of kgdb and thus there may be unknown + issues that still need to be fixed. Please send all bug reports + to dsaxena@mvista.com. + + +Theory of Operation +------------------------------------------------------------ + +[to be completed] + + +Adding KGDB Support to your Board Port +------------------------------------------------------------ + +Adding KGDB support to your ARM port is fairly simple. You simply +need to create the three functions: + + - kgdb_serial_init(void) + This function is called to initialize the serial port. In + the future, this will include a parameter with the cmdline + options sent to kgdb. + + - kgdb_serial_putchar(unsigned char) + Output a single character over the serial port + + - unsigned char kgdb_serial_getchar(void) + Receive a single character over the serial port + +Once those three functions have been created, the rest of KGDB is +board independent and should work without any problems. + +Console Messages over KGDB +------------------------------------------------------------ + +Note that if you have only one serial port on your board, you cannot +use that serial port for both serial console and KGDB. In this case, +you can add a 'console=ttyKGDB' option to your kernel command line +and KGDB will output console messages to the GDB client. + + +Using KGDB +------------------------------------------------------------ + +To use kgdb you need to first turn on both the CONFIG_KGDB and +CONFIG_KGDB_SERIAL config options. In addition to this, you can +turn on CONFIG_KGDB_CONSOLE to enable console output to be +viewed by the GDB client program. + +Once KGDB is enabled, the kernel will automatically breakpoint() +at arch/arm/kernel/trap.s:trap_init(). Note that this is the +earliest point at which KGDB can be intialized due to the fact +that it relies on the undefined instruction handler. Once KGDB +is entered, you can connect to it from the client via +'target remote /dev/ttySx', where ttySx is the serial port on +the host machine that is connected to your board. + +Note that you must let the kernel breakpoint() before trying to +connect the debugger, otherwise the two will get out of sync and +you will not be able to start the debug session. + +If you don't want the kernel to stop immediately at boot up, you can +add the 'nohalt' option to the command line. If you have CONFIG_MAGICSYSRQ +turned on, you can send a SysReq-G to the system console at anytime to +force a breakpoint. In minicom, this is accomplished via the following +key combination: Alt-A f g. + +Once you've established a connection between the GDB client and the KGDB +stub, you can debug as you normally would. Consult the GDB documentation +if you need help with debugging commands. + +Finding Bugs +------------------------------------------------------------ + +If you think you've found a bug in the communication layer between +the client and KGDB, add the following command to the beggining of +your gdb session: 'set debug remote 1'. This will output all packet +data to the screen and you can send the packet log along with a +description of what you were doing at the time to me. + diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Thu Dec 4 16:24:26 2003 +++ b/MAINTAINERS Thu Dec 4 16:24:26 2003 @@ -701,6 +701,13 @@ L: linux-hippi@sunsite.dk S: Maintained +HOST AP DRIVER +P: Jouni Malinen +M: jkmaline@cc.hut.fi +L: hostap@shmoo.com +W: http://hostap.epitest.fi/ +S: Maintained + HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series P: Jaroslav Kysela M: perex@suse.cz diff -Nru a/Makefile b/Makefile --- a/Makefile Thu Dec 4 16:24:25 2003 +++ b/Makefile Thu Dec 4 16:24:25 2003 @@ -1,11 +1,13 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 21 -EXTRAVERSION =-rmk1 +EXTRAVERSION =-rmk1-ds3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) -ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +# ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) + +ARCH = arm KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ @@ -19,7 +21,7 @@ HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -CROSS_COMPILE = +CROSS_COMPILE = /opt/montavista/devkit/arm/xscale_le/bin/xscale_le- # # Include the make variables (CC, etc...) diff -Nru a/Rules.make b/Rules.make --- a/Rules.make Thu Dec 4 16:24:26 2003 +++ b/Rules.make Thu Dec 4 16:24:26 2003 @@ -328,3 +328,5 @@ ifneq ($(FILES_FLAGS_CHANGED),) $(FILES_FLAGS_CHANGED): dummy endif + + diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile --- a/arch/arm/Makefile Thu Dec 4 16:24:25 2003 +++ b/arch/arm/Makefile Thu Dec 4 16:24:25 2003 @@ -22,6 +22,18 @@ CFLAGS +=-g endif +ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) +CC += -mbig-endian +AS += -EB +LD += -EB +endif + + +# +# Determine GCC version for proper compiler options +# +GCC_VERSION := $(shell $(CROSS_COMPILE)gcc -v 2>&1 | grep version | cut -f3 -d' ' | cut -f1 -d.) + # Select CPU dependent flags. Note that order of declaration is important; # the options further down the list override previous items. # @@ -38,6 +50,11 @@ arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5 +ifeq ($(GCC_VERSION),3) + arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -mcpu=xscale +else + arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mxscale +endif # This selects how we optimise for the processor. tune-y := @@ -49,10 +66,15 @@ tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 +ifeq ($(GCC_VERSION),3) + tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale +else + tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm +endif CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm -AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float +AFLAGS +=$(apcs-y) $(arch-y) -msoft-float ifeq ($(CONFIG_CPU_26),y) PROCESSOR := armo @@ -68,7 +90,7 @@ ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv -TEXTADDR = 0xC0008000 +TEXTADDR = 0x$(shell echo $(CONFIG_KERNEL_START)|sed -e's/0000$$/8000/'|sed -e's/^0x//') LDSCRIPT = arch/arm/vmlinux-armv.lds.in endif @@ -164,6 +186,26 @@ MACHINE = omaha endif +ifeq ($(CONFIG_ARCH_IOP3XX),y) +MACHINE = iop3xx +endif + +ifeq ($(CONFIG_ARCH_IXP1200),y) +MACHINE = ixp1200 +endif + +ifeq ($(CONFIG_ARCH_ADIFCC),y) +MACHINE = adifcc +endif + +ifeq ($(CONFIG_ARCH_IXP425),y) +MACHINE = ixp425 +endif + +ifeq ($(CONFIG_ARCH_IXP2000),y) +MACHINE = ixp2000 +endif + export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS # Only set INCDIR if its not already defined above @@ -269,7 +311,7 @@ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) -bzImage zImage zinstall Image bootpImage install: vmlinux +bzImage zImage zinstall Image bootpImage install zsrec %.swap: vmlinux @$(MAKEBOOT) $@ CLEAN_FILES += \ diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile --- a/arch/arm/boot/Makefile Thu Dec 4 16:24:25 2003 +++ b/arch/arm/boot/Makefile Thu Dec 4 16:24:25 2003 @@ -117,6 +117,30 @@ ZRELADDR = 0x20008000 endif +ifeq ($(CONFIG_ARCH_IOP3XX),y) +ZRELADDR = 0xa0008000 +PARAMS_PHYS = 0xa0000100 +endif + +ifeq ($(CONFIG_ARCH_ADIFCC),y) +ZRELADDR = 0xc0008000 +PARAMS_PHYS = 0xc0000100 +endif + +ifeq ($(CONFIG_ARCH_IXP1200),y) +ZRELADDR = 0x$(shell echo $(CONFIG_IXP1200_SDRAM_BASE) | sed -e 's/0000$$/8000/') +endif + +ifeq ($(CONFIG_ARCH_IXP425),y) +ZRELADDR = 0x00008000 +PARAMS_PHYS = 0x00000100 +endif + +ifeq ($(CONFIG_ARCH_IXP2000),y) +# compressed kernel relocating address +ZRELADDR = 0x1c008000 +endif + # # We now have a PIC decompressor implementation. Decompressors running # from RAM should not define ZTEXTADDR. Decompressors running directly @@ -140,6 +164,9 @@ zImage: compressed/vmlinux $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ +zsrec: compressed/vmlinux + $(OBJCOPY) -O srec -R .note -R .comment -S $< $@ + bootpImage: bootp/bootp $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ @@ -159,8 +186,14 @@ zinstall: zImage sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" +endianswap: endianswap.c + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< + +%.swap: % endianswap + ./endianswap < $< > $@ + clean: - $(RM) Image zImage bootpImage + $(RM) Image zImage bootpImage endianswap zsrec *.swap @$(MAKE) -C compressed clean @$(MAKE) -C bootp clean diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile --- a/arch/arm/boot/compressed/Makefile Thu Dec 4 16:24:26 2003 +++ b/arch/arm/boot/compressed/Makefile Thu Dec 4 16:24:26 2003 @@ -71,6 +71,21 @@ OBJS += head-sa1100.o endif +ifeq ($(CONFIG_CPU_XSCALE),y) +OBJS += head-xscale.o +endif + +# +# Just borrow from SA1* for now +# +ifeq ($(CONFIG_ARCH_IXP1200),y) +OBJS += head-sa1100.o +endif + +ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) +OBJS += big-endian.o +endif + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) diff -Nru a/arch/arm/boot/compressed/big-endian.S b/arch/arm/boot/compressed/big-endian.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/boot/compressed/big-endian.S Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * linux/arch/arm/boot/compressed/big-endian.S + * + * Switch CPU into big endian mode. + * Author: Nicolas Pitre + */ + + .section ".start", #alloc, #execinstr + + mrc p15, 0, r0, c1, c0, 0 @ read control reg + orr r0, r0, #(1 << 7) @ enable big endian mode + mcr p15, 0, r0, c1, c0, 0 @ write control reg + diff -Nru a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/boot/compressed/head-xscale.S Thu Dec 4 16:24:26 2003 @@ -0,0 +1,78 @@ +/* + * linux/arch/arm/boot/compressed/head-xscale.S + * + * XScale specific tweaks. This is merged into head.S by the linker. + * + */ + +#include +#include +#include + + .section ".start", #alloc, #execinstr + +__XScale_start: + + @ Preserve r8/r7 i.e. kernel entry values + + @ Be sure to flush kernel binary out of the cache, + @ whatever state it is, before it is turned off. + @ This is done by fetching through currently executed + @ memory to be sure we hit the same cache. + + bic r2, pc, #0x1f + add r3, r2, #0x10000 @ 64 kb is quite enough... +1: ldr r0, [r2], #32 + teq r2, r3 + bne 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches + + @ disabling MMU and caches + mrc p15, 0, r0, c1, c0, 0 @ read control reg + bic r0, r0, #0x05 @ clear DC, MMU + bic r0, r0, #0x1000 @ clear Icache + mcr p15, 0, r0, c1, c0, 0 + + + @ + @ TODO: Move this to bootloader! + @ +#ifdef CONFIG_ARCH_IOP321 + @ Make up for RedBoots memory map + @ New redboot will fix this... + orr pc, pc, #0xa0000000 + nop + +#ifdef CONFIG_ARCH_IQ80321 + mov r7, #MACH_TYPE_IQ80321 +#endif +#ifdef CONFIG_ARCH_IQ31244 + mov r7, #(MACH_TYPE_IQ31244 & 0xff) + orr r7, r7, #(MACH_TYPE_IQ31244 & 0xff00) +#endif +#endif + +#ifdef CONFIG_ARCH_IQ80310 + + /* + * Crank the CPU up to 733MHz + */ + mov r1, #9 + mcr p14, 0, r1, c6, c0, 0 + + /* + * Disable ECC error notification + * At some point, we should add an ECC handler to Linux + */ + mov r1, #0x1500 + mov r0, #0x4 + str r0, [r1, #0x34] + + mov r7, #MACH_TYPE_IQ80310 +#endif + +#ifdef CONFIG_ARCH_BRH + mov r7, #MACH_TYPE_BRH +#endif + diff -Nru a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S --- a/arch/arm/boot/compressed/head.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/boot/compressed/head.S Thu Dec 4 16:24:25 2003 @@ -343,7 +343,11 @@ orr r1, r1, #3 << 10 add r2, r3, #16384 1: cmp r1, r8 @ if virt > start of RAM +#ifdef CONFIG_XSCALE_CACHE_ERRATA + orrhs r1, r1, #0x08 @ set cacheable, not bufferable +#else orrhs r1, r1, #0x0c @ set cacheable, bufferable +#endif cmp r1, r9 @ if virt > end of RAM bichs r1, r1, #0x0c @ clear cacheable, bufferable str r1, [r0], #4 @ 1:1 mapping @@ -429,6 +433,7 @@ mov r1, r7 @ restore architecture number mov pc, r4 @ call kernel + /* * Here follow the relocatable cache support functions for the * various processors. This is a generic hook for locating an @@ -509,6 +514,12 @@ b __armv4_cache_flush .word 0x6901b110 @ sa1110 + .word 0xfffffff0 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + + .word 0x6901c120 .word 0xfffffff0 b __armv4_cache_on b __armv4_cache_off diff -Nru a/arch/arm/boot/endianswap.c b/arch/arm/boot/endianswap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/boot/endianswap.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,50 @@ +/* + * endianswap.c : Swaps endianness on 4-byte boundaries. + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * The purpose of this tool is to convert a kernel image which is compiled + * to run in a different endianness than what the CPU is initially set with. + * The kernel will switch the CPU endian mode as required, but since the + * bootloader lays the kernel in memory according to the current endianness + * we have to swap it over. As long as the desired endianness is set before + * any memory access smaller than a word is performed there shouldn't be any + * problem executing such code. + */ + +#include + +int main(int argc, char *argv[]) +{ + int a, b, c, d; + + for (;;) { + a = getchar(); + b = getchar(); + c = getchar(); + d = getchar(); + if ((a|b|c|d) & ~0xff) + break; + putchar(d); + putchar(c); + putchar(b); + putchar(a); + } + if (a < 0) + return 0; + if (b < 0) + b = 0; + if (c < 0) + c = 0; + if (d < 0) + d = 0; + putchar(d); + putchar(c); + putchar(b); + putchar(a); + return 0; +} diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Thu Dec 4 16:24:25 2003 +++ b/arch/arm/config.in Thu Dec 4 16:24:25 2003 @@ -17,6 +17,7 @@ mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE endmenu @@ -33,7 +34,8 @@ comment 'System Type' choice 'ARM system type' \ - "Anakin CONFIG_ARCH_ANAKIN \ + "ADIFCC-based CONFIG_ARCH_ADIFCC \ + Anakin CONFIG_ARCH_ANAKIN \ Archimedes/A5000 CONFIG_ARCH_ARCA5K \ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \ @@ -42,6 +44,9 @@ Excalibur-ARM CONFIG_ARCH_CAMELOT \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ + IOP3xx-based CONFIG_ARCH_IOP3XX \ + IXP425-based CONFIG_ARCH_IXP425 \ + IXP2000-based CONFIG_ARCH_IXP2000 \ Omaha CONFIG_ARCH_OMAHA \ LinkUp-L7200 CONFIG_ARCH_L7200 \ Motorola-MX1ADS CONFIG_ARCH_MX1ADS \ @@ -146,6 +151,50 @@ dep_bool ' Atmel AT91RM9200 Development Board' CONFIG_ARCH_AT91RM9200DK $CONFIG_ARCH_AT91RM9200 endmenu +if [ "$CONFIG_ARCH_IOP3XX" = "y" ]; then + mainmenu_option next_comment + comment 'IOP3xx Implementation Options' + choice 'IOP3xx System Type' \ + "IQ80310 CONFIG_ARCH_IQ80310\ + IQ80321 CONFIG_ARCH_IQ80321\ + IQ31244 CONFIG_ARCH_IQ31244" IQ80310 + +# Which IOP variants are we supporting? + if [ "$CONFIG_ARCH_IQ80310" = "y" ]; then + define_bool CONFIG_ARCH_IOP310 y + else + define_bool CONFIG_ARCH_IOP310 n + fi + + if [ "$CONFIG_ARCH_IQ80321" = "y" -o "$CONFIG_ARCH_IQ31244" = "y" ]; then + define_bool CONFIG_ARCH_IOP321 y + else + define_bool CONFIG_ARCH_IOP321 n + fi + + comment 'IOP3xx Chipset Features' + dep_bool 'Support IOP3xx AAU RAID Acceleration (EXPERIMENTAL)' CONFIG_IOP3XX_AAU + endmenu +fi + +if [ "$CONFIG_ARCH_IXP2000" = "y" ]; then + choice 'IXP2000 System Type' \ + "IXDP2400 CONFIG_ARCH_IXDP2400\ + IXDP2800 CONFIG_ARCH_IXDP2800" IXDP2400 + bool 'Workaround for PCI I/O errrata' CONFIG_IXP2000_PCI_IO_ERRATA +fi + +if [ "$CONFIG_ARCH_IXP425" = "y" ]; then + mainmenu_option next_comment + comment 'IXP425 Implementation Options' + comment 'IXP425 Board Types' + bool ' Support for IXDP425 board' CONFIG_ARCH_IXDP425 y + bool ' Support for IXCDP1100 board' CONFIG_ARCH_IXCDP1100 n + bool ' Support for PrPMC1100 board' CONFIG_ARCH_PRPMC1100 n + bool ' Support for ADI Coyote board' CONFIG_ARCH_ADI_COYOTE n + endmenu +fi + mainmenu_option next_comment comment 'CLPS711X/EP721X Implementations' dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X @@ -156,7 +205,6 @@ dep_bool ' GUIDEA07' CONFIG_ARCH_GUIDEA07 $CONFIG_ARCH_CLPS711X dep_bool ' P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X - # XXX Maybe these should indicate register compatibility # instead of being mutually exclusive. if [ "$CONFIG_ARCH_EDB7211" = "y" ]; then @@ -181,6 +229,15 @@ endmenu +if [ "$CONFIG_ARCH_ADIFCC" = "y" ]; then + mainmenu_option next_comment + comment 'ADI FCC Implementation Options' + choice 'ADI FCC System Type' \ + "80200EVB CONFIG_ARCH_ADI_EVB \ + BRH CONFIG_ARCH_BRH" 80200EVB + endmenu +fi + # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -345,7 +402,7 @@ # SA110 if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ - "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_ANAKIN" = "y" ]; then + "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_ANAKIN" = "y" -o ]; then define_bool CONFIG_CPU_SA110 y else if [ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -383,8 +440,21 @@ else define_bool CONFIG_CPU_32v4 n fi +# XScale +if [ "$CONFIG_ARCH_IOP3XX" = "y" -o "$CONFIG_ARCH_ADIFCC" = "y" -o \ + "$CONFIG_ARCH_IXP425" = "y" -o "$CONFIG_ARCH_IXP2000" = "y" ]; then + define_bool CONFIG_CPU_32v5 y + define_bool CONFIG_CPU_XSCALE y + define_bool CONFIG_ARM_THUMB y +fi comment 'Processor Features' +if [ "$CONFIG_CPU_XSCALE" = "y" ]; then + bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER + bool 'Workaround for XScale Cache Errata(see help)' CONFIG_XSCALE_CACHE_ERRATA + bool 'Support for BDI2000 JTAG Debugger' CONFIG_XSCALE_BDI2000 + bool 'Enable d-cache write allocate (x-bit)' CONFIG_XSCALE_XBIT +fi if [ "$CONFIG_CPU_ARM720T" = "y" -o "$CONFIG_CPU_ARM920T" = "y" -o \ "$CONFIG_CPU_ARM922T" = "y" -o "$CONFIG_CPU_ARM926T" = "y" -o \ @@ -420,6 +490,8 @@ define_bool CONFIG_DISCONTIGMEM n fi +bool 'Generate big endian kernel' CONFIG_CPU_BIG_ENDIAN + endmenu mainmenu_option next_comment @@ -428,7 +500,11 @@ # Now handle the bus types if [ "$CONFIG_ARCH_FTVPCI" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ - "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then + "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_IOP3XX" = "y" -o \ + "$CONFIG_ARCH_BRH" = "y" -o \ + "$CONFIG_ARCH_IXP425" = "y" -o \ + "$CONFIG_ARCH_IXP2000" = "y" ]; then define_bool CONFIG_PCI y else if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then @@ -439,6 +515,13 @@ fi fi +if [ "$CONFIG_ARCH_IOP3XX" = "y" -o \ + "$CONFIG_ARCH_BRH" = "y" -o \ + "$CONFIG_ARCH_IXP425" = "y" -o \ + "$CONFIG_ARCH_IXP2000" = "y" ]; then + define_bool CONFIG_PCI_AUTOCONFIG y +fi + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ @@ -459,6 +542,18 @@ define_bool CONFIG_ISA_DMA n fi +if [ "$CONFIG_ADVANCED_OPTIONS" = "y" -a "$CONFIG_CPU_32" = "y" -a \ + "$CONFIG_DISCONTIGMEM" != "y" ]; then + bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL + if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then + hex " Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000 + fi +fi + +if [ "$CONFIG_KERNEL_START_BOOL" != "y" ]; then + define_hex CONFIG_KERNEL_START 0xc0000000 +fi + # Compressed boot loader in ROM. Yes, we really want to ask about # TEXT and BSS so we preserve their values in the config files. bool 'Compressed boot loader in ROM/flash' CONFIG_ZBOOT_ROM @@ -514,7 +609,8 @@ "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" -o \ "$CONFIG_ARCH_P720T" = "y" -o \ - "$CONFIG_ARCH_OMAHA" = "y" ]; then + "$CONFIG_ARCH_OMAHA" = "y" -o \ + "$CONFIG_ARCH_IXDP2800" = "y" ]; then bool 'Timer and CPU usage LEDs' CONFIG_LEDS if [ "$CONFIG_LEDS" = "y" ]; then if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ @@ -524,7 +620,8 @@ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ "$CONFIG_ARCH_P720T" = "y" -o \ - "$CONFIG_ARCH_OMAHA" = "y" ]; then + "$CONFIG_ARCH_OMAHA" = "y" -o \ + "$CONFIG_ARCH_IXDP2800" = "y" ]; then bool ' Timer LED' CONFIG_LEDS_TIMER bool ' CPU usage LED' CONFIG_LEDS_CPU fi @@ -705,7 +802,8 @@ # you know what you are doing and are willing to live without stack traces, you # can get a slightly smaller kernel by setting this option to n, but then RMK # will have to kill you ;). -if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then +if [ "$CONFIG_ARCH_OMAHA" = "y" -o \ + "$CONFIG_ARCH_IOP3XX" = "y" ]; then # # Note: We want all the performance we can get, so this means # we accept the debugging limitations of setting CONFIG_FRAME_POINTER=n diff -Nru a/arch/arm/def-configs/adi_evb b/arch/arm/def-configs/adi_evb --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/adi_evb Thu Dec 4 16:24:26 2003 @@ -0,0 +1,791 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +CONFIG_ARCH_ADIFCC=y +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP1200 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# ADI FCC Implementation Options +# +CONFIG_ARCH_ADI_EVB=y +# CONFIG_ARCH_BRH is not set +CONFIG_XSCALE_PMU_TIMER=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +CONFIG_XSCALE_PMU_TIMER=y +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_PMU is not set +CONFIG_ARM_THUMB=y +# CONFIG_DISCONTIGMEM is not set +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_3G_KERNEL is not set + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/mtdblock1" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +CONFIG_MTD_ADI_EVB=y +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_IXP1200 is not set +# CONFIG_SERIAL_IXP1200_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/def-configs/brh b/arch/arm/def-configs/brh --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/brh Thu Dec 4 16:24:26 2003 @@ -0,0 +1,805 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +CONFIG_ARCH_ADIFCC=y +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP425 is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# ADI FCC Implementation Options +# +# CONFIG_ARCH_ADI_EVB is not set +CONFIG_ARCH_BRH=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_XSCALE_XBIT is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,57600 ip=bootp root=nfs" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IOP3XX is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_IXP425 is not set +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -Nru a/arch/arm/def-configs/coyote b/arch/arm/def-configs/coyote --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/coyote Thu Dec 4 16:24:26 2003 @@ -0,0 +1,803 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +CONFIG_ARCH_IXP425=y +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# IXP425 Implementation Options +# +# CONFIG_ARCH_IXDP425 is not set +# CONFIG_ARCH_IXCDP1100 is not set +# CONFIG_ARCH_PRPMC1100 is not set +CONFIG_ARCH_ADI_COYOTE=y + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_XSCALE_XBIT is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS1,115200 root=/dev/nfs ip=bootp mem=32M@0x00000000" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_LUBBOCK is not set +# CONFIG_MTD_IXP425 is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_NOR_TOTO is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_SPIA is not set +# CONFIG_MTD_NAND_TOTO is not set +# CONFIG_MTD_NAND_AUTCPU12 is not set +# CONFIG_MTD_NAND_EDB7312 is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +CONFIG_HOSTAP=y +# CONFIG_PLX_HERMES is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_HOSTAP_PLX is not set +CONFIG_HOSTAP_PCI=y +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_GUIDE is not set +CONFIG_I2C_IXP425=y +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y +# CONFIG_I2C_DS1307 is not set +CONFIG_PCF8549C_NVRAM=y + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/def-configs/iq31244 b/arch/arm/def-configs/iq31244 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/iq31244 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,875 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_IOP3XX=y +# CONFIG_ARCH_IXP1200 is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP425 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IQ80310 is not set +# CONFIG_ARCH_IQ80321 is not set +CONFIG_ARCH_IQ31244=y +# CONFIG_ARCH_IOP310 is not set +CONFIG_ARCH_IOP321=y + +# +# IOP3xx Chipset Features +# +CONFIG_IOP3XX_AAU=y + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +CONFIG_XSCALE_XBIT=y +# CONFIG_DISCONTIGMEM is not set +# CONFIG_CPU_BIG_ENDIAN is not set + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200 mem=128M@0xa0000000" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +CONFIG_MTD_IOP3XX=y +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_IXP425 is not set +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +CONFIG_MD_RAID5=y +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_IXP1200 is not set +# CONFIG_SERIAL_IXP1200_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91US3 is not set +# CONFIG_SERIAL_AT91US3_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/iq80310 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,970 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_IOP3XX=y +# CONFIG_ARCH_IXP425 is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set + +# +# IOP3xx Implementation Options +# +CONFIG_ARCH_IQ80310=y +# CONFIG_ARCH_IQ80321 is not set +# CONFIG_ARCH_IQ31244 is not set +CONFIG_ARCH_IOP310=y +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# +CONFIG_IOP3XX_AAU=y +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +# CONFIG_CPU_BIG_ENDIAN is not set + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +CONFIG_MTD_IOP3XX=y +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_IXP425 is not set +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_ADMA100 is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC79XX is not set +CONFIG_SCSI_AIC7XXX_OLD=y +# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=127 +# CONFIG_AIC7XXX_OLD_PROC_STATS is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO 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_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/def-configs/iq80321 b/arch/arm/def-configs/iq80321 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/iq80321 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,900 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_IOP3XX=y +# CONFIG_ARCH_IXP425 is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IQ80310 is not set +CONFIG_ARCH_IQ80321=y +# CONFIG_ARCH_IQ31244 is not set +# CONFIG_ARCH_IOP310 is not set +CONFIG_ARCH_IOP321=y + +# +# IOP3xx Chipset Features +# +CONFIG_IOP3XX_AAU=y +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +CONFIG_XSCALE_XBIT=y +# CONFIG_DISCONTIGMEM is not set +# CONFIG_CPU_BIG_ENDIAN is not set + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200 mem=128M@0xa0000000" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +CONFIG_MTD_IOP3XX=y +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_IXP425 is not set +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_STATS=y + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +CONFIG_MD_RAID5=y +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_ADMA100 is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/def-configs/ixdp2400 b/arch/arm/def-configs/ixdp2400 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/ixdp2400 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,814 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_ADVANCED_OPTIONS=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP425 is not set +CONFIG_ARCH_IXP2000=y +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set +CONFIG_ARCH_IXDP2400=y +# CONFIG_ARCH_IXDP2800 is not set +CONFIG_IXP2000_PCI_IO_ERRATA=y + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START_BOOL=y +CONFIG_KERNEL_START=80000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,57600 root=nfs ip=bootp" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IOP3XX is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_IXP425 is not set +CONFIG_MTD_IXP2000=y +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_IXP2000_SLAVE=y + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_GUIDE is not set +# CONFIG_I2C_IXP2000 is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y +# CONFIG_I2C_DS1307 is not set +# CONFIG_PCF8549C_NVRAM is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/def-configs/ixdp2800 b/arch/arm/def-configs/ixdp2800 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/ixdp2800 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,713 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_ADVANCED_OPTIONS=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP425 is not set +CONFIG_ARCH_IXP2000=y +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set +# CONFIG_ARCH_IXDP2400 is not set +CONFIG_ARCH_IXDP2800=y +# CONFIG_IXP2000_PCI_IO_ERRATA is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START_BOOL=y +CONFIG_KERNEL_START=80000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0 ip=bootp root=nfs nohalt" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -Nru a/arch/arm/def-configs/ixdp425 b/arch/arm/def-configs/ixdp425 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/ixdp425 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,795 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP1200 is not set +# CONFIG_ARCH_IXP2000 is not set +CONFIG_ARCH_IXP425=y +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# IXP425 Implementation Options +# + +# +# IXP425 Board Types +# +CONFIG_ARCH_IXDP425=y +# CONFIG_ARCH_IXCDP1100 is not set +# CONFIG_ARCH_PRPMC1100 is not set + +# +# IXP425 Options +# +CONFIG_IXP425_PCI_ERRATA=y +# CONFIG_XSCALE_PMU_TIMER is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y + +# +# Processor Features +# +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=256M@0x00000000" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IOP3XX is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +CONFIG_MTD_IXP425=y +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_IXP1200 is not set +# CONFIG_SERIAL_IXP1200_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91US3 is not set +# CONFIG_SERIAL_AT91US3_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_GUIDE is not set +CONFIG_I2C_IXP425=y +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y +# CONFIG_I2C_DS1307 is not set +CONFIG_PCF8549C_NVRAM=y + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/def-configs/ixm1200 b/arch/arm/def-configs/ixm1200 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/ixm1200 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,682 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +CONFIG_ARCH_IXP1200=y +# CONFIG_ARCH_IXP425 is not set +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# IXP1200 Implementation Options +# +CONFIG_IXP1200_SDRAM_BASE=c0000000 +CONFIG_IXP1200_SDRAM_SIZE=128 + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +CONFIG_CPU_SA110=y +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set + +# +# Processor Features +# +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="ip=bootp ixphost console=ttyIXP0,38400" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +CONFIG_SERIAL_IXP1200=y +CONFIG_SERIAL_IXP1200_CONSOLE=y +CONFIG_IXP1200_DEFAULT_BAUDRATE=38400 +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/def-configs/ixp12eb b/arch/arm/def-configs/ixp12eb --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/ixp12eb Thu Dec 4 16:24:26 2003 @@ -0,0 +1,741 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_IXP1200=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# IXP12xx Implementation Options +# +CONFIG_ARCH_IXP12EB=y +# CONFIG_ARCH_IXM1200 is not set +CONFIG_IXP1200_SDRAM_BASE=c0000000 +CONFIG_IXP1200_SDRAM_SIZE=32 + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +CONFIG_CPU_SA110=y +# CONFIG_CPU_SA1100 is not set +# CONFIG_ARM_THUMB is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="ip=bootp rw" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +CONFIG_SERIAL_IXP1200=y +CONFIG_SERIAL_IXP1200_CONSOLE=y +CONFIG_IXP1200_DEFAULT_BAUDRATE=9600 +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/def-configs/prpmc1100 b/arch/arm/def-configs/prpmc1100 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/def-configs/prpmc1100 Thu Dec 4 16:24:26 2003 @@ -0,0 +1,748 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP1200 is not set +# CONFIG_ARCH_IXP2000 is not set +CONFIG_ARCH_IXP425=y +# CONFIG_ARCH_OMAHA is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# IXP425 Implementation Options +# +CONFIG_ARCH_IXDP425=y +CONFIG_ARCH_IXCDP1100=y +CONFIG_ARCH_PRPMC1100=y +CONFIG_IXP425_PCI_ERRATA=y +# CONFIG_XSCALE_PMU_TIMER is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=256M@0x00000000" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_IQ80321 is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_BRH is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +CONFIG_MTD_IXP425=y +# CONFIG_MTD_IXP2000 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_IXP1200 is not set +# CONFIG_SERIAL_IXP1200_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91US3 is not set +# CONFIG_SERIAL_AT91US3_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_IXP2000_SLAVE is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_GUIDE is not set +CONFIG_I2C_IXP425=y +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y +# CONFIG_I2C_DS1307 is not set +CONFIG_PCF8549C_NVRAM=y + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -Nru a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile --- a/arch/arm/kernel/Makefile Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/Makefile Thu Dec 4 16:24:25 2003 @@ -24,6 +24,7 @@ pci-footbridge = dec21285.o pci-shark = via82c505.o + # this is here to allow us to eventually move it out to mach-ftvpci pci-$(CONFIG_ARCH_FTVPCI) += ftv-pci.o @@ -44,8 +45,10 @@ no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \ - $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \ - $(CONFIG_ARCH_AT91RM9200) + $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_IXP1200) \ + $(CONFIG_ARCH_IOP3XX) $(CONFIG_ARCH_ADIFCC) \ + $(CONFIG_ARCH_OMAHA) $(CONFIG_ARCH_IXP425) \ + $(CONFIG_ARCH_IXP2000) $(CONFIG_ARCH_AT91RM9200) ifneq ($(findstring y,$(no-irq-arch)),y) obj-y += irq-arch.o @@ -59,6 +62,12 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y) + +obj-$(CONFIG_XSCALE_PMU_TIMER) += xscale-time.o +obj-$(CONFIG_XSCALE_PMU) += xscale-pmu.o + +obj-$(CONFIG_XSCALE_PMU_TIMER) += xscale-time.o +obj-$(CONFIG_XSCALE_PMU) += xscale-pmu.o ifneq ($(MACHINE),ebsa110) obj-y += io.o diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c --- a/arch/arm/kernel/armksyms.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/armksyms.c Thu Dec 4 16:24:25 2003 @@ -240,14 +240,25 @@ EXPORT_SYMBOL_NOVERS(abort); /* bitops */ -EXPORT_SYMBOL(set_bit); -EXPORT_SYMBOL(test_and_set_bit); -EXPORT_SYMBOL(clear_bit); -EXPORT_SYMBOL(test_and_clear_bit); -EXPORT_SYMBOL(change_bit); -EXPORT_SYMBOL(test_and_change_bit); -EXPORT_SYMBOL(find_first_zero_bit); -EXPORT_SYMBOL(find_next_zero_bit); +EXPORT_SYMBOL(_set_bit_le); +EXPORT_SYMBOL(_test_and_set_bit_le); +EXPORT_SYMBOL(_clear_bit_le); +EXPORT_SYMBOL(_test_and_clear_bit_le); +EXPORT_SYMBOL(_change_bit_le); +EXPORT_SYMBOL(_test_and_change_bit_le); +EXPORT_SYMBOL(_find_first_zero_bit_le); +EXPORT_SYMBOL(_find_next_zero_bit_le); + +#ifdef __ARMEB__ +EXPORT_SYMBOL(_set_bit_be); +EXPORT_SYMBOL(_test_and_set_bit_be); +EXPORT_SYMBOL(_clear_bit_be); +EXPORT_SYMBOL(_test_and_clear_bit_be); +EXPORT_SYMBOL(_change_bit_be); +EXPORT_SYMBOL(_test_and_change_bit_be); +EXPORT_SYMBOL(_find_first_zero_bit_be); +EXPORT_SYMBOL(_find_next_zero_bit_be); +#endif /* elf */ EXPORT_SYMBOL(elf_platform); diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c --- a/arch/arm/kernel/bios32.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/bios32.c Thu Dec 4 16:24:25 2003 @@ -19,20 +19,6 @@ static int debug_pci; int have_isa_bridge; -struct pci_sys_data { - /* - * The hardware we are attached to - */ - struct hw_pci *hw; - - unsigned long mem_offset; - - /* - * These are the resources for the root bus. - */ - struct resource *resource[3]; -}; - void pcibios_report_status(u_int status_mask, int warn) { struct pci_dev *dev; @@ -245,7 +231,30 @@ } } + +#ifdef CONFIG_ARCH_IXP1200 +/* Properly setup 32-byte cache line size */ +static void __init pci_fixup_ixp12xx(struct pci_dev *dev) +{ + u8 foo; + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &foo); + + printk("PCI: %s has cache line of %#02x\n", dev->name, foo); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + +} +#endif + + struct pci_fixup pcibios_fixups[] = { +#ifdef CONFIG_ARCH_IXP12xx + { + PCI_FIXUP_FINAL, + PCI_ANY_ID, PCI_ANY_ID, + pci_fixup_ixp12xx + }, +#endif { PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, @@ -456,6 +465,16 @@ extern struct hw_pci ftv_pci; extern struct hw_pci shark_pci; extern struct hw_pci integrator_pci; +extern struct hw_pci ixp1200_pci; +extern struct hw_pci iq80310_pci; +extern struct hw_pci iq80321_pci; +extern struct hw_pci iq31244_pci; +extern struct hw_pci brh_pci; +extern struct hw_pci ixdp425_pci; +extern struct hw_pci coyote_pci; +extern struct hw_pci ixdp2400_pci; +extern struct hw_pci ixdp2800_pci; +extern struct hw_pci prpmc1100_pci; void __init pcibios_init(void) { @@ -505,6 +524,58 @@ break; } #endif +#ifdef CONFIG_ARCH_IXP1200 + if(machine_is_ixp1200()) { + hw = &ixp1200_pci; + break; + } +#endif +#ifdef CONFIG_ARCH_IOP3XX + if(machine_is_iq80310()) { + hw = &iq80310_pci; + break; + } + if(machine_is_iq80321()) { + hw = &iq80321_pci; + break; + } + if(machine_is_iq31244()) { + hw = &iq31244_pci; + break; + } +#endif +#ifdef CONFIG_ARCH_BRH + if (machine_is_brh()) { + hw = &brh_pci; + break; + } +#endif +#ifdef CONFIG_ARCH_IXP425 + if (machine_is_ixdp425()) { + hw = &ixdp425_pci; + break; + } + if (machine_is_prpmc1100()) { + hw = &prpmc1100_pci; + break; + } + if (machine_is_adi_coyote()) { + hw = &coyote_pci; + break; + } +#endif +#ifdef CONFIG_ARCH_IXDP2400 + if (machine_is_ixdp2400()) { + hw = &ixdp2400_pci; + break; + } +#endif +#ifdef CONFIG_ARCH_IXDP2800 + if (machine_is_ixdp2800()) { + hw = &ixdp2800_pci; + break; + } +#endif } while (0); if (hw == NULL) @@ -541,7 +612,12 @@ /* * Assign any unassigned resources. */ + + // TODO: Make PCI_AUTO go away +#ifndef CONFIG_PCI_AUTOCONFIG pci_assign_unassigned_resources(); +#endif + pci_fixup_irqs(root->hw->swizzle, root->hw->map_irq); } diff -Nru a/arch/arm/kernel/debug-armv.S b/arch/arm/kernel/debug-armv.S --- a/arch/arm/kernel/debug-armv.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/kernel/debug-armv.S Thu Dec 4 16:24:26 2003 @@ -435,6 +435,180 @@ bne 1001b .endm +#elif defined(CONFIG_ARCH_IXP1200) + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x90000000 @ physical base address + movne \rx, #0xf0000000 @ virtual address + add \rx, \rx, #0x00003000 @ + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0xc00] @ UARTDR + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x400] @ UARTFLG + tst \rd, #1 << 2 @ loop until set + beq 1001b + .endm + + .macro waituart,rd,rx + .endm + +#elif defined(CONFIG_ARCH_IOP3XX) + + .macro addruart,rx + mov \rx, #0xfe000000 +#ifdef CONFIG_ARCH_IQ80310) + orr \rx, \rx, #0x00810000 +#elif defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244) + orr \rx, \rx, #0x00800000 +#else +#error Unknown IOP3XX implementation +#endif + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx + .endm + +#elif defined(CONFIG_ARCH_ADI_EVB) + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + mov \rx, #0x00400000 @ physical base address + orrne \rx, \rx, #0xff000000 @ virtual base + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b + .endm + +#elif defined(CONFIG_ARCH_ADIFCC) + +#ifdef CONFIG_ARCH_ADI_EVB + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + mov \rx, #0x00400000 @ physical base address + orrne \rx, #0xff000000 @ virtual base + .endm +#elif defined(CONFIG_ARCH_BRH) + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x03000000 @ physical base address + movne \rx, #0xff000000 @ virtual base + .endm +#endif + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b + .endm + +#elif defined(CONFIG_ARCH_IXP2000) + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0xc0000000 @ Physical base + addeq \rx, \rx, #0x00030000 + movne \rx, #0xfa000000 @ virtual base + addne \rx, \rx, #0x00ff0000 + addne \rx, \rx, #0x0000b000 +#ifdef __ARMEB__ + orr \rx, \rx, #0x00000003 +#endif + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + tst \rd, #0x60 + beq 1002b + .endm + + .macro waituart,rd,rx + nop + nop + nop + .endm + + +#elif defined(CONFIG_ARCH_IXP425) + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0xc8000000 @ Physical + movne \rx, #0xff000000 @ Virtual + orrne \rx, \rx, #0x00fd0000 + orrne \rx, \rx, #0x00002000 +#ifdef __ARMEB__ + add \rx,\rx,#3 +#endif + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 @ check THRE and TEMT bits + teq \rd, #0x60 + beq 1002b + .endm + + .macro waituart,rd,rx + nop + nop + nop + .endm + #elif defined(CONFIG_ARCH_MX1ADS) .macro addruart,rx @@ -467,7 +641,6 @@ tst \rd, #1 << 3 @ TXDC beq 1002b @ wait until transmit done .endm - #else diff -Nru a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c --- a/arch/arm/kernel/dma.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/dma.c Thu Dec 4 16:24:25 2003 @@ -18,6 +18,7 @@ #include #include +#include #include #include diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/entry-armv.S Thu Dec 4 16:24:25 2003 @@ -615,6 +615,365 @@ .text .endm +#elif defined(CONFIG_ARCH_IXP1200) + +#include + + .macro disable_fiq + .endm + + .equ irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000 + .equ irq_mask_pci_err_low, IRQ_MASK_PCI_ERR & 0x00ffffff + .equ arm_csr_base_3, ARM_CSR_BASE & 0xff000000 + .equ arm_csr_base_2, ARM_CSR_BASE & 0x00ff0000 + .equ arm_csr_base_1, ARM_CSR_BASE & 0x0000ff00 + .equ pci_csr_base_3, PCI_CSR_BASE & 0xff000000 + .equ pci_csr_base_2, PCI_CSR_BASE & 0x00ff0000 + .equ pci_csr_base_1, PCI_CSR_BASE & 0x0000ff00 + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mov r4, #arm_csr_base_3 + orr r4, r4, #arm_csr_base_2 + orr r4, r4, #arm_csr_base_1 + add r4, r4, #CSR_ARM_IRQ + ldr \irqstat, [r4] @ get interrupts + tst \irqstat, #IXP1200_IRQS @ check for interrupts + beq 1001f + + tst \irqstat, #IRQ_MASK_UENG + movne \irqnr, #IXP1200_IRQ_UENG + bne 1001f + + tst \irqstat, #IRQ_MASK_CINT + movne \irqnr, #IXP1200_IRQ_CINT + bne 1001f + + tst \irqstat, #IRQ_MASK_SRAM + movne \irqnr, #IXP1200_IRQ_SRAM + bne 1001f + + tst \irqstat, #IRQ_MASK_SDRAM + movne \irqnr, #IXP1200_IRQ_SDRAM + bne 1001f + + tst \irqstat, #IRQ_MASK_UART + movne \irqnr, #IXP1200_IRQ_UART + bne 1001f + + tst \irqstat, #IRQ_MASK_RTC + movne \irqnr, #IXP1200_IRQ_RTC + bne 1001f + + @ Check for an ints from PCI register + + tst \irqstat, #IRQ_MASK_PCI_INTS + beq 1001f + + mov r4, #pci_csr_base_3 + orr r4, r4, #pci_csr_base_2 + orr r4, r4, #pci_csr_base_1 + add r4, r4, #CSR_IRQ_STATUS + ldr \irqstat, [r4] @ get pci interrupts + + tst \irqstat, #IRQ_MASK_DMA1 + movne \irqnr, #IXP1200_IRQ_DMA1 + bne 1001f + + tst \irqstat, #IRQ_MASK_DMA2 + movne \irqnr, #IXP1200_IRQ_DMA2 + bne 1001f + + tst \irqstat, #IRQ_MASK_DMA1NB + movne \irqnr, #IXP1200_IRQ_DMA1NB + bne 1001f + + tst \irqstat, #IRQ_MASK_DMA2NB + movne \irqnr, #IXP1200_IRQ_DMA2NB + bne 1001f + + tst \irqstat, #IRQ_MASK_PCI + movne \irqnr, #IXP1200_IRQ_PCI + bne 1001f + + tst \irqstat, #IRQ_MASK_I2O + movne \irqnr, #IXP1200_IRQ_I2O + bne 1001f + + tst \irqstat, #IRQ_MASK_DOORBELL + movne \irqnr, #IXP1200_IRQ_DOORBELL + + tst \irqstat, #IRQ_MASK_TIMER1 + movne \irqnr, #IXP1200_IRQ_TIMER1 + bne 1001f + + tst \irqstat, #IRQ_MASK_TIMER2 + movne \irqnr, #IXP1200_IRQ_TIMER2 + bne 1001f + + tst \irqstat, #IRQ_MASK_TIMER3 + movne \irqnr, #IXP1200_IRQ_TIMER3 + bne 1001f + + tst \irqstat, #IRQ_MASK_TIMER4 + movne \irqnr, #IXP1200_IRQ_TIMER4 + bne 1001f + + tst \irqstat, #IRQ_MASK_SWI + movne \irqnr, #IXP1200_IRQ_SWI + bne 1001f + + tst \irqstat, #IRQ_MASK_BIST + movne \irqnr, #IXP1200_IRQ_BIST + bne 1001f + + tst \irqstat, #IRQ_MASK_PWRM + movne \irqnr, #IXP1200_IRQ_PWRM + bne 1001f + + tst \irqstat, #irq_mask_pci_err_high + tsteq \irqstat, #irq_mask_pci_err_low + movne \irqnr, #IXP1200_IRQ_PCI_ERR + bne 1001f + +1001: + .endm + + .macro irq_prio_table + .endm + +#elif defined(CONFIG_ARCH_IOP310) || defined(CONFIG_ARCH_ADIFCC) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mrc p13, 0, \irqstat, c4, c0, 0 @ get INTSRC + mrc p13, 0, \base, c0, c0, 0 @ get INTCTL + + tst \irqstat, #(1<<29) @ if INTSRC_BI + tstne \base, #(1<<3) @ and INTCTL_BM + movne \irqnr, #IRQ_XS80200_BCU + bne 1001f + + tst \irqstat, #(1<<28) @ if INTSRC_PI + tstne \base, #(1<<2) @ and INTCTL_PM + movne \irqnr, #IRQ_XS80200_PMU + bne 1001f + + tst \irqstat, #(1<<31) @ if INTSRC_FI + tstne \base, #(1<<0) @ and INTCTL_FM + movne \irqnr, #IRQ_XS80200_EXTFIQ + bne 1001f + + tst \irqstat, #(1<<30) @ if INTSRC_II + tstne \base, #(1<<1) @ and INTCTL_IM + movne \irqnr, #IRQ_XS80200_EXTIRQ +1001: + .endm + + .macro irq_prio_table + .endm + +#elif defined(CONFIG_ARCH_IOP321) + .macro disable_fiq + .endm + + /* + * Note: only deal with normal interrupts, not FIQ + */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov \irqnr, #0 + mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC + cmp \irqstat, #0 + beq 1001f + clz \irqnr, \irqstat + mov \base, #31 + subs \irqnr,\base,\irqnr + add \irqnr,\irqnr,#IRQ_IOP321_DMA0_EOT +1001: + .endm + + .macro irq_prio_table + .endm + +#elif defined(CONFIG_ARCH_IXP2000) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mov \irqnr, #0x0 @clear out irqnr as default + mov \base, #0xfa000000 + orr \base, \base, #0x00ff0000 + orr \base, \base, #0x0000d000 + orr \base, \base, #0x08 + ldr \irqstat, [\base] @ get interrupts + + mov \tmp, #(1<<4) @#IRQ_MASK_TIMER1 + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_TIMER1 + bne 1001f + + mov \tmp, #(1<<0) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_SWI + bne 1001f + + mov \tmp, #(1<<1) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_ERRSUM + bne 1001f + + mov \tmp, #(1<<2) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_UART + bne 1001f + + mov \tmp, #(1<<3) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_GPIO + bne 1001f + + mov \tmp, #(1<<5) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_TIMER2 + bne 1001f + + mov \tmp, #(1<<6) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_TIMER3 + bne 1001f + + mov \tmp, #(1<<7) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_TIMER4 + bne 1001f + + mov \tmp, #(1<<8) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_PMU + bne 1001f + + mov \tmp, #(1<<9) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_SPF + bne 1001f + + mov \tmp, #(1<<10) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_DMA1 + bne 1001f + + mov \tmp, #(1<<11) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_DMA2 + bne 1001f + + mov \tmp, #(1<<12) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_DMA3 + bne 1001f + + mov \tmp, #(1<<13) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_PCI_DOORBELL + bne 1001f + + mov \tmp, #(1<<14) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_ME_ATTN + bne 1001f + + mov \tmp, #(1<<15) + tst \irqstat, \tmp + beq 999f + + mov \base, #0xfa000000 + orr \base, \base, #0x00ff0000 + orr \base, \base, #0x0000f100 + orr \base, \base, #0x00000058 + ldr \irqstat, [\base] + + mov \tmp, #(1<<26) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_PCIA + bne 1001f + + mov \tmp, #(1<<27) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_PCIB + moveq \irqnr, #IRQ_IXP2000_PCI + b 1001f + +999: mov \tmp, #(1<<16) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDA0 + bne 1001f + + mov \tmp, #(1<<17) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDA1 + bne 1001f + + mov \tmp, #(1<<18) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDA2 + bne 1001f + + mov \tmp, #(1<<19) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDA3 + bne 1001f + + mov \tmp, #(1<<24) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDB0 + bne 1001f + + mov \tmp, #(1<<25) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDB1 + bne 1001f + + mov \tmp, #(1<<26) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDB2 + bne 1001f + + mov \tmp, #(1<<27) + tst \irqstat, \tmp + movne \irqnr, #IRQ_IXP2000_THDB3 + bne 1001f + +1001: + .endm + + .macro irq_prio_table + .endm + +#elif defined (CONFIG_ARCH_IXP425) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =(IXP425_INTC_BASE_VIRT+IXP425_ICIP_OFFSET) + ldr \irqstat, [\irqstat] @ get interrupts + mov \irqnr, #0 +1001: tst \irqstat, #1 + addeq \irqnr, \irqnr, #1 + moveq \irqstat, \irqstat, lsr #1 + tsteq \irqnr, #32 + beq 1001b + teq \irqnr, #32 + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif @@ -728,10 +1087,8 @@ add r5, sp, #S_FRAME_SIZE add r4, sp, #S_SP stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro - adrsvc al, r9, 1f @ r9 = normal FP return bl call_fpe @ lr = undefined instr return - mov r0, r5 @ unsigned long pc mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) @@ -885,6 +1242,7 @@ .text /* * Register switch for ARMv3 and ARMv4 processors + * Save DSP (CP0) state on XScale CPUs * r0 = previous, r1 = next, return previous. * previous and next are guaranteed not to be the same. */ @@ -892,9 +1250,17 @@ stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr str ip, [sp, #-4]! @ Save cpsr_SVC +#ifdef CONFIG_CPU_XSCALE + mra r4, r5, acc0 + stmfd sp!, {r4, r5} +#endif str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC ldr r2, [r1, #TSS_DOMAIN] +#ifdef CONFIG_CPU_XSCALE + ldmfd sp!, {r4, r5} + mar acc0, r4, r5 +#endif ldr ip, [sp], #4 mcr p15, 0, r2, c3, c0 @ Set domain register msr spsr, ip @ Save tasks CPSR into SPSR for this return @@ -1145,6 +1511,9 @@ str r3, [r2], #4 cmp r0, r1 blt 1b +#ifdef CONFIG_XSCALE_BDI2000 + bkpt #1 +#endif LOADREGS(fd, sp!, {r4 - r6, pc}) .data diff -Nru a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S --- a/arch/arm/kernel/entry-common.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/kernel/entry-common.S Thu Dec 4 16:24:26 2003 @@ -128,6 +128,7 @@ .align 5 ENTRY(vector_swi) + save_user_regs zero_fp get_scno diff -Nru a/arch/arm/kernel/head-armv.S b/arch/arm/kernel/head-armv.S --- a/arch/arm/kernel/head-armv.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/kernel/head-armv.S Thu Dec 4 16:24:26 2003 @@ -129,6 +129,8 @@ * FIXME - No bootloader, so manually set 'r1' with our architecture number. */ mov r1, #MACH_TYPE_L7200 +#elif defined(CONFIG_ARCH_IXP1200) + mov r1, #MACH_TYPE_IXP1200 #endif mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode @@ -254,6 +256,7 @@ add r3, r3, #1 << 20 str r3, [r0], #4 @ KERNEL + 3MB +#ifndef CONFIG_ARCH_IXP1200 /* * Ensure that the first section of RAM is present. * we assume that: @@ -265,7 +268,7 @@ and r2, r5, #0xfe000000 @ round down add r3, r8, r2 @ flags + rambase str r3, [r0] - +#endif bic r8, r8, #0x0c @ turn off cacheable @ and bufferable bits #ifdef CONFIG_DEBUG_LL diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c --- a/arch/arm/kernel/time.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/kernel/time.c Thu Dec 4 16:24:25 2003 @@ -136,7 +136,7 @@ #endif #ifdef CONFIG_LEDS_TIMER -static void do_leds(void) +void do_leds(void) { static unsigned int count = 50; diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c --- a/arch/arm/kernel/traps.c Thu Dec 4 16:24:26 2003 +++ b/arch/arm/kernel/traps.c Thu Dec 4 16:24:26 2003 @@ -29,6 +29,7 @@ #include #include #include +#include #include "ptrace.h" @@ -199,6 +200,13 @@ dump_instr(regs); } +#ifdef CONFIG_KGDB + /* REVISIT: I'm not sure where to place this call to do_kgdb. So it's here for now... */ + if (kgdb_active()) { + do_kgdb(regs, SIGKILL); /* SIGKILL sure seems appropriate here. : ) */ + } +#endif + spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -223,6 +231,18 @@ regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; pc = (unsigned long *)instruction_pointer(regs); +#ifdef CONFIG_KGDB + /* + * If we're not in user mode, we must have hit a breakpoint + * (or something * else has gone terribly wrong). + * So check in with do_kgdb... + */ + if (!user_mode(regs) && kgdb_active()) { + do_kgdb(regs, SIGTRAP); + return; + } +#endif + #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", current->comm, current->pid, pc); @@ -239,6 +259,7 @@ force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops - undefined instruction", regs, mode); } @@ -252,6 +273,12 @@ current->comm, current->pid, instruction_pointer(regs)); dump_instr(regs); #endif +#ifdef CONFIG_KGDB + /* REVISIT: We don't need this since we only support CONFIG_CPU_32 case. */ + if (!user_mode(regs) && kgdb_active()) { + do_kgdb(regs, SIGBUS); + } +#endif current->thread.error_code = 0; current->thread.trap_no = 11; @@ -287,7 +314,7 @@ console_verbose(); - printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", + printk("Bad mode in %s handler detected: mode %s\n", handler[reason], processor_modes[proc_mode]); /* @@ -348,6 +375,11 @@ switch (no & 0xffff) { case 0: /* branch through 0 */ +#ifdef CONFIG_KGDB + if (!user_mode(regs) && kgdb_active()) { + do_kgdb(regs, -1); + } +#endif info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; @@ -422,6 +454,11 @@ c_backtrace(regs->ARM_fp, processor_mode(regs)); } #endif +#ifdef CONFIG_KGDB + if (!user_mode(regs) && kgdb_active()) { + do_kgdb(regs, SIGILL); + } +#endif info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLTRP; @@ -456,6 +493,11 @@ dump_instr(regs); show_pte(current->mm, addr); #endif +#ifdef CONFIG_KGDB + if (!user_mode(regs) && kgdb_active()) { + do_kgdb(regs, SIGILL); + } +#endif info.si_signo = SIGILL; info.si_errno = 0; @@ -510,6 +552,17 @@ panic("Oops failed to kill thread"); } +#ifdef CONFIG_KGDB +static int kgdb_halt = 1; + +void __init nohalt_setup(char *line) +{ + kgdb_halt = 0; +} + +__setup("nohalt", nohalt_setup); +#endif + void __init trap_init(void) { extern void __trap_init(unsigned long); @@ -521,5 +574,14 @@ base); #ifdef CONFIG_CPU_32 modify_domain(DOMAIN_USER, DOMAIN_CLIENT); +#endif + + /* + * This is the earliest we can bkpt for now as we rely on + * undefined instruction trap to hook into KGDB. + */ +#ifdef CONFIG_KGDB + if(kgdb_halt) + breakpoint(); #endif } diff -Nru a/arch/arm/kernel/xscale-pmu.c b/arch/arm/kernel/xscale-pmu.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/kernel/xscale-pmu.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,174 @@ +/* + * pmu.c + * + * This function provides the implementation of the access functions to + * the Performance Monitoring Unit on all CPUs based on the XScale core. + * + * See Documentation/arm/XScale/pmu.txt for example usage + * + * Author: Deepak Saxena + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 SOFTWARE IS PROVIDED ``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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +static atomic_t usage = ATOMIC_INIT(0); +static unsigned long id = 0; +static u32 pmnc; +struct pmu_results results; + +#define PMU_ENABLE 0x001 /* Enable counters */ +#define PMN_RESET 0x002 /* Reset event counters */ +#define CCNT_RESET 0x004 /* Reset clock counter */ +#define PMU_RESET CCNT_RESET | PMN_RESET +#define CLK_DIV 0x008 /* Clock divide enbable */ +#define INT_ENABLE 0x070 /* Interrupt enable */ + +#define PMN0_OVERFLOW 0x100 /* Perfromance counter 0 overflow */ +#define PMN1_OVERFLOW 0x200 /* Performance counter 1 overflow */ +#define CCNT_OVERFLOW 0x400 /* Clock counter overflow */ + +static void pmu_irq_handler(int, void *, struct pt_regs *); + + +int pmu_claim(void) +{ + int err = 0; + + if(atomic_read(&usage)) + return -EBUSY; + + err = request_irq(XSCALE_PMU_IRQ, pmu_irq_handler, SA_INTERRUPT, + NULL, (void *)&results); + if(err < 0) + { + printk(KERN_ERR "unable to request IRQ %d for 80200 PMU: %d\n", + XSCALE_PMU_IRQ, err); + return err; + } + + atomic_inc(&usage); + pmnc = 0; + asm ("mcr p14, 0, %0, c0, c0, 0" : : "r" (pmnc)); + + return ++id; +} + +int pmu_release(int claim_id) +{ + if(!atomic_read(&usage)) + return 0; + + if(claim_id != id) + return -EPERM; + + free_irq(XSCALE_PMU_IRQ, (void *)&results); + atomic_dec(&usage); + + return 0; +} + +int pmu_start(u32 pmn0, u32 pmn1) +{ + results.ccnt_of = 0; + results.ccnt = 0; + results.pmn0_of = 0; + results.pmn0 = 0; + results.pmn1_of = 0; + results.pmn1 = 0; + + pmnc = (pmn1 << 20) | (pmn0 << 12); + pmnc |= PMU_ENABLE | PMU_RESET | INT_ENABLE; + + asm ("mcr p14, 0, %0, c0, c0, 0" : : "r" (pmnc)); + + /* event 0x5 branch instr exec work around */ + /* fixed in B stepping of the chip */ + /* A stepping requires two writes to pmnc to execute correctly */ + if((pmn0 == 0x5) || (pmn1 == 0x5)) + { + asm ("mcr p14, 0, %0, c0, c0, 0" : : "r" (pmnc)); + } + + return 0; +} + +int pmu_stop(struct pmu_results *results) +{ + u32 ccnt; + u32 pmn0; + u32 pmn1; + + if(!pmnc) + return -ENOSYS; + + asm ("mrc p14, 0, %0, c1, c0, 0" : "=r" (ccnt)); + asm ("mrc p14, 0, %0, c2, c0, 0" : "=r" (pmn0)); + asm ("mrc p14, 0, %0, c3, c0, 0" : "=r" (pmn1)); + + pmnc = 0; + + asm ("mcr p14, 0, %0, c0, c0, 0" : : "r" (pmnc)); + + results->ccnt = ccnt; + results->pmn0 = pmn0; + results->pmn1 = pmn1; + return 0; +} + +static void pmu_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pmu_results *results = (struct pmu_results *)dev_id; + + /* NOTE: there's an A stepping errata that states if an overflow */ + /* bit already exists and another occurs, the previous */ + /* Overflow bit gets cleared. There's no workaround. */ + /* Fixed in B stepping or later */ + + /* read the status */ + asm ("mrc p14, 0, %0, c0, c0, 0" : "=r" (pmnc)); + + if(pmnc & PMN0_OVERFLOW) + { + results->pmn0_of++; + } + + if(pmnc & PMN1_OVERFLOW) + { + results->pmn1_of++; + } + + if(pmnc & CCNT_OVERFLOW) + { + results->ccnt_of++; + } + + asm ("mcr p14, 0, %0, c0, c0, 0" : : "r" (pmnc)); +} + diff -Nru a/arch/arm/kernel/xscale-time.c b/arch/arm/kernel/xscale-time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/kernel/xscale-time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,133 @@ +/* + * linux/arch/arm/kernel/xscale-time.c + * + * This file implements a timer based on the XScale's internal + * performance monitoring clock counter. This code exists for + * boards without external timers to be developed on or during + * early hardware bring up if the external timer does not + * work. To utilize it, CONFIG_XSCALE_PMU_TIMER should be + * set by the configuration scripts. You also need to have + * a #define for IRQ_XSCALE_PMU that maps the PMU interrupt + * on your specific board/processor. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 + +extern int setup_arm_irq(int, struct irqaction *); + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long xscale_pmu_gettimeoffset (void) +{ + unsigned long elapsed, usec; + + /* We need elapsed timer ticks since last interrupt */ + /* + * Read the CCNT value. The returned value is + * between -LATCH and 0, 0 corresponding to a full jiffy + */ + asm volatile ("mrc p14, 0, %0, c1, c0, 0" : "=r" (elapsed)); + elapsed += LATCH; + + /* Now convert them to usec */ + usec = (unsigned long)(elapsed*tick)/LATCH; + + return usec; +} + +static void xscale_pmu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + long cnt; + unsigned long PMNC; + + /* + * The overflow must be cleared before the CCNT + * register is updated to prevent a race condition + * that can cause a lost timer tick. + */ + asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (PMNC)); + /* Enable CCNT overflow interrupt in the PMNC */ + asm volatile ("mcr p14, 0, %0, c0, c0, 0" : : "r" (PMNC & 0x0ffff479)); + + do { + do_timer(regs); + + /* + * Bring the count back for one timer tick. + * To be precise, we need to consider the cycles + * involved in this read-modify-write sequence, as well as + * cache fill operations which can stall the instruction + * pipeline. + */ + asm volatile ( "\ + mcr p15, 0, ip, c7, c10, 4 @ Flush the write (& read) buffers\n\ + b 1f\n\ + .align 5 @ Align code on a cache line boundary\n\ +1: mrc p14, 0, %0, c1, c0, 0\n\ + sub %0, %0, %1\n\ + mcr p14, 0, %0, c1, c0, 0" + : "=&r" (cnt) : "r" (LATCH-10)); + } while (cnt >= 0); +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + name: "timer", + handler: xscale_pmu_timer_interrupt, + flags: SA_INTERRUPT +}; + +void __init setup_timer (void) +{ + unsigned long INTSTR; + + gettimeoffset = xscale_pmu_gettimeoffset; + setup_arm_irq(XSCALE_PMU_IRQ, &timer_irq); + + printk("Using XScale PMU as timer source(IRQ %d, %d MHz Clock Tick)\n", + XSCALE_PMU_IRQ, CLOCK_TICK_RATE / 1000000 ); + + /* + * Need to do this b/c going to IDLE mode on XScale causes + * the PMU to idle also, which means we loose the timer tick! + */ + disable_hlt(); + + + if(machine_is_iq80310()) + { + /* Steer PMU int to IRQ */ + asm volatile("mrc p13, 0, %0, c8, c0, 0" : "=r" (INTSTR)); + /* Clear write-as-zero bits 31:2 and PMU steering bit 0 */ + asm volatile ("mcr p13, 0, %0, c8, c0, 0" : : "r" (INTSTR & 2)); + } + + /* set the initial CCNT value */ + asm volatile ("mcr p14, 0, %0, c1, c0, 0" : : "r" (-LATCH)); + + /* enable interrupt to occur on CCNT wraps in the PMNC */ + asm volatile ("mcr p14, 0, %0, c0, c0, 0" : : "r" (0x0ffff443)); +} diff -Nru a/arch/arm/lib/changebit.S b/arch/arm/lib/changebit.S --- a/arch/arm/lib/changebit.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/changebit.S Thu Dec 4 16:24:25 2003 @@ -14,7 +14,10 @@ /* Purpose : Function to change a bit * Prototype: int change_bit(int bit, void *addr) */ -ENTRY(change_bit) + +ENTRY(_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_change_bit_le) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 diff -Nru a/arch/arm/lib/clearbit.S b/arch/arm/lib/clearbit.S --- a/arch/arm/lib/clearbit.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/clearbit.S Thu Dec 4 16:24:26 2003 @@ -16,7 +16,9 @@ * Prototype: int clear_bit(int bit, void *addr) */ -ENTRY(clear_bit) +ENTRY(_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_clear_bit_le) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 diff -Nru a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S --- a/arch/arm/lib/csumpartial.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/csumpartial.S Thu Dec 4 16:24:26 2003 @@ -41,7 +41,7 @@ tst buf, #1 @ odd address? ldrneb td0, [buf], #1 subne len, len, #1 - adcnes sum, sum, td0, lsl #8 + adcnes sum, sum, td0, lsl #byte(1) .less4: tst len, #6 beq .less8_byte @@ -57,7 +57,11 @@ ldrb td0, [buf], #1 ldrb td3, [buf], #1 sub len, len, #2 +#ifndef __ARMEB__ orr td0, td0, td3, lsl #8 +#else + orr td0, td3, td0, lsl #8 +#endif #endif adcs sum, sum, td0 tst len, #6 @@ -65,7 +69,7 @@ .less8_byte: tst len, #1 @ odd number of bytes ldrneb td0, [buf], #1 @ include last byte - adcnes sum, sum, td0 @ update checksum + adcnes sum, sum, td0, lsl #byte(0) @ update checksum .done: adc r0, sum, #0 @ collect up the last carry ldr td0, [sp], #4 @@ -77,7 +81,7 @@ .not_aligned: tst buf, #1 @ odd address ldrneb td0, [buf], #1 @ make even subne len, len, #1 - adcnes sum, sum, td0, lsl #8 @ update checksum + adcnes sum, sum, td0, lsl #byte(1) @ update checksum tst buf, #2 @ 32-bit aligned? #if __LINUX_ARM_ARCH__ >= 4 @@ -88,7 +92,11 @@ ldrneb td0, [buf], #1 ldrneb ip, [buf], #1 subne len, len, #2 +#ifndef __ARMEB__ orrne td0, td0, ip, lsl #8 +#else + orrne td0, ip, td0, lsl #8 +#endif #endif adcnes sum, sum, td0 @ update checksum mov pc, lr diff -Nru a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S --- a/arch/arm/lib/csumpartialcopygeneric.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/csumpartialcopygeneric.S Thu Dec 4 16:24:25 2003 @@ -36,16 +36,16 @@ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst dst, #2 moveq pc, lr @ dst is now 32bit aligned .dst_16bit: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 mov pc, lr @ dst is now 32bit aligned @@ -63,16 +63,16 @@ /* Align dst */ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst len, #6 beq .less8_byteonly 1: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 .less8_aligned: tst len, #6 bne 1b @@ -80,7 +80,7 @@ tst len, #1 beq .done load1b r8 - adcs sum, sum, r8 @ update checksum + adcs sum, sum, r8, lsl #byte(0) @ update checksum strb r8, [dst], #1 b .done @@ -139,16 +139,17 @@ beq .done load1l r4 tst len, #2 + mov r5, r4, lsr #byte(0) beq .exit - adcs sum, sum, r4, lsl #16 - strb r4, [dst], #1 - mov r4, r4, lsr #8 - strb r4, [dst], #1 - mov r4, r4, lsr #8 + adcs sum, sum, r4, push #16 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 + mov r5, r4, lsr #byte(2) .exit: tst len, #1 - strneb r4, [dst], #1 - andne r4, r4, #255 - adcnes sum, sum, r4 + strneb r5, [dst], #1 + andne r5, r5, #255 + adcnes sum, sum, r5, lsl #byte(0) /* * If the dst pointer was not 16-bit aligned, we @@ -167,27 +168,27 @@ adc sum, sum, #0 @ include C from dst alignment and ip, src, #3 bic src, src, #3 - load1l r4 + load1l r5 cmp ip, #2 beq .src2_aligned bhi .src3_aligned - mov r4, r4, lsr #8 @ C = 0 + mov r4, r5, pull #8 @ C = 0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - mov r7, r7, lsr #8 - orr r7, r7, r8, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + mov r7, r7, pull #8 + orr r7, r7, r8, push #24 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #8 + mov r4, r8, pull #8 sub ip, ip, #16 teq ip, #0 bne 1b @@ -196,49 +197,50 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #8 + mov r4, r6, pull #8 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #24 + orr r4, r4, r5, push #24 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #8 + mov r4, r5, pull #8 4: ands len, len, #3 beq .done + mov r5, r4, lsr #byte(0) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 - strb r4, [dst], #1 - mov r4, r4, lsr #8 - strb r4, [dst], #1 - mov r4, r4, lsr #8 + adcs sum, sum, r4, push #16 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 + mov r5, r4, lsr #byte(2) b .exit -.src2_aligned: mov r4, r4, lsr #16 +.src2_aligned: mov r4, r5, pull #16 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 - mov r7, r7, lsr #16 - orr r7, r7, r8, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + mov r7, r7, pull #16 + orr r7, r7, r8, push #16 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #16 + mov r4, r8, pull #16 sub ip, ip, #16 teq ip, #0 bne 1b @@ -247,51 +249,52 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #16 + mov r4, r6, pull #16 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #16 + orr r4, r4, r5, push #16 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #16 + mov r4, r5, pull #16 4: ands len, len, #3 beq .done + mov r5, r4, lsr #byte(0) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 - strb r4, [dst], #1 - mov r4, r4, lsr #8 - strb r4, [dst], #1 + adcs sum, sum, r4 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 tst len, #1 beq .done - load1b r4 + load1b r5 b .exit -.src3_aligned: mov r4, r4, lsr #24 +.src3_aligned: mov r4, r5, pull #24 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - mov r7, r7, lsr #24 - orr r7, r7, r8, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + mov r7, r7, pull #24 + orr r7, r7, r8, push #8 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #24 + mov r4, r8, pull #24 sub ip, ip, #16 teq ip, #0 bne 1b @@ -300,28 +303,30 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #24 + mov r4, r6, pull #24 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #8 + orr r4, r4, r5, push #8 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #24 + mov r4, r5, pull #24 4: ands len, len, #3 beq .done + mov r5, r4, lsr #byte(0) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 - strb r4, [dst], #1 + strb r5, [dst], #1 + adcs sum, sum, r4 load1l r4 - strb r4, [dst], #1 - adcs sum, sum, r4, lsl #24 - mov r4, r4, lsr #8 + mov r5, r4, lsr #byte(0) + strb r5, [dst], #1 + adcs sum, sum, r4, push #24 + mov r5, r4, lsr #byte(1) b .exit diff -Nru a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S --- a/arch/arm/lib/findbit.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/findbit.S Thu Dec 4 16:24:26 2003 @@ -15,14 +15,14 @@ * Purpose : Find a 'zero' bit * Prototype: int find_first_zero_bit(void *addr, int maxbit); */ -ENTRY(find_first_zero_bit) +ENTRY(_find_first_zero_bit_le) mov r2, #0 -.bytelp: ldrb r3, [r0, r2, lsr #3] +1: ldrb r3, [r0, r2, lsr #3] eors r3, r3, #0xff @ invert bits bne .found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer cmp r2, r1 @ any more? - bcc .bytelp + bcc 1b add r0, r1, #1 @ no free bits RETINSTR(mov,pc,lr) @@ -30,15 +30,43 @@ * Purpose : Find next 'zero' bit * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset) */ -ENTRY(find_next_zero_bit) +ENTRY(_find_next_zero_bit_le) ands ip, r2, #7 - beq .bytelp @ If new byte, goto old routine + beq 1b @ If new byte, goto old routine ldrb r3, [r0, r2, lsr#3] eor r3, r3, #0xff @ now looking for a 1 bit movs r3, r3, lsr ip @ shift off unused bits + bne .found + orr r2, r2, #7 @ if zero, then no bits here + add r2, r2, #1 @ align bit pointer + b 1b @ loop for next bit + +#ifdef __ARMEB__ + +ENTRY(_find_first_zero_bit_be) + mov r2, #0 +1: eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] + eors r3, r3, #0xff @ invert bits + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer + cmp r2, r1 @ any more? + bcc 1b + add r0, r1, #1 @ no free bits + RETINSTR(mov,pc,lr) + +ENTRY(_find_next_zero_bit_be) + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr#3] + eor r3, r3, #0xff @ now looking for a 1 bit + movs r3, r3, lsr ip @ shift off unused bits orreq r2, r2, #7 @ if zero, then no bits here addeq r2, r2, #1 @ align bit pointer - beq .bytelp @ loop for next bit + beq 1b @ loop for next bit + +#endif /* * One or more bits in the LSB of r3 are assumed to be set. diff -Nru a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S --- a/arch/arm/lib/getuser.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/getuser.S Thu Dec 4 16:24:25 2003 @@ -42,14 +42,18 @@ .global __get_user_2 __get_user_2: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] - sub r2, r2, #2 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TSK_ADDR_LIMIT] + sub ip, ip, #2 + cmp r0, ip 2: ldrlsbt r1, [r0], #1 -3: ldrlsbt r2, [r0] - orrls r1, r1, r2, lsl #8 +3: ldrlsbt ip, [r0] +#ifndef __ARMEB__ + orrls r1, r1, ip, lsl #8 +#else + orrls r1, ip, r1, lsl #8 +#endif movls r0, #0 movls pc, lr b __get_user_bad diff -Nru a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S --- a/arch/arm/lib/io-readsb.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/io-readsb.S Thu Dec 4 16:24:25 2003 @@ -9,7 +9,6 @@ */ #include #include -#include .insb_align: rsb ip, ip, #4 cmp ip, r2 @@ -30,80 +29,87 @@ ands ip, r1, #3 bne .insb_align -.insb_aligned: stmfd sp!, {r4 - r6, lr} +.insb_aligned: stmfd sp!, {r4, r5, lr} subs r2, r2, #16 bmi .insb_no_16 .insb_16_lp: ldrb r3, [r0] + mov r3, r3, lsl #byte(0) ldrb r4, [r0] - orr r3, r3, r4, lsl #8 + orr r3, r3, r4, lsl #byte(1) ldrb r4, [r0] - orr r3, r3, r4, lsl #16 + orr r3, r3, r4, lsl #byte(2) ldrb r4, [r0] - orr r3, r3, r4, lsl #24 + orr r3, r3, r4, lsl #byte(3) ldrb r4, [r0] + mov r4, r4, lsl #byte(0) ldrb r5, [r0] - orr r4, r4, r5, lsl #8 + orr r4, r4, r5, lsl #byte(1) ldrb r5, [r0] - orr r4, r4, r5, lsl #16 + orr r4, r4, r5, lsl #byte(2) ldrb r5, [r0] - orr r4, r4, r5, lsl #24 + orr r4, r4, r5, lsl #byte(3) ldrb r5, [r0] - ldrb r6, [r0] - orr r5, r5, r6, lsl #8 - ldrb r6, [r0] - orr r5, r5, r6, lsl #16 - ldrb r6, [r0] - orr r5, r5, r6, lsl #24 - ldrb r6, [r0] + mov r5, r5, lsl #byte(0) ldrb ip, [r0] - orr r6, r6, ip, lsl #8 + orr r5, r5, ip, lsl #byte(1) ldrb ip, [r0] - orr r6, r6, ip, lsl #16 + orr r5, r5, ip, lsl #byte(2) ldrb ip, [r0] - orr r6, r6, ip, lsl #24 - stmia r1!, {r3 - r6} + orr r5, r5, ip, lsl #byte(3) + ldrb ip, [r0] + mov ip, ip, lsl #byte(0) + ldrb lr, [r0] + orr ip, ip, lr, lsl #byte(1) + ldrb lr, [r0] + orr ip, ip, lr, lsl #byte(2) + ldrb lr, [r0] + orr ip, ip, lr, lsl #byte(3) + stmia r1!, {r3 - r5, ip} subs r2, r2, #16 bpl .insb_16_lp tst r2, #15 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) + LOADREGS(eqfd, sp!, {r4, r5, pc}) .insb_no_16: tst r2, #8 beq .insb_no_8 ldrb r3, [r0] + mov r3, r3, lsl #byte(0) ldrb r4, [r0] - orr r3, r3, r4, lsl #8 + orr r3, r3, r4, lsl #byte(1) ldrb r4, [r0] - orr r3, r3, r4, lsl #16 + orr r3, r3, r4, lsl #byte(2) ldrb r4, [r0] - orr r3, r3, r4, lsl #24 + orr r3, r3, r4, lsl #byte(3) ldrb r4, [r0] + mov r4, r4, lsl #byte(0) ldrb r5, [r0] - orr r4, r4, r5, lsl #8 + orr r4, r4, r5, lsl #byte(1) ldrb r5, [r0] - orr r4, r4, r5, lsl #16 + orr r4, r4, r5, lsl #byte(2) ldrb r5, [r0] - orr r4, r4, r5, lsl #24 + orr r4, r4, r5, lsl #byte(3) stmia r1!, {r3, r4} .insb_no_8: tst r2, #4 beq .insb_no_4 ldrb r3, [r0] + mov r3, r3, lsl #byte(0) ldrb r4, [r0] - orr r3, r3, r4, lsl #8 + orr r3, r3, r4, lsl #byte(1) ldrb r4, [r0] - orr r3, r3, r4, lsl #16 + orr r3, r3, r4, lsl #byte(2) ldrb r4, [r0] - orr r3, r3, r4, lsl #24 + orr r3, r3, r4, lsl #byte(3) str r3, [r1], #4 .insb_no_4: ands r2, r2, #3 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) + LOADREGS(eqfd, sp!, {r4, r5, pc}) cmp r2, #2 ldrb r3, [r0] @@ -113,4 +119,4 @@ ldrgtb r3, [r0] strgtb r3, [r1] - LOADREGS(fd, sp!, {r4 - r6, pc}) + LOADREGS(fd, sp!, {r4, r5, pc}) diff -Nru a/arch/arm/lib/io-readsl-armv4.S b/arch/arm/lib/io-readsl-armv4.S --- a/arch/arm/lib/io-readsl-armv4.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/io-readsl-armv4.S Thu Dec 4 16:24:26 2003 @@ -9,7 +9,6 @@ */ #include #include -#include /* * Note that some reads can be aligned on half-word boundaries. @@ -31,6 +30,10 @@ blt 4f bgt 6f +#ifndef __ARMEB__ + + /* little endian code */ + strh ip, [r1], #2 mov ip, ip, lsr #16 3: subs r2, r2, #1 @@ -67,4 +70,49 @@ mov ip, ip, lsr #16 strb ip, [r1] mov pc, lr + +#else + + /* big endian code */ + + + mov r3, ip, lsr #16 + strh r3, [r1], #2 +3: mov r3, ip, lsl #16 + subs r2, r2, #1 + ldrne ip, [r0] + orrne r3, r3, ip, lsr #16 + strne r3, [r1], #4 + bne 3b + strh ip, [r1], #2 + mov pc, lr + +4: mov r3, ip, lsr #24 + strb r3, [r1], #1 + mov r3, ip, lsr #8 + strh r3, [r1], #2 +5: mov r3, ip, lsl #24 + subs r2, r2, #1 + ldrne ip, [r0] + orrne r3, r3, ip, lsr #8 + strne r3, [r1], #4 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: mov r3, ip, lsr #24 + strb r3, [r1], #1 +7: mov r3, ip, lsl #8 + subs r2, r2, #1 + ldrne ip, [r0] + orrne r3, r3, ip, lsr #24 + strne r3, [r1], #4 + bne 7b + mov r3, ip, lsr #8 + strh r3, [r1], #2 + strb ip, [r1], #1 + mov pc, lr + +#endif + diff -Nru a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S --- a/arch/arm/lib/io-readsw-armv4.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/io-readsw-armv4.S Thu Dec 4 16:24:26 2003 @@ -9,7 +9,14 @@ */ #include #include -#include + + .macro pack, rd, hw1, hw2 +#ifndef __ARMEB__ + orr \rd, \hw1, \hw2, lsl #16 +#else + orr \rd, \hw2, \hw1, lsl #16 +#endif + .endm .insw_bad_alignment: adr r0, .insw_bad_align_msg @@ -41,19 +48,19 @@ .insw_8_lp: ldrh r3, [r0] ldrh r4, [r0] - orr r3, r3, r4, lsl #16 + pack r3, r3, r4 ldrh r4, [r0] ldrh r5, [r0] - orr r4, r4, r5, lsl #16 + pack r4, r4, r5 ldrh r5, [r0] ldrh ip, [r0] - orr r5, r5, ip, lsl #16 + pack r5, r5, ip ldrh ip, [r0] ldrh lr, [r0] - orr ip, ip, lr, lsl #16 + pack ip, ip, lr stmia r1!, {r3 - r5, ip} @@ -68,11 +75,11 @@ ldrh r3, [r0] ldrh r4, [r0] - orr r3, r3, r4, lsl #16 + pack r3, r3, r4 ldrh r4, [r0] ldrh ip, [r0] - orr r4, r4, ip, lsl #16 + pack r4, r4, ip stmia r1!, {r3, r4} @@ -81,7 +88,7 @@ ldrh r3, [r0] ldrh ip, [r0] - orr r3, r3, ip, lsl #16 + pack r3, r3, ip str r3, [r1], #4 diff -Nru a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S --- a/arch/arm/lib/io-writesb.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/io-writesb.S Thu Dec 4 16:24:25 2003 @@ -9,7 +9,26 @@ */ #include #include -#include + + .macro outword, rd +#ifndef __ARMEB__ + strb \rd, [r0] + mov \rd, \rd, lsr #8 + strb \rd, [r0] + mov \rd, \rd, lsr #8 + strb \rd, [r0] + mov \rd, \rd, lsr #8 + strb \rd, [r0] +#else + mov lr, \rd, lsr #24 + strb lr, [r0] + mov lr, \rd, lsr #16 + strb lr, [r0] + mov lr, \rd, lsr #8 + strb lr, [r0] + strb \rd, [r0] +#endif + .endm .outsb_align: rsb ip, ip, #4 cmp ip, r2 @@ -30,86 +49,37 @@ ands ip, r1, #3 bne .outsb_align -.outsb_aligned: stmfd sp!, {r4 - r6, lr} +.outsb_aligned: stmfd sp!, {r4, r5, lr} subs r2, r2, #16 bmi .outsb_no_16 -.outsb_16_lp: ldmia r1!, {r3 - r6} - - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - +.outsb_16_lp: ldmia r1!, {r3, r4, r5, ip} + outword r3 + outword r4 + outword r5 + outword ip subs r2, r2, #16 bpl .outsb_16_lp tst r2, #15 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) + LOADREGS(eqfd, sp!, {r4, r5, pc}) .outsb_no_16: tst r2, #8 beq .outsb_no_8 ldmia r1!, {r3, r4} - - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] + outword r3 + outword r4 .outsb_no_8: tst r2, #4 beq .outsb_no_4 ldr r3, [r1], #4 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] + outword r3 .outsb_no_4: ands r2, r2, #3 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) + LOADREGS(eqfd, sp!, {r4, r5, pc}) cmp r2, #2 ldrb r3, [r1], #1 @@ -119,4 +89,4 @@ ldrgtb r3, [r1] strgtb r3, [r0] - LOADREGS(fd, sp!, {r4 - r6, pc}) + LOADREGS(fd, sp!, {r4, r5, pc}) diff -Nru a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S --- a/arch/arm/lib/io-writesl.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/io-writesl.S Thu Dec 4 16:24:26 2003 @@ -9,7 +9,6 @@ */ #include #include -#include ENTRY(__raw_writesl) teq r2, #0 @ do we have to check for the zero len? @@ -29,25 +28,25 @@ bgt 4f blt 5f -3: mov ip, r3, lsr #16 +3: mov ip, r3, pull #16 ldr r3, [r1], #4 - orr ip, ip, r3, lsl #16 + orr ip, ip, r3, push #16 str ip, [r0] subs r2, r2, #1 bne 3b mov pc, lr -4: mov ip, r3, lsr #24 +4: mov ip, r3, pull #24 ldr r3, [r1], #4 - orr ip, ip, r3, lsl #8 + orr ip, ip, r3, push #8 str ip, [r0] subs r2, r2, #1 bne 4b mov pc, lr -5: mov ip, r3, lsr #8 +5: mov ip, r3, pull #8 ldr r3, [r1], #4 - orr ip, ip, r3, lsl #24 + orr ip, ip, r3, push #24 str ip, [r0] subs r2, r2, #1 bne 5b diff -Nru a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S --- a/arch/arm/lib/io-writesw-armv4.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/io-writesw-armv4.S Thu Dec 4 16:24:26 2003 @@ -9,7 +9,18 @@ */ #include #include -#include + + .macro outword, rd +#ifndef __ARMEB__ + strh \rd, [r0] + mov \rd, \rd, lsr #16 + strh \rd, [r0] +#else + mov lr, \rd, lsr #16 + strh lr, [r0] + strh \rd, [r0] +#endif + .endm .outsw_bad_alignment: adr r0, .outsw_bad_align_msg @@ -40,20 +51,10 @@ bmi .no_outsw_8 .outsw_8_lp: ldmia r1!, {r3, r4, r5, ip} - - strh r3, [r0] - mov r3, r3, lsr #16 - strh r3, [r0] - strh r4, [r0] - mov r4, r4, lsr #16 - strh r4, [r0] - strh r5, [r0] - mov r5, r5, lsr #16 - strh r5, [r0] - strh ip, [r0] - mov ip, ip, lsr #16 - strh ip, [r0] - + outword r3 + outword r4 + outword r5 + outword ip subs r2, r2, #8 bpl .outsw_8_lp @@ -64,20 +65,14 @@ beq .no_outsw_4 ldmia r1!, {r3, ip} - strh r3, [r0] - mov r3, r3, lsr #16 - strh r3, [r0] - strh ip, [r0] - mov ip, ip, lsr #16 - strh ip, [r0] + outword r3 + outword ip .no_outsw_4: tst r2, #2 beq .no_outsw_2 ldr r3, [r1], #4 - strh r3, [r0] - mov r3, r3, lsr #16 - strh r3, [r0] + outword r3 .no_outsw_2: tst r2, #1 ldrneh r3, [r1] diff -Nru a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S --- a/arch/arm/lib/memcpy.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/memcpy.S Thu Dec 4 16:24:25 2003 @@ -99,24 +99,24 @@ cmp r2, #12 blt 10f sub r2, r2, #12 -9: mov r3, r7, lsr #8 +9: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 9b adds r2, r2, #12 blt 100f -10: mov r3, r7, lsr #8 +10: mov r3, r7, pull #8 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 str r3, [r0], #4 bge 10b 100: sub r1, r1, #3 @@ -125,24 +125,24 @@ 11: cmp r2, #12 blt 13f /* */ sub r2, r2, #12 -12: mov r3, r7, lsr #16 +12: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7,LSL#16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 12b adds r2, r2, #12 blt 14f -13: mov r3, r7, lsr #16 +13: mov r3, r7, pull #16 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 str r3, [r0], #4 bge 13b 14: sub r1, r1, #2 @@ -151,24 +151,24 @@ 15: cmp r2, #12 blt 17f sub r2, r2, #12 -16: mov r3, r7, lsr #24 - ldmia r1!,{r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 +16: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 16b adds r2, r2, #12 blt 18f -17: mov r3, r7, lsr #24 +17: mov r3, r7, pull #24 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl#8 + orr r3, r3, r7, push #8 str r3, [r0], #4 bge 17b 18: sub r1, r1, #1 @@ -240,24 +240,24 @@ cmp r2, #12 blt 28f sub r2, r2, #12 -27: mov r7, r3, lsl #8 +27: mov r7, r3, push #8 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #24 - mov r6, r6, lsl #8 - orr r6, r6, r5, lsr #24 - mov r5, r5, lsl #8 - orr r5, r5, r4, lsr #24 - mov r4, r4, lsl #8 - orr r4, r4, r3, lsr #24 + orr r7, r7, r6, pull #24 + mov r6, r6, push #8 + orr r6, r6, r5, pull #24 + mov r5, r5, push #8 + orr r5, r5, r4, pull #24 + mov r4, r4, push #8 + orr r4, r4, r3, pull #24 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 27b adds r2, r2, #12 blt 29f -28: mov ip, r3, lsl #8 +28: mov ip, r3, push #8 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #24 + orr ip, ip, r3, pull #24 str ip, [r0, #-4]! bge 28b 29: add r1, r1, #3 @@ -266,24 +266,24 @@ 30: cmp r2, #12 blt 32f sub r2, r2, #12 -31: mov r7, r3, lsl #16 +31: mov r7, r3, push #16 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #16 - mov r6, r6, lsl #16 - orr r6, r6, r5, lsr #16 - mov r5, r5, lsl #16 - orr r5, r5, r4, lsr #16 - mov r4, r4, lsl #16 - orr r4, r4, r3, lsr #16 + orr r7, r7, r6, pull #16 + mov r6, r6, push #16 + orr r6, r6, r5, pull #16 + mov r5, r5, push #16 + orr r5, r5, r4, pull #16 + mov r4, r4, push #16 + orr r4, r4, r3, pull #16 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 31b adds r2, r2, #12 blt 33f -32: mov ip, r3, lsl #16 +32: mov ip, r3, push #16 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #16 + orr ip, ip, r3, pull #16 str ip, [r0, #-4]! bge 32b 33: add r1, r1, #2 @@ -292,24 +292,24 @@ 34: cmp r2, #12 blt 36f sub r2, r2, #12 -35: mov r7, r3, lsl #24 +35: mov r7, r3, push #24 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #8 - mov r6, r6, lsl #24 - orr r6, r6, r5, lsr #8 - mov r5, r5, lsl #24 - orr r5, r5, r4, lsr #8 - mov r4, r4, lsl #24 - orr r4, r4, r3, lsr #8 + orr r7, r7, r6, pull #8 + mov r6, r6, push #24 + orr r6, r6, r5, pull #8 + mov r5, r5, push #24 + orr r5, r5, r4, pull #8 + mov r4, r4, push #24 + orr r4, r4, r3, pull #8 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 35b adds r2, r2, #12 blt 37f -36: mov ip, r3, lsl #24 +36: mov ip, r3, push #24 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #8 + orr ip, ip, r3, pull #8 str ip, [r0, #-4]! bge 36b 37: add r1, r1, #1 diff -Nru a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S --- a/arch/arm/lib/putuser.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/putuser.S Thu Dec 4 16:24:25 2003 @@ -18,7 +18,7 @@ * Inputs: r0 contains the address * r1, r2 contains the value * Outputs: r0 is the error code - * lr corrupted + * ip, lr corrupted * * No other registers must be altered. (see include/asm-arm/uaccess.h * for specific ASM register usage). @@ -30,11 +30,11 @@ .global __put_user_1 __put_user_1: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] - sub r2, r2, #1 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TSK_ADDR_LIMIT] + sub ip, ip, #1 + cmp r0, ip 1: strlsbt r1, [r0] movls r0, #0 movls pc, lr @@ -42,25 +42,30 @@ .global __put_user_2 __put_user_2: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] - sub r2, r2, #2 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TSK_ADDR_LIMIT] + sub ip, ip, #2 + cmp r0, ip + movls ip, r1, lsr #8 +#ifndef __ARMEB__ 2: strlsbt r1, [r0], #1 - movls r1, r1, lsr #8 +3: strlsbt ip, [r0] +#else +2: strlsbt ip, [r0], #1 3: strlsbt r1, [r0] +#endif movls r0, #0 movls pc, lr b __put_user_bad .global __put_user_4 __put_user_4: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] - sub r2, r2, #4 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TSK_ADDR_LIMIT] + sub ip, ip, #4 + cmp r0, ip 4: strlst r1, [r0] movls r0, #0 movls pc, lr diff -Nru a/arch/arm/lib/setbit.S b/arch/arm/lib/setbit.S --- a/arch/arm/lib/setbit.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/setbit.S Thu Dec 4 16:24:25 2003 @@ -16,7 +16,9 @@ * Prototype: int set_bit(int bit, void *addr) */ -ENTRY(set_bit) +ENTRY(_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_set_bit_le) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 diff -Nru a/arch/arm/lib/testchangebit.S b/arch/arm/lib/testchangebit.S --- a/arch/arm/lib/testchangebit.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/lib/testchangebit.S Thu Dec 4 16:24:26 2003 @@ -11,7 +11,9 @@ #include .text -ENTRY(test_and_change_bit) +ENTRY(_test_and_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_change_bit_le) add r1, r1, r0, lsr #3 and r3, r0, #7 mov r0, #1 diff -Nru a/arch/arm/lib/testclearbit.S b/arch/arm/lib/testclearbit.S --- a/arch/arm/lib/testclearbit.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/testclearbit.S Thu Dec 4 16:24:25 2003 @@ -11,7 +11,9 @@ #include .text -ENTRY(test_and_clear_bit) +ENTRY(_test_and_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_clear_bit_le) add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #7 @ Get bit offset mov r0, #1 diff -Nru a/arch/arm/lib/testsetbit.S b/arch/arm/lib/testsetbit.S --- a/arch/arm/lib/testsetbit.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/testsetbit.S Thu Dec 4 16:24:25 2003 @@ -11,7 +11,9 @@ #include .text -ENTRY(test_and_set_bit) +ENTRY(_test_and_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_set_bit_le) add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #7 @ Get bit offset mov r0, #1 diff -Nru a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S --- a/arch/arm/lib/uaccess.S Thu Dec 4 16:24:25 2003 +++ b/arch/arm/lib/uaccess.S Thu Dec 4 16:24:25 2003 @@ -115,9 +115,9 @@ .c2u_1fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_1nowords - mov r3, r7, lsr #8 + mov r3, r7, pull #8 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -129,49 +129,49 @@ subs ip, ip, #16 blt .c2u_1rem8lp -.c2u_1cpy8lp: mov r3, r7, lsr #8 +.c2u_1cpy8lp: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_1cpy8lp .c2u_1rem8lp: tst ip, #8 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #24 - movne r4, r4, lsr #8 - orrne r4, r4, r7, lsl #24 + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #24 + orrne r3, r3, r7, push #24 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_1fupi -.c2u_1nowords: mov r3, r7, lsr #8 +.c2u_1nowords: mov r3, r7, lsr #byte(1) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(2) USER( strgebt r3, [r0], #1) @ May fault - movgt r3, r3, lsr #8 + movgt r3, r7, lsr #byte(3) USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_2fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_2nowords - mov r3, r7, lsr #16 + mov r3, r7, pull #16 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -183,38 +183,38 @@ subs ip, ip, #16 blt .c2u_2rem8lp -.c2u_2cpy8lp: mov r3, r7, lsr #16 +.c2u_2cpy8lp: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_2cpy8lp .c2u_2rem8lp: tst ip, #8 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #16 - movne r4, r4, lsr #16 - orrne r4, r4, r7, lsl #16 + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #16 + orrne r3, r3, r7, push #16 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_2fupi -.c2u_2nowords: mov r3, r7, lsr #16 +.c2u_2nowords: mov r3, r7, lsr #byte(2) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(3) USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 USER( strgtbt r3, [r0], #1) @ May fault @@ -223,9 +223,9 @@ .c2u_3fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_3nowords - mov r3, r7, lsr #24 + mov r3, r7, pull #24 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #8 + orr r3, r3, r7, push #8 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -237,40 +237,40 @@ subs ip, ip, #16 blt .c2u_3rem8lp -.c2u_3cpy8lp: mov r3, r7, lsr #24 +.c2u_3cpy8lp: mov r3, r7, pull #24 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_3cpy8lp .c2u_3rem8lp: tst ip, #8 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #8 - movne r4, r4, lsr #24 - orrne r4, r4, r7, lsl #8 + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #8 + orrne r3, r3, r7, push #8 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_3fupi -.c2u_3nowords: mov r3, r7, lsr #24 +.c2u_3nowords: mov r3, r7, lsr #byte(3) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - ldrge r3, [r1], #0 + ldrgeb r3, [r1], #1 USER( strgebt r3, [r0], #1) @ May fault - movgt r3, r3, lsr #8 + ldrgtb r3, [r1], #0 USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished @@ -374,9 +374,9 @@ .cfu_1fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_1nowords - mov r3, r7, lsr #8 + mov r3, r7, pull #8 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -388,49 +388,49 @@ subs ip, ip, #16 blt .cfu_1rem8lp -.cfu_1cpy8lp: mov r3, r7, lsr #8 +.cfu_1cpy8lp: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_1cpy8lp .cfu_1rem8lp: tst ip, #8 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #24 - movne r4, r4, lsr #8 - orrne r4, r4, r7, lsl #24 + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #24 + orrne r3, r3, r7, push #24 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_1fupi -.cfu_1nowords: mov r3, r7, lsr #8 +.cfu_1nowords: mov r3, r7, lsr #byte(1) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(2) strgeb r3, [r0], #1 - movgt r3, r3, lsr #8 + movgt r3, r7, lsr #byte(3) strgtb r3, [r0], #1 b .cfu_finished .cfu_2fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_2nowords - mov r3, r7, lsr #16 + mov r3, r7, pull #16 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -442,38 +442,38 @@ subs ip, ip, #16 blt .cfu_2rem8lp -.cfu_2cpy8lp: mov r3, r7, lsr #16 +.cfu_2cpy8lp: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_2cpy8lp .cfu_2rem8lp: tst ip, #8 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #16 - movne r4, r4, lsr #16 - orrne r4, r4, r7, lsl #16 + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #16 + orrne r3, r3, r7, push #16 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_2fupi -.cfu_2nowords: mov r3, r7, lsr #16 +.cfu_2nowords: mov r3, r7, lsr #byte(2) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(3) strgeb r3, [r0], #1 USER( ldrgtbt r3, [r1], #0) @ May fault strgtb r3, [r0], #1 @@ -482,9 +482,9 @@ .cfu_3fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_3nowords - mov r3, r7, lsr #24 + mov r3, r7, pull #24 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #8 + orr r3, r3, r7, push #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -496,40 +496,40 @@ subs ip, ip, #16 blt .cfu_3rem8lp -.cfu_3cpy8lp: mov r3, r7, lsr #24 +.cfu_3cpy8lp: mov r3, r7, pull #24 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_3cpy8lp .cfu_3rem8lp: tst ip, #8 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #8 - movne r4, r4, lsr #24 - orrne r4, r4, r7, lsl #8 + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #8 + orrne r3, r3, r7, push #8 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_3fupi -.cfu_3nowords: mov r3, r7, lsr #24 +.cfu_3nowords: mov r3, r7, lsr #byte(3) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrget r3, [r1], #0) @ May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 - movgt r3, r3, lsr #8 +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .cfu_finished diff -Nru a/arch/arm/mach-adifcc/Makefile b/arch/arm/mach-adifcc/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/Makefile Thu Dec 4 16:24:26 2003 @@ -0,0 +1,23 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := adifcc.o + +# Object file lists. + +obj-y := arch.o xs80200-irq.o mm.o +obj-m := csum.o +obj-n := +obj- := + +export-objs := + +obj-$(CONFIG_ARCH_BRH) += brh-irq.o brh-pci.o pci.o pci-auto.o brh-time.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/arm/mach-adifcc/arch.c b/arch/arm/mach-adifcc/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/arch.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,61 @@ +/* + * linux/arch/arm/mach-adifcc/arch.c + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 + + +static void __init +fixup_adi(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + if(machine_is_adi_evb()) + { + mi->bank[0].start = 0xc0000000; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + mi->nr_banks = 1; + } +} + +extern void adi_map_io(void); + +#ifdef CONFIG_ARCH_ADI_EVB +extern void xs80200_init_irq(void); + +MACHINE_START(ADI_EVB, "ADI 80200EVB Evaluation Board") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0xc0000000, 0x00400000, 0xff400000) + FIXUP(fixup_adi) + MAPIO(adi_map_io) + INITIRQ(xs80200_init_irq) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_BRH +extern void brh_init_irq(void); + +MACHINE_START(BRH, "ADI BRH") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0xc0000000, 0x03000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_adi) + MAPIO(adi_map_io) + INITIRQ(brh_init_irq) +MACHINE_END +#endif + diff -Nru a/arch/arm/mach-adifcc/brh-irq.c b/arch/arm/mach-adifcc/brh-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/brh-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,137 @@ +/* + * arch/arm/mach-adifcc/brh.h + * + * Interrupt code for ADI BRH board + * + * Author: Deepak Saxena + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 +#include +#include + +#include + +extern void xs80200_init_irq(void); + +static void brh_irq_mask(unsigned int irq) +{ + long intmask = *(BRH_INT_MASK); + + intmask |= (1 << (irq - NR_XS80200_IRQS)); + + *(BRH_INT_MASK) = intmask; +} + +static void brh_irq_unmask(unsigned int irq) +{ + long intmask = *(BRH_INT_MASK); + + intmask &= ~(1 << (irq - NR_XS80200_IRQS)); + + *(BRH_INT_MASK) = intmask; +} + +extern void do_IRQ(int, struct pt_regs *); + +static void brh_irq_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 irq_stat = *(BRH_INT_STAT); + u32 irq_mask = *(BRH_INT_MASK); + int irqno = 0; + + irq_stat &= ~irq_mask; + + if(irq_stat & 0x00000001) + irqno = IRQ_BRH_SWI; + else if(irq_stat & 0x00000002) + irqno = IRQ_BRH_TIMERA; + else if(irq_stat & 0x00000004) + irqno = IRQ_BRH_TIMERB; + else if(irq_stat & 0x00000008) + irqno = IRQ_BRH_ERROR; + else if(irq_stat & 0x00000010) + irqno = IRQ_BRH_DMA_EOT; + else if(irq_stat & 0x00000020) + irqno = IRQ_BRH_DMA_PARITY; + else if(irq_stat & 0x00000040) + irqno = IRQ_BRH_DMA_TABORT; + else if(irq_stat & 0x00000080) + irqno = IRQ_BRH_DMA_MABORT; + else if(irq_stat & 0x00010000) + irqno = IRQ_BRH_PCI_PERR; + else if(irq_stat & 0x00080000) + irqno = IRQ_BRH_PCI_SERR; + else if(irq_stat & 0x00100000) + irqno = IRQ_BRH_ATU_PERR; + else if(irq_stat & 0x00200000) + irqno = IRQ_BRH_ATU_TABORT; + else if(irq_stat & 0x00400000) + irqno = IRQ_BRH_ATU_MABORT; + else if(irq_stat & 0x01000000) + irqno = IRQ_BRH_UART_A; + else if(irq_stat & 0x02000000) + irqno = IRQ_BRH_UART_B; + else if(irq_stat & 0x04000000) + irqno = IRQ_BRH_PCI_INT_A; + else if(irq_stat & 0x08000000) + irqno = IRQ_BRH_PCI_INT_B; + else if(irq_stat & 0x10000000) + irqno = IRQ_BRH_PCI_INT_C; + else if(irq_stat & 0x20000000) + irqno = IRQ_BRH_PCI_INT_D; + else if(irq_stat & 0x40000000) + irqno = IRQ_BRH_SOFT_RESET; + + if(!irqno) + printk(KERN_ERR "Error: Spurious BRH interrupt\n"); + +// printk("brh_irq_demux called: %d\n", irqno); + do_IRQ(irqno, regs); +} + +static struct irqaction brh_irq = { + name: "BRH IRQ", + handler: brh_irq_demux, + flags: SA_INTERRUPT +}; + +extern int setup_arm_irq(int, struct irqaction *); + +void __init brh_init_irq(void) +{ + int i = 0; + + /* + * Route all sources to IRQ instead of FIQ + * Mask all sources + */ + *(BRH_INT_STEERING) = 0; + *(BRH_INT_MASK) = 0xffffffff; + + for(i = NR_XS80200_IRQS; i < NR_IRQS; i++) + { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = brh_irq_mask; + irq_desc[i].mask = brh_irq_mask; + irq_desc[i].unmask = brh_irq_unmask; + } + + xs80200_init_irq(); + + setup_arm_irq(IRQ_XS80200_EXTIRQ, &brh_irq); +} diff -Nru a/arch/arm/mach-adifcc/brh-pci.c b/arch/arm/mach-adifcc/brh-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/brh-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,445 @@ +/* + * arch/arm/mach-adiff/brh-pci.c + * + * PCI routines for ADI BRH board + * + * Author: Deepak Saxena + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +static int brh_pci_abort_handler(unsigned long, unsigned int, struct pt_regs *); + +//#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +/* + * Used to check on status of bad config cycles + */ +static int error_ocurred; + +static u32* +brh_pci_config_setup(struct pci_dev *dev, int where) +{ + u32 *paddress; + + error_ocurred = 0; + + /* Must be dword aligned */ + + where &= ~3; + + /* + * For top bus, generate type 0, else type 1 + */ + if(!dev->bus->number) + { + if(PCI_SLOT(dev->devfn) > 3) + return NULL; + + *BRH_PCI_CONFIG_CTRL = 0x00000000; + + paddress = ((0xfb000000) | (1 << (PCI_SLOT(dev->devfn)+11)) | + (PCI_FUNC(dev->devfn) << 8) | where); + + } + else + { + *BRH_PCI_CONFIG_CTRL = 0x00000001; + + paddress = ((0xfb000000) | (dev->bus->number << 16) | + (PCI_SLOT(dev->devfn) << 11) | + (PCI_FUNC(dev->devfn) << 8) | where); + } + + + DBG("brh_pci_config_setup(%d:%d:%d:%d) returning %#10x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, paddress); + + return paddress; +} + + +static int +brh_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + u32 *address; + + DBG("config_read_byte %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = brh_pci_config_setup(dev, where); + + if(!address) + *value = 0xff; + else + { + cli(); + *value = (u8)(((*address) >> ((where % 0x04) * 8)) & 0xff); + if(error_ocurred) *value = 0xff; + sti(); + } + + + DBG("config_read_byte read %#4x\n", *value); + + return PCIBIOS_SUCCESSFUL; +} + +static int +brh_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + u32 *address; + + DBG("config_read_word %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = brh_pci_config_setup(dev, where); + + if(!address) + *value = 0xffff; + else + { + cli(); + *value = (u16)(((*address) >> ((where % 0x04) *8)) & 0xffff); + if(error_ocurred) *value = 0xffff; + sti(); + } + + DBG("config_read_word read %#6x\n", *value); + + return PCIBIOS_SUCCESSFUL; +} + +static int +brh_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + u32 *address; + + DBG("config_read_dword %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = brh_pci_config_setup(dev, where); + + if(!address) + *value = 0xffffffff; + else + { + cli(); + *value = *address; + if(error_ocurred) *value = 0xffffffff; + sti(); + } + + DBG("config_read_dword read %#10x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +/* + * We don't do error checking on the address for writes. + * It's assumed that the user checked for the device existing first + * by doing a read first. + */ +static int +brh_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + u32 *address; + u32 mask; + u32 temp; + + address = brh_pci_config_setup(dev, where); + + mask = ~(0x000000ff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) *8)); + *address = (*address & mask) | temp; + + return PCIBIOS_SUCCESSFUL; +} + +static int +brh_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + u32 *address; + u32 mask; + u32 temp; + + address = brh_pci_config_setup(dev, where); + + mask = ~(0x0000ffff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) * 8)); + *address = (*address & mask) | temp; + + return PCIBIOS_SUCCESSFUL; +} + +static int +brh_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + u32 *address; + + address = brh_pci_config_setup(dev, where); + + *address = value; + + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops brh_ops = { + brh_read_config_byte, + brh_read_config_word, + brh_read_config_dword, + brh_write_config_byte, + brh_write_config_word, + brh_write_config_dword, +}; + +static struct pci_controller *hose; + +static int +brh_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + u16 status; + + DBG("\n"); + DBG("DATA ABORT ON %#010x\n", addr); + + brh_read_config_word(fake_pci_dev(hose, 0, 0), + PCI_STATUS, + &status); + + DBG("BRH_PCI_MAST_INT: %#010x\n", *BRH_PCI_MAST_INT); + DBG("PCI_CFG_STATUS: %#010x\n", status); + DBG("INT STATUS: %#010x\n", *BRH_INT_STAT); + + /* + * Clear Mast. Abort line + */ + *BRH_PCI_MAST_INT |= 0x8; + + status |= PCI_STATUS_REC_MASTER_ABORT; + brh_write_config_word(fake_pci_dev(hose, 0, 0), + PCI_STATUS, + status); + + error_ocurred = 1; + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +static struct resource brh_mem = { + name: "BRH PCI Non-Prefetch Memory Space", + start: 0x0c000000, + end: 0x0fffffff, + flags: IORESOURCE_MEM +}; + +static struct resource brh_io = { + name: "BRH PCI I/O Space", + start: 0x0a000000, + end: 0x0bffffff, + flags: IORESOURCE_IO +}; + +void brh_pci_setup_resources(struct resource **res) +{ + if(request_resource(&ioport_resource, &brh_io)) + panic("COULD NOT REQUEST I/O"); + + if(request_resource(&iomem_resource, &brh_mem)) + panic("COULD NOT REQUEST MEM"); + + res[0] = &brh_io; + res[1] = &brh_mem; + res[2] = NULL; +} + +void __init +brh_pci_init(void *sysdata) +{ + struct pci_bus *bus; + struct pci_dev *dev; + u8 rev_id; + + DBG("Allocating hose\n"); + + hose = pcibios_alloc_controller(); + if(!hose) + panic("Could not allocate PCI hose"); + + brh_read_config_byte(fake_pci_dev(hose, 0, 0), + PCI_REVISION_ID, &rev_id); + + printk("PCI: BRH Revision is %#04x\n", rev_id); + + system_rev = rev_id; + + /* + * RedBoot enables the PCI unit, but the PCI config can't + * be updated while PCI is enabled. + */ + brh_write_config_word(fake_pci_dev(hose, 0, 0), PCI_COMMAND, 0); + + + /* + * Setup two outbound PCI mem ATUs to be 1:1 mapped + * along with the I/O ATU. + */ +#ifndef __ARMEB__ + *BRH_PCI_MEM_ATU1 = (unsigned int)0x0c000000; + *BRH_PCI_MEM_ATU2 = (unsigned int)0x0e000000; + *BRH_PCI_IO_ATU = (unsigned int)0x0a000000; +#else + *BRH_PCI_MEM_ATU1 = (unsigned int)0x0c000004; + *BRH_PCI_MEM_ATU2 = (unsigned int)0x0e000004; + *BRH_PCI_IO_ATU = (unsigned int)0x0a000004; +#endif + + hose->first_busno = 0; + hose->last_busno = 0; + hose->io_space.start = 0x0a000000; + hose->io_space.end = 0x0bffffff; + hose->mem_space.start = 0x0c000000; + hose->mem_space.end = 0x0fffffff; + + /* + * + * We setup the two inbound windows to be contigous from + * 0xc0000000 to 0xc3ffffff. This allows for 1:1 mapping of + * phys to bus addresses. We also need to setup the inbound + * translation registers to force the 1:1 mapping. + */ + if(!system_rev) { + brh_write_config_dword(fake_pci_dev(hose, 0, 0), + PCI_BASE_ADDRESS_0, 0xc0000000); +#ifndef __ARMEB__ + *BRH_PCI_MEM0_XLATE = 0x00000000; +#else + *BRH_PCI_MEM0_XLATE = 0x00000001; +#endif + } else { + + /* + * Disable the two 32M windows + */ + brh_write_config_dword(fake_pci_dev(hose, 0, 0), + PCI_BASE_ADDRESS_0, 0x00000000); + brh_write_config_dword(fake_pci_dev(hose, 0, 0), + PCI_BASE_ADDRESS_1, 0x00000000); + + brh_write_config_dword(fake_pci_dev(hose, 0, 0), + PCI_BASE_ADDRESS_2, 0xc0000000); + +#ifndef __ARMEB__ + *BRH_PCI_MEM2_XLATE = 0x00000000; +#else + *BRH_PCI_MEM2_XLATE = 0x00000001; +#endif + } + + brh_write_config_word(fake_pci_dev(hose, 0, 0), PCI_COMMAND, + PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER); + + DBG("Calling autoconfig\n"); + + hook_fault_code(4, brh_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(6, brh_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(8, brh_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); + hook_fault_code(10, brh_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); +// hook_fault_code(16+6, brh_pci_abort_handler, SIGBUS, "PCI Config Cycle Abort\n"); + + /* + * Autoconfig the bus + */ + hose->last_busno = pciauto_bus_scan(hose, 0); + + DBG("Scanning the bus\n"); + /* Scan the bus */ + bus = pci_scan_bus(0, &brh_ops, sysdata); +} + +#define INTA IRQ_BRH_PCI_INT_A +#define INTB IRQ_BRH_PCI_INT_B +#define INTC IRQ_BRH_PCI_INT_C +#define INTD IRQ_BRH_PCI_INT_D + +static int __init +brh_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + const long min_idsel = 1, max_idsel = 3, irqs_per_slot = 4; + + static char pci_irq_table[][4] = + { + /* + * PCI IDSEL/INTPIN -> INTLINE + */ + {INTB, INTB, INTB, INTB}, /* Enet 0 */ + {INTC, INTC, INTC, INTC}, /* Enet 1 */ + {INTA, INTB, INTC, INTD}, /* PCI Slot */ + }; + + return PCI_IRQ_TABLE_LOOKUP; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return brh_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + +struct hw_pci brh_pci __initdata = { + init: brh_pci_init, + swizzle: common_swizzle, + map_irq: brh_map_irq, + setup_resources: brh_pci_setup_resources +}; + diff -Nru a/arch/arm/mach-adifcc/brh-time.c b/arch/arm/mach-adifcc/brh-time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/brh-time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,81 @@ +/* + * arch/arm/mach-adifcc/brh-time.c + * + * Timer code for BECC onboard timer + * + * Author: Deepak Saxena + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 CONFG_XSCALE_PMU_TIMER + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +static unsigned long brh_gettimeoffset(void) +{ + unsigned long elapsed, usec; + + /* Elapsed timer ticks since last IRQ */ + elapsed = LATCH - (*BRH_TIMERA_VALUE); + + /* Conver to usec */ + usec = (unsigned long)(elapsed * tick) / LATCH; + + return usec; +} + +static void brh_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + *BRH_TIMERA_CTRL |= BRH_TIMER_INTERRUPT; + + /* + * Hack...see IQ80310 timer for reasoning + */ + irq_exit(smp_processor_id(), irq); + do_timer(regs); + irq_enter(smp_processor_id(), irq); +} + +static struct irqaction timer_irq = { + name: "timer", +}; + +extern unsigned long (*gettimeoffset)(void); +extern int setup_arm_irq(int, struct irqaction *); + +void __init setup_timer(void) +{ + gettimeoffset = brh_gettimeoffset; + timer_irq.handler = brh_timer_interrupt; + setup_arm_irq(IRQ_BRH_TIMERA, &timer_irq); + + *BRH_TIMERA_CTRL = 0; + *BRH_TIMERA_PRELOAD = LATCH; + *BRH_TIMERA_CTRL = BRH_TIMER_ENABLE | BRH_TIMER_CONTINOUS; +} + +#endif // !CONFIG_XSCALE_PMU_TIMER diff -Nru a/arch/arm/mach-adifcc/mm.c b/arch/arm/mach-adifcc/mm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/mm.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/mach-xscale/mm.c + */ + +#include +#include + +#include +#include +#include +#include + +#include + +static struct map_desc adi_evb_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + /* On-board devices */ + { 0xff400000, 0x00400000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static struct map_desc brh_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + /* PCI Config Window */ + { 0xfb000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, + /* PCI I/O Window */ + { 0xfd000000, 0x0a000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, + /* On board devices - UART 0 & 1, LED */ + { 0xff000000, 0x03000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, + /* BECC Configurations Registers */ + { 0xff400000, 0x04000000, 0x00010000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init adi_map_io(void) +{ + if(machine_is_adi_evb()) + iotable_init(adi_evb_io_desc); + else if(machine_is_brh()) + iotable_init(brh_io_desc); +} diff -Nru a/arch/arm/mach-adifcc/pci-auto.c b/arch/arm/mach-adifcc/pci-auto.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/pci-auto.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,379 @@ +/* + * arch/arm/mach-iop310/pci-auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 + +// #define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int bar_limit) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask, bar_nr = 0; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + DBG("PCI Autoconfig: Bridge %d. IO_FILTER = %#010x..%#010x\n", + current_bus, + (pciauto_upper_iospc & 0x0000f000) >> 8, + pciauto_upper_iospc >> 16); + + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) + { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + /* If config space read fails from this device, move on */ + if (early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } + else + { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_5); + } + } + } + return sub_bus; +} diff -Nru a/arch/arm/mach-adifcc/pci.c b/arch/arm/mach-adifcc/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,250 @@ +/* + * arch/arm/mach-iop310/pci.c + * + * Generic PCI support functionality that should eventually move to + * arch/arm/kernel/bios32.c. Derived from support in ppc and alpha. + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +/* + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * some boards that don't follow the PCI spec's suggestion so we + * break this piece out separately. + */ +static inline u8 +bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +u8 __init +common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(dev->bus->number); + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +/* + * Null PCI config access functions, for the case when we can't + * find a hose. + */ +#define NULL_PCI_OP(rw, size, type) \ +static int \ +null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + return PCIBIOS_DEVICE_NOT_FOUND; \ +} + + NULL_PCI_OP(read, byte, u8 *) + NULL_PCI_OP(read, word, u16 *) + NULL_PCI_OP(read, dword, u32 *) + NULL_PCI_OP(write, byte, u8) + NULL_PCI_OP(write, word, u16) +NULL_PCI_OP(write, dword, u32) + +static struct pci_ops null_pci_ops = +{ + null_read_config_byte, + null_read_config_word, + null_read_config_dword, + null_write_config_byte, + null_write_config_word, + null_write_config_dword +}; + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +struct pci_dev * +fake_pci_dev(struct pci_controller *hose, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + if (hose == 0) { + hose = pci_bus_to_hose(busnr); + if (hose == 0) + printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); + } + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose? hose->ops: &null_pci_ops; + return &dev; +} + +static int next_controller_index; + +struct pci_controller * __init +pcibios_alloc_controller(void) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *)kmalloc(sizeof(*hose), GFP_KERNEL); + memset(hose, 0, sizeof(struct pci_controller)); + + *hose_tail = hose; + hose_tail = &hose->next; + + hose->index = next_controller_index++; + + return hose; +} + +struct pci_controller * +pci_bus_to_hose(int bus) +{ + struct pci_controller *hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +void __init +pci_exclude_device(unsigned char bus, unsigned char devfn) +{ + struct pci_dev *dev, *pdev = NULL; + + /* Walk the pci device list */ + pci_for_each_dev(dev) + { + if ((dev->bus->number == bus) && (dev->devfn == devfn)) + { + /* + * Remove the device from the global and + * bus lists. + */ + list_del(&(dev->global_list)); + list_del(&(dev->bus_list)); + + /* Free the pci_dev structure */ + kfree(dev); + + break; + } + pdev = dev; + } +} + +static inline void __init alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + pr = pci_find_parent_resource(dev, r); + if(!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Can not allocate resource region %d" \ + " of device %s\n", idx, dev->slot_name); + r->end -= r->start; + r->start = 0; + } +} + +void __init +pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + int i; + struct resource *res, *pr; + + if(!bus_list) return; + + /* Depth-First Search on bus tree */ + for (ln = bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + pci_read_bridge_bases(bus); + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Can not allocate resource region " + "%d of PCI bridge %d\n", i, bus->number); + DBG("PCI: resource is %lx..%lx (%lx)\n", + res->start, res->end, res->flags); + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +void __init pcibios_allocate_resources(void) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r; + + pci_for_each_dev(dev) + { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) + { + r = &dev->resource[idx]; + + if(r->parent) + continue; + if(!r->start) + continue; + + alloc_resource(dev, idx); + } + } +} + + diff -Nru a/arch/arm/mach-adifcc/xs80200-irq.c b/arch/arm/mach-adifcc/xs80200-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-adifcc/xs80200-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,68 @@ +/* + * linux/arch/arm/mach-adifcc/irq.c + * + * Author: Deepak Saxena + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 + +void xs80200_irq_mask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; + case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void xs80200_irq_unmask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; + case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void __init xs80200_init_irq(void) +{ + int i; + unsigned long int_steer = 0x0; + + /* + * Steer interrupts to IRQ instead of FIQ + */ + asm ("mcr p13, 0, %0, c8, c0, 0" : : "r" (int_steer)); + + for (i = 0; i < NR_XS80200_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = xs80200_irq_mask; + irq_desc[i].mask = xs80200_irq_mask; + irq_desc[i].unmask = xs80200_irq_unmask; + } +} + diff -Nru a/arch/arm/mach-iop3xx/Makefile b/arch/arm/mach-iop3xx/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/Makefile Thu Dec 4 16:24:26 2003 @@ -0,0 +1,44 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := iop3xx.o + +# Object file lists. + +obj-y := arch.o pci.o pci-auto.o + +obj-n := +obj- := + +export-objs := + +obj-m := + +obj-$(CONFIG_ARCH_IOP310) += xs80200-irq.o iop310-irq.o iop310-pci.o mm.o + +obj-$(CONFIG_ARCH_IQ80310) += iq80310-pci.o iq80310-irq.o + +obj-$(CONFIG_ARCH_IOP321) += iop321-irq.o iop321-pci.o mm-321.o iop321-time.o + +obj-$(CONFIG_ARCH_IQ80321) += iq80321-pci.o + +obj-$(CONFIG_ARCH_IQ31244) += iq31244-pci.o + +ifeq ($(CONFIG_ARCH_IQ80310),y) + ifneq ($(CONFIG_XSCALE_PMU_TIMER),y) + obj-y += iq80310-time.o + endif +endif + +obj-$(CONFIG_IOP3XX_AAU) += aau.o +obj-$(CONFIG_IOP3XX_DMA) += dma.o +obj-$(CONFIG_IOP3XX_MU) += message.o +obj-$(CONFIG_IOP3XX_PMON) += pmon.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/arm/mach-iop3xx/aau.c b/arch/arm/mach-iop3xx/aau.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/aau.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,660 @@ +/* + * arch/arm/mach-iop3xxx/aau->c + * + * Support functions for the Intel 803xx AAU channels. The AAU is + * a HW XOR unit that is specifically designed for use with RAID5 + * applications. This driver provides an interface that is used by + * the Linux RAID stack. + * + * Original Author: Dave Jiang + * + * Contributors: David A. Griego + * Deepak Saxena + * + * Maintainer: Deepak Saxena + * + * Copyright (C) 2003 Intel Corporation + * Copyright (C) 2003 MontaVista Software, Inc. + * + * 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. + * + * TODO: Move to 2.5 kernel + * Replace list interface with a cache of objects? + * Move interrupt handling to tasklet? + * Better error handling (ERR IRQs and runtime errors) + * + * History: (02/25/2003, DJ) Initial Creation + * (04/23/2003, DS) Cleanups, add support for iop310 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * pick up local definitions + */ +#include "aau.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#include +#endif + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK(s, args...) printk("IOP3xx AAU: " s "\n", ## args) +#define DENTER() DPRINTK("Entered...\n"); +#define DEXIT() DPRINTK("Exited...\n"); +#else +#define DPRINTK(s, args...) +#define DENTER() +#define DEXIT() +#endif + +/* globals */ +iop3xx_aau_t *aau; /* AAU context */ + +/* static prototypes */ +static int iop3xx_aau_chaininit(iop3xx_aau_t * aa); +static void iop3xx_aau_isr(int, void *, struct pt_regs *); + +static inline void aau_queue_descriptor(sw_aau_t *sw_desc) +{ + unsigned long flags; + + // Set last NDAR to NULL + sw_desc->next = NULL; + sw_desc->status = AAU_ACTIVE; + + spin_lock_irqsave(&aau->process_lock, flags); + list_add_tail(&sw_desc->link, &aau->process_q); + + aau->last_desc->aau_desc->NDAR = sw_desc->aau_phys; + aau->last_desc = sw_desc; + *(aau->regs.ACR) = AAU_ACR_AAU_ENABLE | AAU_ACR_CHAIN_RESUME; + spin_unlock_irqrestore(&aau->process_lock, flags); + + DPRINTK("Going to sleep"); + wait_event_interruptible(sw_desc->wait, + (sw_desc->status & (AAU_COMPLETE | AAU_ERROR))); + DPRINTK("Woken up!"); + + spin_lock_irqsave(&aau->free_lock, flags); + list_add_tail(&sw_desc->link, &aau->free_q); + spin_unlock_irqrestore(&aau->free_lock, flags); +} + +void +xor_iop3xxaau_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + sw_aau_t *sw_desc = NULL; + unsigned long flags; + + DENTER(); + + spin_lock_irqsave(&aau->free_lock, flags); + if (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + if (sw_desc->aau_phys != *aau->regs.ADAR) { + list_del(&sw_desc->link); + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + spin_unlock_irqrestore(&aau->free_lock, flags); + + // flush the cache to memory before AAU touches them + cpu_dcache_clean_range((unsigned long) p1, (unsigned long) p1 + bytes); + cpu_dcache_clean_range((unsigned long) p2, (unsigned long) p2 + bytes); + + // setting up AAU descriptors + sw_desc->aau_desc->DAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR2 = virt_to_phys(p2); + sw_desc->aau_desc->BC = bytes; + + // write enable, direct fill block 1, xor the rest + sw_desc->aau_desc->DC = AAU_ADCR_WREN | AAU_ADCR_XOR_2 | AAU_ADCR_IE; + sw_desc->aau_desc->NDAR = 0; + + aau_queue_descriptor(sw_desc); + + if (sw_desc->status & AAU_ERROR) { + printk(KERN_ERR "%s: IOP321 AAU operation failed!\n", __func__); + BUG(); + } + + // invalidate the cache region to destination + cpu_dcache_invalidate_range((unsigned long) p1, + (unsigned long) p1 + bytes); + DEXIT(); +} + +void +xor_iop3xxaau_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + sw_aau_t *sw_desc = NULL; + unsigned long flags; + + spin_lock_irqsave(&aau->free_lock, flags); + if (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + if (sw_desc->aau_phys != *aau->regs.ADAR) { + list_del(&sw_desc->link); + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + spin_unlock_irqrestore(&aau->free_lock, flags); + + // flush the cache to memory before AAU touches them + cpu_dcache_clean_range((unsigned long) p1, (unsigned long) p1 + bytes); + cpu_dcache_clean_range((unsigned long) p2, (unsigned long) p2 + bytes); + cpu_dcache_clean_range((unsigned long) p3, (unsigned long) p3 + bytes); + + // setting up AAU descriptors + sw_desc->aau_desc->DAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR2 = virt_to_phys(p2); + sw_desc->aau_desc->SAR3 = virt_to_phys(p3); + sw_desc->aau_desc->BC = bytes; + + // write enable, direct fill block 1, xor the rest + sw_desc->aau_desc->DC = AAU_ADCR_WREN | AAU_ADCR_XOR_3 | AAU_ADCR_IE; + sw_desc->aau_desc->NDAR = 0; + + aau_queue_descriptor(sw_desc); + + // check to see if AAU failed + if (sw_desc->status & AAU_ERROR) { + printk(KERN_ERR "%s: IOP321 AAU operation failed!\n", __func__); + BUG(); + } + // invalidate the cache region to destination + cpu_dcache_invalidate_range((unsigned long) p1, + (unsigned long) p1 + bytes); +} + +void +xor_iop3xxaau_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + sw_aau_t *sw_desc = NULL; + unsigned long flags; + + spin_lock_irqsave(&aau->free_lock, flags); + if (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + if (sw_desc->aau_phys != *aau->regs.ADAR) { + list_del(&sw_desc->link); + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + spin_unlock_irqrestore(&aau->free_lock, flags); + + // flush the cache to memory before AAU touches them + cpu_dcache_clean_range((unsigned long) p1, (unsigned long) p1 + bytes); + cpu_dcache_clean_range((unsigned long) p2, (unsigned long) p2 + bytes); + cpu_dcache_clean_range((unsigned long) p3, (unsigned long) p3 + bytes); + cpu_dcache_clean_range((unsigned long) p4, (unsigned long) p4 + bytes); + + // setting up AAU descriptors + sw_desc->aau_desc->DAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR2 = virt_to_phys(p2); + sw_desc->aau_desc->SAR3 = virt_to_phys(p3); + sw_desc->aau_desc->SAR4 = virt_to_phys(p4); + + sw_desc->aau_desc->BC = bytes; + // write enable, direct fill block 1, xor the rest + sw_desc->aau_desc->DC = AAU_ADCR_WREN | AAU_ADCR_XOR_4 | AAU_ADCR_IE; + sw_desc->aau_desc->NDAR = 0; + + aau_queue_descriptor(sw_desc); + + // check to see if AAU failed + if (sw_desc->status & AAU_ERROR) { + printk(KERN_ERR "%s: IOP321 AAU operation failed!\n", __func__); + BUG(); + } + + // invalidate the cache region to destination + cpu_dcache_invalidate_range((unsigned long) p1, + (unsigned long) p1 + bytes); +} + +void +xor_iop3xxaau_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + sw_aau_t *sw_desc = NULL; + unsigned long flags; + + spin_lock_irqsave(&aau->free_lock, flags); + if (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + if (sw_desc->aau_phys != *aau->regs.ADAR) { + list_del(&sw_desc->link); + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + } else { + // This should NEVER happen. We need to increase the amount + // of descriptors if that is the case + // TODO: put in something nice later to handle this! + + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + spin_unlock_irqrestore(&aau->free_lock, flags); + BUG(); + return; + } + spin_unlock_irqrestore(&aau->free_lock, flags); + + // flush the cache to memory before AAU touches them + cpu_dcache_clean_range((unsigned long) p1, (unsigned long) p1 + bytes); + cpu_dcache_clean_range((unsigned long) p2, (unsigned long) p2 + bytes); + cpu_dcache_clean_range((unsigned long) p3, (unsigned long) p3 + bytes); + cpu_dcache_clean_range((unsigned long) p4, (unsigned long) p4 + bytes); + cpu_dcache_clean_range((unsigned long) p5, (unsigned long) p5 + bytes); + + // setting up AAU descriptors + sw_desc->aau_desc->DAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR = virt_to_phys(p1); + sw_desc->aau_desc->SAR2 = virt_to_phys(p2); + sw_desc->aau_desc->SAR3 = virt_to_phys(p3); + sw_desc->aau_desc->SAR4 = virt_to_phys(p4); + sw_desc->aau_desc->SAR5 = virt_to_phys(p5); + sw_desc->aau_desc->BC = bytes; + + // write enable, direct fill block 1, xor the rest + sw_desc->aau_desc->DC = AAU_ADCR_WREN | AAU_ADCR_XOR_5 | AAU_ADCR_IE; + sw_desc->aau_desc->NDAR = 0; + + aau_queue_descriptor(sw_desc); + + // check to see if AAU failed + if (sw_desc->status & AAU_ERROR) { + printk(KERN_ERR "%s: IOP321 AAU operation failed!\n", __func__); + BUG(); + } + + // invalidate the cache region to destination + cpu_dcache_invalidate_range((unsigned long) p1, + (unsigned long) p1 + bytes); +} + +static void +iop3xx_aau_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + iop3xx_aau_t *aa = (iop3xx_aau_t *) dev_id; + u32 csr = 0; + sw_aau_t *sw_desc = NULL; + int irq_thresh = AAU_IRQ_THRESH; + + DENTER(); + + csr = *(aa->regs.ASR); + + // make sure the interrupt is for us + if (!(csr & (AAU_ASR_DONE_MASK | AAU_ASR_ERR_MASK))) { + return; + } + + // Does not support more than AAU chaining of multiple processes yet */ + while (csr && irq_thresh--) { + // clear interrupts + *(aa->regs.ASR) |= AAU_ASR_DONE_MASK | AAU_ASR_ERR_MASK; + + spin_lock(&aa->process_lock); + while (!list_empty(&aa->process_q)) { + sw_desc = list_entry(aa->process_q.next, sw_aau_t, link); + if (sw_desc->aau_phys != *aa->regs.ADAR) { + list_del(&sw_desc->link); + if (!(csr & AAU_ASR_ERR_MASK)) { + sw_desc->status = AAU_COMPLETE; + } else { + sw_desc->status = AAU_ERROR; + } + wake_up_interruptible(&sw_desc->wait); + } else { + if (!(*aa->regs.ASR & AAU_ASR_ACTIVE)) { + list_del(&sw_desc->link); + if (!(csr & AAU_ASR_ERR_MASK)) { + sw_desc->status = AAU_COMPLETE; + } else { + sw_desc->status = AAU_ERROR; + } + wake_up_interruptible(&sw_desc->wait); + } else { + spin_unlock(&aa->process_lock); + return; + } + } + } + spin_unlock(&aa->process_lock); + + // re-read CSR to check for more interrupts + csr = *(aa->regs.ASR); + } // end of while(csr) + + DEXIT(); +} + +int +iop3xx_aau_init(void) +{ + int i; + sw_aau_t *sw_desc = NULL; + void *desc = NULL; + int err = 0; + + aau = kmalloc(sizeof(*aau), GFP_KERNEL); + + printk("Intel IOP3xx AAU RAID Copyright(c) 2003 Intel Corporation\n"); + + /* init free stack */ + INIT_LIST_HEAD(&aau->free_q); + INIT_LIST_HEAD(&aau->process_q); + + /* init free stack spinlock */ + spin_lock_init(&aau->free_lock); + spin_lock_init(&aau->process_lock); + + aau->last_desc = NULL; + + /* pre-alloc AAU descriptors */ + for (i = 0; i < MAX_AAU_DESC; i++) { + /* + * we keep track of original address before alignment + * adjust so we can free it later + */ + sw_desc = kmalloc(sizeof (sw_aau_t), GFP_KERNEL); + sw_desc->aau_virt = desc = + kmalloc((sizeof (aau_desc_t) + 0x20), GFP_KERNEL); + memset(desc, 0, sizeof (aau_desc_t) + 0x20); + + /* + * hardware descriptors must be aligned on an + * 8-word boundary + */ + desc = (aau_desc_t *) (((u32) desc & 0xffffffe0) + 0x20); + // get the physical address + sw_desc->aau_phys = (u32) virt_to_phys(desc); + // remap it to non-cached + sw_desc->aau_desc = + (aau_desc_t *) ioremap(sw_desc->aau_phys, + sizeof (aau_desc_t)); + + sw_desc->status = AAU_FREE; + init_waitqueue_head(&sw_desc->wait); + + /* put the descriptors on the free stack */ + list_add(&sw_desc->link, &aau->free_q); + } + + /* + * Fill out AAU descriptor based on IOP type + */ +#ifdef CONFIG_ARCH_IOP321 + if(iop_is_321()) { + aau->regs.ACR = IOP321_AAU_ACR; + aau->regs.ASR = IOP321_AAU_ASR; + aau->regs.ADAR = IOP321_AAU_ADAR; + aau->regs.ANDAR = IOP321_AAU_ANDAR; + aau->regs.SAR = IOP321_AAU_SAR1; + aau->regs.DAR = IOP321_AAU_DAR; + aau->regs.BCR = IOP321_AAU_ABCR; + aau->regs.DCR = IOP321_AAU_ADCR; + + aau->irq.EOT = IRQ_IOP321_AA_EOT; + aau->irq.EOC = IRQ_IOP321_AA_EOC; + aau->irq.ERR = IRQ_IOP321_AA_ERR; + + aau->device_id = "IOP321 HW XOR"; + } +#endif +#ifdef CONFIG_ARCH_IOP310 + if(iop_is_310()) { + aau->regs.ACR = IOP310_AAU_ACR; + aau->regs.ASR = IOP310_AAU_ASR; + aau->regs.ADAR = IOP310_AAU_ADAR; + aau->regs.ANDAR = IOP310_AAU_ANDAR; + aau->regs.SAR = IOP310_AAU_SAR1; + aau->regs.DAR = IOP310_AAU_DAR; + aau->regs.BCR = IOP310_AAU_ABCR; + aau->regs.DCR = IOP310_AAU_ADCR; + + aau->irq.EOT = -1; + aau->irq.EOC = IRQ_IOP310_AAU; + aau->irq.ERR = -1; + + aau->device_id = "IOP310 HW XOR"; + } +#endif + /* clear AAU control register */ + + *(aau->regs.ACR) = AAU_ACR_CLEAR; + *(aau->regs.ASR) |= (AAU_ASR_DONE_MASK | AAU_ASR_ERR_MASK); + *(aau->regs.ANDAR) = 0; + + if(aau->irq.EOT >= 0) + err = request_irq(aau->irq.EOT, iop3xx_aau_isr, SA_INTERRUPT, + aau->device_id, (void *)aau); + if (err < 0) { + printk(KERN_ERR "%s: unable to request IRQ %d for " + "AAU %d: %d\n", aau->device_id, aau->irq.EOT, 0, err); + return -EBUSY; + } + + if(aau->irq.EOC >= 0) + err = request_irq(aau->irq.EOC, iop3xx_aau_isr, SA_INTERRUPT, + aau->device_id, (void *)aau); + if (err < 0) { + printk(KERN_ERR "%s: unable to request IRQ %d for " + "AAU %d: %d\n", aau->device_id, aau->irq.EOC, 0, err); + return -EBUSY; + } + + if(aau->irq.ERR >= 0) + err = request_irq(aau->irq.ERR, iop3xx_aau_isr, SA_INTERRUPT, + aau->device_id, (void *)aau); + if (err < 0) { + printk(KERN_ERR "%s: unable to request IRQ %d for " + "AAU %d: %d\n", aau->device_id, aau->irq.ERR, 0, err); + return -EBUSY; + } + + err = iop3xx_aau_chaininit(aau); + if (err < 0) { + printk(KERN_ERR "unable to setup chaining\n"); + return -EIO; + } + + DPRINTK("AAU init Done!\n"); + return 0; +} /* end of iop3xx_aau_init() */ + +void +iop3xx_aau_exit(void) +{ + sw_aau_t *sw_desc = NULL; + + while (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + list_del(&sw_desc->link); + iounmap(sw_desc->aau_desc); + kfree(sw_desc->aau_virt); + kfree((void *) sw_desc); + } + + while (!list_empty(&aau->process_q)) { + sw_desc = list_entry(aau->process_q.next, sw_aau_t, link); + list_del(&sw_desc->link); + iounmap(sw_desc->aau_desc); + kfree(sw_desc->aau_virt); + kfree((void *) sw_desc); + } + + // get rid of the last dangle descriptor + sw_desc = aau->last_desc; + iounmap(sw_desc->aau_desc); + kfree(sw_desc->aau_virt); + kfree((void *) sw_desc); + + free_irq(aau->irq.EOC, (void *) &aau); + free_irq(aau->irq.EOT, (void *) &aau); + free_irq(aau->irq.ERR, (void *) &aau); +} + +static int +iop3xx_aau_chaininit(iop3xx_aau_t * aa) +{ + int flags = 0; + sw_aau_t *sw_desc = NULL; + u32 csr = 0; + + spin_lock_irqsave(&aau->free_lock, flags); + + if (!list_empty(&aau->free_q)) { + sw_desc = list_entry(aau->free_q.next, sw_aau_t, link); + list_del(&sw_desc->link); + } else { + /* + * This should NEVER happen. We need to increase the amount + * of descriptors if that is the case + * + * TODO: put in something nice later to handle this! + */ + spin_unlock_irqrestore(&aau->free_lock, flags); + DPRINTK(KERN_ERR "out of AAU descriptors! Increase!\n"); + BUG(); + return -ENOMEM; + } + spin_unlock_irqrestore(&aau->free_lock, flags); + + DPRINTK("soft AAU desc acquired"); + + /* + * Initialize HW chaining + */ + sw_desc->aau_desc->BC = 0; + sw_desc->aau_desc->DC = 0; // NULL command + sw_desc->aau_desc->NDAR = 0; + sw_desc->next = NULL; + + spin_lock_irqsave(&aau->process_lock, flags); + list_add(&sw_desc->link, &aau->process_q); + spin_unlock_irqrestore(&aau->process_lock, flags); + + // Do AAU stuff + *(aau->regs.ASR) |= (AAU_ASR_DONE_MASK | AAU_ASR_ERR_MASK); + *(aau->regs.ANDAR) = sw_desc->aau_phys; + *(aau->regs.ACR) = AAU_ACR_AAU_ENABLE; + + DPRINTK("we are polling"); + csr = *(aau->regs.ASR); + while (csr & AAU_ASR_ACTIVE) { + csr = *(aau->regs.ASR); + } + + DPRINTK("removing from processing queue"); + spin_lock_irqsave(&aau->process_lock, flags); + list_del(&sw_desc->link); + spin_unlock_irqrestore(&aau->process_lock, flags); + + sw_desc->status = AAU_FREE; + spin_lock_irqsave(&aau->free_lock, flags); + list_add_tail(&sw_desc->link, &aau->free_q); + spin_unlock_irqrestore(&aau->free_lock, flags); + + // check to see if AAU failed + if (!(csr & AAU_ASR_ERR_MASK)) { + aau->last_desc = sw_desc; + } else { + aau->last_desc = NULL; + return -EIO; + } + + return 0; +} /* end of iop3xx_aau_chaininit() */ + +module_init(iop3xx_aau_init); +module_exit(iop3xx_aau_exit); +MODULE_LICENSE(GPL); + diff -Nru a/arch/arm/mach-iop3xx/aau.h b/arch/arm/mach-iop3xx/aau.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/aau.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,140 @@ +/* + * Private Definitions for IOP3XX AAU + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2003 Intel 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. + * + */ + +#ifndef _AAU_PRIVATE_H_ +#define _AAU_PRIVATE_H_ + +#define AAU_IRQ_THRESH 10 + +#define MAX_AAU_DESC 64 +#define AAU_DESC_SIZE 32 + +/* + * AAU Control Register + */ +#define AAU_ACR_CLEAR 0x00000000 +#define AAU_ACR_AAU_ENABLE 0x00000001 +#define AAU_ACR_CHAIN_RESUME 0x00000002 +#define AAU_ACR_512B_EN 0x00000004 + +/* + * AAU Status Register + */ +#define AAU_ASR_INT_MST_ABORT 0x00000020 +#define AAU_ASR_EOC_INT 0x00000100 +#define AAU_ASR_EOT_INT 0x00000200 +#define AAU_ASR_ACTIVE 0x00000400 +#define AAU_ASR_DONE_MASK (AAU_ASR_EOC_INT | AAU_ASR_EOT_INT) +#define AAU_ASR_ERR_MASK (AAU_ASR_INT_MST_ABORT) + +/* + * AAU Descriptor Control Register + */ +#define AAU_ADCR_IE 0x00000001 /* Interrupt Enable */ +#define AAU_ADCR_DIRFILL 0x0000000E /* memory to memory transfer */ +#define AAU_ADCR_MEMFILL 0x00000004 /* memory fill */ +#define AAU_ADCR_WREN 0x80000000 /* dest write enable */ + +#define AAU_ADCR_XOR_2 0x0000001e +#define AAU_ADCR_XOR_3 0x0000009e +#define AAU_ADCR_XOR_4 0x0000049e +#define AAU_ADCR_XOR_5 0x0000249e + +#define AAU_FREE 0x0 +#define AAU_ACTIVE 0x1 +#define AAU_COMPLETE 0x2 +#define AAU_ERROR 0x4 + + +/* + * AAU Descriptor + * + * This descriptor can be extended to support up 32 buffers at + * once, but we're not supporting that atm as the Linux RAID + * stack only support 5 blocks at once. :( + */ +typedef struct _aau_desc { + u32 NDAR; /* next descriptor adress */ + u32 SAR; /* source addr 1 or data */ + u32 SAR2; /* source addr 2 */ + u32 SAR3; /* source addr 3 */ + u32 SAR4; /* source addr 4 */ + u32 DAR; /* dest addr */ + u32 BC; /* byte count */ + u32 DC; /* descriptor control */ + u32 SAR5; + u32 SAR6; + u32 SAR7; + u32 SAR8; +} aau_desc_t __attribute__((__aligned__(L1_CACHE_BYTES * 2))); + +/* + * AAU Software Descriptor + */ +typedef struct _sw_aau sw_aau_t; + +struct _sw_aau { + struct list_head link; + aau_desc_t *aau_desc; /* AAU descriptor pointer */ + void *aau_virt; /* unaligned virtual aau addr */ + u32 aau_phys; /* aligned aau physical */ + u32 status; + void *virt_src; /* virt source */ + void *virt_dest; /* virt destination */ + u32 phys_src; /* physical/bus address of src */ + u32 phys_dest; /* Physical/bus address of dest */ + u32 buf_size; + sw_aau_t *next; + wait_queue_head_t wait; +}; + +/* + * AAU control register structure + */ +typedef struct _aau_regs { + volatile u32 *ACR; /* channel control register */ + volatile u32 *ASR; /* channel status register */ + volatile u32 *ADAR; /* descriptor address register */ + volatile u32 *ANDAR; /* next descriptor address register */ + volatile u32 *SAR; /* SAR 1 */ + /* SAR2...SAR32 */ /* not supported yet */ + volatile u32 *DAR; /* local address register */ + volatile u32 *BCR; /* byte count register */ + volatile u32 *DCR; /* descriptor control register */ + volatile u32 *EDCR0; + volatile u32 *EDCR1; + volatile u32 *EDCR2; +} aau_regs_t __attribute__((__aligned__(L1_CACHE_BYTES))); + +/* + * AAU structure. + */ +typedef struct _aau_ctrl_t { + spinlock_t aau_lock; /* lock for accessing AAU registers */ + struct list_head process_q; + struct list_head free_q; + spinlock_t process_lock; /* process queue lock */ + spinlock_t free_lock; /* hold queue lock */ + struct { + int EOT; + int EOC; + int ERR; + } irq; + const char *device_id; /* Device name */ + aau_regs_t regs; + sw_aau_t *last_desc; +} iop3xx_aau_t; + +#define SW_ENTRY(list) list_entry((list.next), sw_aau_t, link) + +#endif + diff -Nru a/arch/arm/mach-iop3xx/arch.c b/arch/arm/mach-iop3xx/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/arch.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,64 @@ +/* + * linux/arch/arm/mach-iop3xx/arch.c + * + * Author: Nicolas Pitre + * Copyright (C) 2001-2003 MontaVista Software, Inc. + * + * Maintainer: Deepak Saxena + * + * 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 + +#ifdef CONFIG_ARCH_IQ80310 +extern void iq80310_map_io(void); +extern void iq80310_init_irq(void); +#endif + +#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244) +extern void iq80321_map_io(void); +extern void iop321_init_irq(void); +#endif + +#ifdef CONFIG_ARCH_IQ80310 +MACHINE_START(IQ80310, "Cyclone IQ80310") + MAINTAINER("MontaVista Software Inc.") + BOOT_MEM(0xa0000000, 0xfe000000, 0xfe000000) + BOOT_PARAMS(0xa0000100) + MAPIO(iq80310_map_io) + INITIRQ(iq80310_init_irq) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_IQ80321 +MACHINE_START(IQ80321, "Intel IQ80321") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(0xa0000000, 0xfe800000, 0xfe800000) + BOOT_PARAMS(0xa0000100) + MAPIO(iq80321_map_io) + INITIRQ(iop321_init_irq) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_IQ31244 +MACHINE_START(IQ31244, "Intel IQ31244") + MAINTAINER("Nobody") + BOOT_MEM(0xa0000000, 0xfe800000, 0xfe800000) + BOOT_PARAMS(0xa0000100) + MAPIO(iq80321_map_io) + INITIRQ(iop321_init_irq) +MACHINE_END +#endif diff -Nru a/arch/arm/mach-iop3xx/dma.c b/arch/arm/mach-iop3xx/dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/dma.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,977 @@ +/************************************************************************** + * + * arch/arm/mach-iop310/dma.c + * + * Support functions for the Intel 80312 DMA channels. + * (see also Documentation/arm/XScale/iop310/dma.txt) + * + * Design inspired by the SA1100 DMA code by Nicolas Pitre + * Generic DMA ATU setup sample code provided by Larry Stewart + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2001 Intel 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. + * + * Todos: Thorough Error handling (no FIQ support yet) + * Do zero-size DMA transfer/channel at init + * so all we have to do is chainining + * + * + * History: (06/26/2001, DJ) Initial Creation + * (07/06/2001, DJ) Use __raw_(read/write)l() instead of + * memory mapped register because they aren't working yet + * (07/12/2001, DJ) Hooked DMA to INTD. Need their own INTs. + * (not anymore since 2.4.7-rmk3-iop310.1-dj1) + * (07/19/2001, DJ) Fixed some logic stuff after doing AAU. + * (08/22/2001, DJ) Changed spinlock calls to no save flags + * (08/27/2001, DJ) Added irq threshold handling + * (09/07/2001, DJ) Added cached/non-cached support, changed + * data structure to use list.h from Linux kernel, the API + * sleep now instead of requiring user to. slight API + * interface changes. Added mid-chain int notification + * support. User can also select the appropriate PCI + * commands. + * (09/10/2001, DJ) Made DMA descriptor embed in user SGL. + * Removed significant amount of data copying. User + * procedures a bit more exposed to hardware operation in + * trade off of performance. + * (10/11/2001, DJ) Added cache invalidate before hardware touches + * it to prevent data corruption. + *************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * pick up local definitions + */ +#include "dma.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#include +#endif + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK(s, args...) printk("80310DMA: " s, ## args) +#else +#define DPRINTK(s, args...) +#endif + +/* globals */ +static iop310_dma_t dma_chan[MAX_IOP310_DMA_CHANNEL]; /* DMA channels */ +static struct list_head dma_free_stack; /* free DMA descriptor stack */ +static spinlock_t dma_free_lock; /* free DMA stack lock */ + +/* static prototypes */ +static inline int dma_start(iop310_dma_t *, sw_dma_t *); +static void dma_task(void *); +static void dma_irq_handler(int, void *, struct pt_regs *); +static void dma_process(iop310_dma_t *); + +/*=======================================================================*/ +/* Procedure: dma_start() */ +/* */ +/* Description: This function starts the DMA engine. If the DMA */ +/* has already started then chain resume will be done */ +/* */ +/* Parameters: dma: DMA channel device */ +/* dma_chain: DMA data chain to pass to DMAC */ +/* */ +/* Returns: int -- success: 0 */ +/* failure: -EBUSY */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +static int dma_start(iop310_dma_t * dma, sw_dma_t * dma_chain) +{ + u32 status; + + status = *(dma->reg_addr.CSR); + + /* check channel status error */ + if(status & DMA_CSR_ERR_MASK) + { + DPRINTK("start: Channel Error %x\n", status); + /* should clean the channel up then, or let int handle it? */ + return -EBUSY; + } + + /* if channel not active */ + if(!(status & DMA_CSR_CH_ACTIVE)) + { + /* set the next descriptor address register */ + DPRINTK("Start at phys: %#x\n", dma_chain->dma_phys); + *(dma->reg_addr.NDAR) = dma_chain->dma_phys; + + DPRINTK("Enabling channel now\n"); + + *(dma->reg_addr.CCR) = DMA_CCR_CHANNEL_ENABLE; + } + else + { + DPRINTK("Resuming chain\n"); + /* if active, chain up to last DMA chain */ + + dma->last_desc->dma_desc.NDAR = (u32) dma_chain->dma_phys; + + /* flush cache since we changed field */ + cpu_dcache_clean_range((u32)&dma->last_desc->dma_desc.NDAR, + (u32)(&dma->last_desc->dma_desc.NDAR + 1)); + + /* resume the chain */ + *(dma->reg_addr.CCR) |= DMA_CCR_CHAIN_RESUME; + } + + /* set the last channel descriptor to last descriptor in chain */ + dma->last_desc = dma_chain->tail; + + return 0; +} + +/*=======================================================================*/ +/* Procedure: dma_task() */ +/* */ +/* Description: This function is the bottom half hdlr of the DMA INT */ +/* handler. It is queued as an imm task on the imm */ +/* task Q. It process all the complete DMA chain in the */ +/* holding Q and wakes up the user and free the resource*/ +/* */ +/* Parameters: data: DMA device as parameter */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +static void dma_task(void *data) +{ + iop310_dma_t *dma = (iop310_dma_t *) data; + u8 end_chain = 0; + sw_dma_t *sw_desc = NULL; + dma_head_t *listhead = NULL; + + DPRINTK("Entering dma_task()\n"); + if(!list_empty(&dma->hold_q)) + { + sw_desc = SW_ENTRY(dma->hold_q.next); + listhead = (dma_head_t *) sw_desc->sgl_head; + } + else + { + DPRINTK("List empty!\n"); + return; + } + + DPRINTK("SW Desc: %#x\n", (u32) sw_desc); + /* process while DMA chain is complete */ + while(sw_desc && + (sw_desc->tail->status & (DMA_NOTIFY | DMA_INCOMPLETE))) + { + /* clean up until end of DMA chain */ + while(!end_chain) + { + /* IE indicates end of chain or int per user request */ + /* DMA_COMPLETE denotes end of real chain */ + if(sw_desc->dma_desc.DC & DMA_DCR_IE) + { + end_chain = 1; + /* set the user list status as done */ + listhead->status |= + sw_desc->tail->status & DMA_USER_MASK; + sw_desc->status |= DMA_NOTIFY; + + if(sw_desc->status & DMA_END_CHAIN) + { + listhead->status |= DMA_COMPLETE; + } + } + + DPRINTK("Remove from holding Q\n"); + spin_lock_irq(&dma->hold_lock); + /* remove from holding queue */ + list_del(&sw_desc->link); + spin_unlock_irq(&dma->hold_lock); + + cpu_dcache_invalidate_range((u32)&sw_desc->dma_desc, + (u32)&sw_desc->dma_desc + DMA_DESC_SIZE); + + + DPRINTK("Cleaning up\n"); + sw_desc->head = NULL; + sw_desc->tail = NULL; + + DPRINTK("Look at another descriptor\n"); + if(!list_empty(&dma->hold_q)) + { + /* peek at next descriptor */ + sw_desc = SW_ENTRY(dma->hold_q.next); + listhead = (dma_head_t *) sw_desc->sgl_head; + } + else + { + sw_desc = NULL; + } + } + + /* reset chain */ + end_chain = 0; + + DPRINTK("----List status: %#x\n", listhead->status); + /* wake up user function waiting for return */ + if(listhead->callback) + { + listhead->callback(listhead); + } + else if(listhead->status & DMA_COMPLETE) + /*if(waitqueue_active(&dma->wait_q)) */ + { + DPRINTK("Waking up waiting process\n"); + wake_up_interruptible(&dma->wait_q); + } + } /* end while */ + + DPRINTK("Exiting DMA task\n"); +} + +/*=======================================================================*/ +/* Procedure: dma_irq_handler() */ +/* */ +/* Description: This function is the interrupt handler for the DMA */ +/* driver. It removes the done DMA descriptors from the */ +/* process Q and put them on the holding Q. it will */ +/* continue to process until process queue empty or the */ +/* current DMA desc on the DMAC is the one we are */ +/* inspecting */ +/* */ +/* Parameters: irq: IRQ activated */ +/* dev_id: device */ +/* regs: registers */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: Interupt is masked. No error handling is done. */ +/* Errors should be done with the FIQ handler, which */ +/* is not supported currently. */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/* Dave Jiang 07/20/01 Check INT instead of CSR for more INT*/ +/*=======================================================================*/ +static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + iop310_dma_t *dma = (iop310_dma_t *) dev_id; + u32 irq_status = 0; + u32 status = 0; + u32 thresh; + + irq_status = *(IOP310_FIQ1ISR); + + if(!(irq_status & DMA_INT_MASK)) + { + return; + } + DPRINTK("IRQ: irq=%d status=%#x\n", irq, irq_status); + + status = *(dma->reg_addr.CSR); + + thresh = atomic_read(&dma->irq_thresh); + + + DPRINTK("CSR: %#x\n", status); + DPRINTK("Thresh: %d\n", thresh); + /* while we continue to get DMA INTs */ + while((irq_status & DMA_INT_MASK) && thresh--) + { + /* clear CSR */ + *(dma->reg_addr.CSR) |= DMA_CSR_DONE_MASK; + + dma_process(dma); + + status = *(dma->reg_addr.CSR); + irq_status = *(IOP310_FIQ1ISR); + } + + /* schedule bottom half */ + dma->dma_task.data = (void *)dma; + /* task goes to the immediate task queue */ + queue_task(&dma->dma_task, &tq_immediate); + /* mark IMMEDIATE BH for execute */ + mark_bh(IMMEDIATE_BH); +} + +/*=======================================================================*/ +/* Procedure: dma_process() */ +/* */ +/* Description: This function processes moves all the dma desc in */ +/* the processing queue that are considered done to the */ +/* holding Q. It is called by the interrupt when the */ +/* done INTs are asserted. It will continue to process */ +/* until either the process queue is empty or current */ +/* DMA desc equals to the one in the DMAC */ +/* */ +/* Parameters: dma: DMA device as parameter */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: Interrupt is masked */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +static void dma_process(iop310_dma_t * dma) +{ + sw_dma_t *sw_desc; + u8 same_addr = 0; + + DPRINTK("Entering dma_process()\n"); + + while(!same_addr && !list_empty(&dma->process_q)) + { + spin_lock(&dma->process_lock); + /* peek the head of the queue */ + sw_desc = SW_ENTRY(dma->process_q.next); + list_del(dma->process_q.next); + spin_unlock(&dma->process_lock); + + if(sw_desc->head->tail->status & DMA_NEW_HEAD) + { + DPRINTK("Process new head\n"); + sw_desc->tail->head = sw_desc; + sw_desc->head = sw_desc; + sw_desc->tail->status &= ~DMA_NEW_HEAD; + } + + sw_desc->status |= DMA_DESC_DONE; + /* if we see end of chain, we set head status to DONE */ + if(sw_desc->dma_desc.DC & DMA_DCR_IE) + { + DPRINTK("INT flag found!\n"); + if(sw_desc->status & DMA_END_CHAIN) + { + DPRINTK("chain complete\n"); + sw_desc->tail->status |= DMA_COMPLETE; + } + else + { + DPRINTK("mid chain flag\n"); + sw_desc->head->tail = sw_desc; + sw_desc->tail = sw_desc; + sw_desc->tail->status |= DMA_NEW_HEAD; + } + sw_desc->tail->status |= DMA_NOTIFY; + } + + DPRINTK("Check if current processing\n"); + /* if descriptor equal same being proccessed, put it back */ + if(((u32) sw_desc == *(dma->reg_addr.DAR)) && + (*(dma->reg_addr.CSR) & DMA_CSR_CH_ACTIVE)) + { + spin_lock(&dma->process_lock); + list_add(&sw_desc->link, &dma->process_q); + spin_unlock(&dma->process_lock); + same_addr = 1; + } + else + { + DPRINTK("Add descriptor: %#x\n", (u32) sw_desc); + spin_lock(&dma->hold_lock); + /* push descriptor in hold Q */ + list_add_tail(&sw_desc->link, &dma->hold_q); + spin_unlock(&dma->hold_lock); + } + } + + DPRINTK("Exiting dma_process()\n"); +} + +/*=======================================================================*/ +/* Procedure: dma_request() */ +/* */ +/* Description: This function requests a DMA chan depend on the bus. */ +/* The bus could be primary PCI or secondary. Currently */ +/* this parameter acts as a DMA channel selector */ +/* */ +/* Parameters: channel: DMA channel */ +/* device_id: device ID */ +/* */ +/* Returns: int - channel # */ +/* -EINVAL: no such DMA channel exist */ +/* -EBUSY: can't allocate irq */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/* Dave Jiang 9/02/01 Interface changed */ +/*=======================================================================*/ +int dma_request(dmach_t channel, const char *device_id) +{ + iop310_dma_t *dma = NULL; + int ch = channel; + int err; + + if(channel >= MAX_IOP310_DMA_CHANNEL) + { + return -EINVAL; + } + + dma = &dma_chan[ch]; + atomic_inc(&dma->ref_count); + + /* get interrupt if ref count is less than or equal to 1 */ + if(atomic_read(&dma->ref_count) <= 1) + { + /* request IRQ for the channel */ + err = request_irq(dma->irq, dma_irq_handler, SA_INTERRUPT, + device_id, (void *)dma); + if(err < 0) + { + printk(KERN_ERR "%s: unable to request IRQ %d for \ + DMA channel %d: %d\n", device_id, dma->irq, ch, err); + dma->lock = 0; + atomic_set(&dma->ref_count, 0); + return -EBUSY; + } + dma->device_id = device_id; + } + + return ch; +} + +/*=======================================================================*/ +/* Procedure: dma_queue_buffer() */ +/* */ +/* Description: This function creates a DMA buffer chain from the */ +/* user supplied SGL chain. It also puts the DMA chain */ +/* onto the processing queue. DMA enable will be called */ +/* by this func */ +/* */ +/* Parameters: channel: DMA channel */ +/* listhead: User SGL (kernel memory) */ +/* */ +/* Returns: int: success -- 0 */ +/* dma_start() condition */ +/* */ +/* Notes/Assumptions: User SGL must point to kernel memory, not user */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +int dma_queue_buffer(dmach_t channel, dma_head_t * listhead) +{ + sw_dma_t *sw_desc = (sw_dma_t *) listhead->list; + sw_dma_t *prev_desc = NULL; + sw_dma_t *head = NULL; + dma_head_t *sgl_head = listhead; + int err = 0; + iop310_dma_t *dma = &dma_chan[channel]; + DECLARE_WAIT_QUEUE_HEAD(wait_q); + + /* scan through entire user SGL */ + DPRINTK("Enter dma_queue_buffer()\n"); + while(sw_desc) + { + DPRINTK("Putting descriptor in process Q\n"); + /* get DMA descriptor */ + + DPRINTK("sw_desc: %#x\n", (u32) sw_desc); + sw_desc->sgl_head = (u32) listhead; + + /* we clean the cache for previous descriptor in chain */ + if(prev_desc) + { + /* prev_desc->dma_desc.NDAR = (u32)sw_desc->dma_phys; */ + cpu_dcache_clean_range((u32)&prev_desc->dma_desc, + (u32)&prev_desc->dma_desc + DMA_DESC_SIZE); + + } + else + { + /* no previous descriptor, so we set this to be head */ + head = sw_desc; + } + + sw_desc->head = head; + /* set previous to current */ + prev_desc = sw_desc; + + /* put descriptor on process Q */ + DPRINTK("Adding swdesc: %#x\n", (u32) sw_desc); + spin_lock_irq(&dma->process_lock); + list_add_tail(&sw_desc->link, &dma->process_q); + spin_unlock_irq(&dma->process_lock); + + /* go to next SGL */ + sw_desc = (sw_dma_t *) sw_desc->next; + } + DPRINTK("Done setting up descriptor list\n"); + + /* if our tail exists */ + if(prev_desc) + { + /* set the head pointer on tail */ + prev_desc->head = head; + /* set the header pointer's tail to tail */ + head->tail = prev_desc; + prev_desc->tail = prev_desc; + + /* clean cache for tail */ + cpu_dcache_clean_range((u32)&prev_desc->dma_desc, + (u32)&prev_desc->dma_desc + DMA_DESC_SIZE); + + DPRINTK("Starting DMA engine\n"); + /* start the DMA */ + DPRINTK("Starting at chain: 0x%x\n", (u32) head); + if((err = dma_start(dma, head)) < 0) + { + DPRINTK("dma_start() failed\n"); + return err; + } + else + { + if(!sgl_head->callback) + { + wait_event_interruptible(dma->wait_q, + (sgl_head->status & DMA_COMPLETE)); + DPRINTK("----W0EN: %#x\n", sgl_head->status); + } + return 0; + } + } + else + { + DPRINTK("What happened to the chain?\n"); + } + + return -EINVAL; +} + + +/*=======================================================================*/ +/* Procedure: dma_suspend() */ +/* */ +/* Description: This function stops the DMA at the earliest instant */ +/* it is capable of. It actually suspends operation. */ +/* */ +/* Parameters: channel: DMA channel */ +/* */ +/* Returns: int: success -- 0 */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +int dma_suspend(dmach_t channel) +{ + iop310_dma_t *dma = &dma_chan[channel]; + + /* remove channel enable bit */ + *(dma->reg_addr.CCR) &= ~DMA_CCR_CHANNEL_ENABLE; + + return 0; +} + +/*=======================================================================*/ +/* Procedure: dma_resume() */ +/* */ +/* Description: This function resumes the DMA operations */ +/* */ +/* Parameters: channel: DMA channel */ +/* */ +/* Returns: int: success -- 0 */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +int dma_resume(dmach_t channel) +{ + iop310_dma_t *dma = &dma_chan[channel]; + + /* set channel enable bit */ + *(dma->reg_addr.CCR) |= DMA_CCR_CHANNEL_ENABLE; + return 0; +} + +/*=======================================================================*/ +/* Procedure: dma_flush_all() */ +/* */ +/* Description: This function flushes the entire process Q for the */ +/* DMA channel in question. It also clears the DMAC. */ +/* */ +/* Parameters: channel: DMA channel */ +/* */ +/* Returns: int: success -- 0 */ +/* */ +/* Notes/Assumptions: Interrupt is masked unless called by app */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +int dma_flush_all(dmach_t channel) +{ + iop310_dma_t *dma = &dma_chan[channel]; + int flags; + sw_dma_t *sw_desc; + + DPRINTK("Flushalll is being called\n"); + *(dma->reg_addr.CCR) = DMA_CCR_CLEAR; + *(dma->reg_addr.CSR) = (DMA_CSR_DONE_MASK | DMA_CSR_ERR_MASK); + + while(!list_empty(&dma->hold_q)) + { + spin_lock_irqsave(&dma->process_lock, flags); + sw_desc = SW_ENTRY(dma->process_q.next); + list_del(dma->process_q.next); + spin_unlock_irqrestore(&dma->process_lock, flags); + + /* set status to be incomplete */ + sw_desc->status |= DMA_INCOMPLETE; + /* put descriptor on holding queue */ + spin_lock_irqsave(&dma->hold_lock, flags); + list_add_tail(&sw_desc->link, &dma->hold_q); + spin_unlock_irqrestore(&dma->hold_lock, flags); + } + + return 0; +} + +/*=======================================================================*/ +/* Procedure: dma_free() */ +/* */ +/* Description: This function frees the DMA channel from usage. */ +/* */ +/* Parameters: channel: DMA channel */ +/* */ +/* Returns: int: success -- 0 */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/* Dave Jiang 7/20/01 Added more clean up code */ +/*=======================================================================*/ +void dma_free(dmach_t channel) +{ + iop310_dma_t *dma = &dma_chan[channel]; + + atomic_dec(&dma->ref_count); + + if(atomic_read(&dma->ref_count) <= 1) + { + /* flush DMA channel */ + dma_flush_all(dma->channel); + dma_task((void *)dma); + dma->ready = 0; + dma->last_desc = NULL; + + /* free the IRQ */ + free_irq(dma->irq, (void *)dma); + dma->lock = 0; + } + + DPRINTK("freed\n"); +} + +/*=======================================================================*/ +/* Procedure: dma_init() */ +/* */ +/* Description: This function initializes all the DMA channels. */ +/* */ +/* Parameters: NONE */ +/* */ +/* Returns: int: success -- 0 */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 6/26/01 Initial Creation */ +/*=======================================================================*/ +int __init dma_init(void) +{ + int channel; + int i; + sw_dma_t *sw_desc = NULL; + void *desc = NULL; + + printk("Intel 80310 DMA Copyright(c) 2001 Intel Corporation\n"); + DPRINTK("Initializing...\n"); + + /* init free stack */ + INIT_LIST_HEAD(&dma_free_stack); + /* init free stack spinlock */ + spin_lock_init(&dma_free_lock); + + /* pre-alloc DMA descriptors */ + for(i = 0; i < MAX_DMA_DESC; i++) + { + /* + * we keep track of original address before alignment + * adjust so we can free it later + */ + desc = kmalloc((sizeof(sw_dma_t) + 0x20), GFP_KERNEL); + memset(desc, 0, sizeof(sw_dma_t) + 0x20); + + /* + * hardware descriptors must be aligned on an + * 8-word boundary + */ + sw_desc = (sw_dma_t *) (((u32) desc & 0xffffffe0) + 0x20); + sw_desc->desc_addr = (u32) desc; + sw_desc->dma_phys = (u32) virt_to_phys(sw_desc); + + + /* put the descriptors on the free stack */ + spin_lock_irq(&dma_free_lock); + list_add(&sw_desc->link, &dma_free_stack); + spin_unlock_irq(&dma_free_lock); + } + + dma_chan[0].reg_addr.CCR = IOP310_DMA0CCR; + dma_chan[0].reg_addr.CSR = IOP310_DMA0CSR; + dma_chan[0].reg_addr.DAR = IOP310_DMA0DAR; + dma_chan[0].reg_addr.NDAR = IOP310_DMA0NDAR; + dma_chan[0].reg_addr.PADR = IOP310_DMA0PADR; + dma_chan[0].reg_addr.PUADR = IOP310_DMA0PUADR; + dma_chan[0].reg_addr.LADR = IOP310_DMA0LADR; + dma_chan[0].reg_addr.BCR = IOP310_DMA0BCR; + dma_chan[0].reg_addr.DCR = IOP310_DMA0DCR; + dma_chan[1].reg_addr.CCR = IOP310_DMA1CCR; + dma_chan[1].reg_addr.CSR = IOP310_DMA1CSR; + dma_chan[1].reg_addr.DAR = IOP310_DMA1DAR; + dma_chan[1].reg_addr.NDAR = IOP310_DMA1NDAR; + dma_chan[1].reg_addr.PADR = IOP310_DMA1PADR; + dma_chan[1].reg_addr.PUADR = IOP310_DMA1PUADR; + dma_chan[1].reg_addr.LADR = IOP310_DMA1LADR; + dma_chan[1].reg_addr.BCR = IOP310_DMA1BCR; + dma_chan[1].reg_addr.DCR = IOP310_DMA1DCR; + dma_chan[2].reg_addr.CCR = IOP310_DMA2CCR; + dma_chan[2].reg_addr.CSR = IOP310_DMA2CSR; + dma_chan[2].reg_addr.DAR = IOP310_DMA2DAR; + dma_chan[2].reg_addr.NDAR = IOP310_DMA2NDAR; + dma_chan[2].reg_addr.PADR = IOP310_DMA2PADR; + dma_chan[2].reg_addr.PUADR = IOP310_DMA2PUADR; + dma_chan[2].reg_addr.LADR = IOP310_DMA2LADR; + dma_chan[2].reg_addr.BCR = IOP310_DMA2BCR; + dma_chan[2].reg_addr.DCR = IOP310_DMA2DCR; + + /* set the IRQ */ + dma_chan[0].irq = IRQ_IOP310_DMA0; + dma_chan[1].irq = IRQ_IOP310_DMA1; + dma_chan[2].irq = IRQ_IOP310_DMA2; + + /* initialize all the channels */ + for(channel = 0; channel < MAX_IOP310_DMA_CHANNEL; channel++) + { + /* init channel lock to 0 */ + atomic_set(&dma_chan[channel].ref_count, 0); + dma_chan[channel].lock = 0; + + atomic_set(&dma_chan[channel].irq_thresh, + DEFAULT_DMA_IRQ_THRESH); + + /* init process Q */ + INIT_LIST_HEAD(&dma_chan[channel].process_q); + /* init holding Q */ + INIT_LIST_HEAD(&dma_chan[channel].hold_q); + /* init locks for Qs */ + spin_lock_init(&dma_chan[channel].hold_lock); + spin_lock_init(&dma_chan[channel].process_lock); + + dma_chan[channel].last_desc = NULL; + /* set the channel for DMA struct */ + dma_chan[channel].channel = channel; + + /* initialize BH task */ + dma_chan[channel].dma_task.sync = 0; + dma_chan[channel].dma_task.routine = (void *)dma_task; + + /* initialize wait Q */ + init_waitqueue_head(&dma_chan[channel].wait_q); + /* clear DMA channel control register */ + + *(dma_chan[channel].reg_addr.CCR) = DMA_CCR_CLEAR; + *(dma_chan[channel].reg_addr.CSR) |= + (DMA_CSR_DONE_MASK | DMA_CSR_ERR_MASK); + *(dma_chan[channel].reg_addr.NDAR) = 0; + } + + DPRINTK("DMA init Done!\n"); + return 0; +} + +/*=======================================================================*/ +/* Procedure: dma_set_irq_threshold() */ +/* */ +/* Description: This function sets the threshold for irq service. */ +/* this is how many times irq gets serviced before bail */ +/* so it wouldn't hog resources */ +/* */ +/* Parameters: channel: DMA channel */ +/* value: threshold value */ +/* */ +/* Returns: N/A */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 8/27/01 Initial Creation */ +/*=======================================================================*/ +void dma_set_irq_threshold(dmach_t channel, int value) +{ + iop310_dma_t *dma = &dma_chan[channel]; + + atomic_set(&dma->irq_thresh, value); +} /* End oi dma_set_irq_threshold() */ + +/*=======================================================================*/ +/* Procedure: dma_get_buffer() */ +/* */ +/* Description: This function acquires an SGL element for the user */ +/* and returns that. It will retry multiple times if no */ +/* descriptor is available. */ +/* */ +/* Parameters: channel: DMA channel */ +/* num_desc: number of descriptors */ +/* */ +/* Returns: N/A */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 9/10/01 Initial Creation */ +/* Dave Jiang 10/04/01 Fixed linking up of sgl list */ +/*=======================================================================*/ +dma_sgl_t *dma_get_buffer(dmach_t channel, int num_desc) +{ + sw_dma_t *sw_desc = NULL; + sw_dma_t *sw_head = NULL; + sw_dma_t *sw_prev = NULL; + + int retry = 10; + DECLARE_WAIT_QUEUE_HEAD(wait_q); + int i; + + if(num_desc > MAX_DMA_DESC) + { + DPRINTK("More descriptor requested than allocated\n"); + return NULL; + } + + for(i = num_desc; i > 0; i--) + { + spin_lock_irq(&dma_free_lock); + if(!list_empty(&dma_free_stack)) + { + sw_desc = SW_ENTRY(dma_free_stack.next); + list_del(dma_free_stack.next); + spin_unlock_irq(&dma_free_lock); + } + else + { + while(retry-- && !sw_desc) + { + spin_unlock_irq(&dma_free_lock); + interruptible_sleep_on_timeout(&wait_q, SLEEP_TIME); + spin_lock_irq(&dma_free_lock); + if(!list_empty(&dma_free_stack)) + { + sw_desc = SW_ENTRY(dma_free_stack.next); + list_del(dma_free_stack.next); + } + spin_unlock_irq(&dma_free_lock); + } + + if(!sw_desc) + { + printk(KERN_WARNING "80310 DMA: No more DMA descriptors"); + spin_lock_irq(&dma_free_lock); + if(sw_head) + { + sw_desc = sw_head; + while(sw_desc) + { + list_add(&sw_desc->link, &dma_free_stack); + sw_desc = (sw_dma_t *) sw_desc->next; + } + } + spin_unlock_irq(&dma_free_lock); + return NULL; + } + } + + if(sw_prev) + { + sw_prev->next = (dma_sgl_t *) sw_desc; + sw_prev->dma_desc.NDAR = sw_desc->dma_phys; + } + else + { + sw_head = sw_desc; + } + + sw_prev = sw_desc; + } + + sw_desc->dma_desc.NDAR = 0; + sw_desc->next = NULL; + sw_desc->status = 0; + + return (dma_sgl_t *) sw_head; +} + +/*=======================================================================*/ +/* Procedure: dma_return_buffer() */ +/* */ +/* Description: This function takes a list of SGL and return it to */ +/* the free stack. */ +/* */ +/* Parameters: channel: DMA channel */ +/* list: SGL list to return to free stack */ +/* */ +/* Returns: N/A */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 9/10/01 Initial Creation */ +/*=======================================================================*/ +void dma_return_buffer(dmach_t channel, dma_sgl_t * list) +{ + sw_dma_t *sw_desc = (sw_dma_t *) list; + + spin_lock_irq(&dma_free_lock); + while(sw_desc) + { + list_add(&sw_desc->link, &dma_free_stack); + sw_desc = (sw_dma_t *) sw_desc->next; + } + spin_unlock_irq(&dma_free_lock); + +} + +EXPORT_SYMBOL_NOVERS(dma_request); +EXPORT_SYMBOL_NOVERS(dma_queue_buffer); +EXPORT_SYMBOL_NOVERS(dma_suspend); +EXPORT_SYMBOL_NOVERS(dma_resume); +EXPORT_SYMBOL_NOVERS(dma_free); +EXPORT_SYMBOL_NOVERS(dma_set_irq_threshold); +EXPORT_SYMBOL_NOVERS(dma_get_buffer); +EXPORT_SYMBOL_NOVERS(dma_return_buffer); + +module_init(dma_init); diff -Nru a/arch/arm/mach-iop3xx/dma.h b/arch/arm/mach-iop3xx/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/dma.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,130 @@ +/* + * Private Definitions for XScale DMA + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2001 Intel 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. + * + */ + +#ifndef _DMA_PRIVATE_H_ +#define _DMA_PRIVATE_H_ + +#define DEFAULT_DMA_IRQ_THRESH 10 + +#define DMA_DESC_SIZE 24 + +#define SLEEP_TIME 50 + +#define DESC_DONE DMA_DONE +#define DESC_INCOMPLETE DMA_INCOMPLETE +#define DESC_HEAD 0x0010 +#define DESC_TAIL 0x0020 + +#define DMA_INT_0 0x01 +#define DMA_INT_1 0x02 +#define DMA_INT_2 0x04 +#define DMA_INT_MASK (DMA_INT_0 | DMA_INT_1 | DMA_INT_2) + +#define DMA_CCR_CLEAR 0x00000000 +#define DMA_CCR_CHANNEL_ENABLE 0x00000001 +#define DMA_CCR_CHAIN_RESUME 0x00000002 + +#define DMA_CSR_PCI_PAR_ERROR 0x00000001 +#define DMA_CSR_PCI_TGT_ABORT 0x00000004 +#define DMA_CSR_PCI_MST_ABORT 0x00000008 +#define DMA_CSR_INT_MST_ABORT 0x00000020 +#define DMA_CSR_EOC_INT 0x00000100 +#define DMA_CSR_EOT_INT 0x00000200 +#define DMA_CSR_CH_ACTIVE 0x00000400 +#define DMA_CSR_DONE_MASK (DMA_CSR_EOC_INT | DMA_CSR_EOT_INT) + +#define DMA_CSR_ERR_MASK (DMA_CSR_PCI_PAR_ERROR | \ + DMA_CSR_PCI_TGT_ABORT | \ + DMA_CSR_PCI_MST_ABORT | \ + DMA_CSR_INT_MST_ABORT) + +#define DMA_CSR_DONE_MASK (DMA_CSR_EOC_INT | DMA_CSR_EOT_INT) + +/* + * DMA Software Descriptor + */ +typedef struct _sw_dma +{ + dma_desc_t dma_desc; /* DMA descriptor pointer */ + u32 status; + void *data; /* local virt */ + struct _dma_sgl *next; /* next descriptor */ + struct list_head link; + u32 sw_desc; /* parent address */ + u32 dma_phys; /* Physical address of DMA */ + u32 desc_addr; /* desc unaligned alloc addr */ + u32 sgl_head; /* user SG head */ + struct _sw_dma *tail; /* chain tail */ + struct _sw_dma *head; /* chain head */ +} sw_dma_t; + +/* + * DMA control register structure + */ +typedef struct _dma_regs +{ + volatile u32 CCR; /* channel control register */ + volatile u32 CSR; /* channel status register */ + volatile u32 DAR; /* descriptor address register */ + volatile u32 NDAR; /* next descriptor address register */ + volatile u32 PADR; /* PCI address register */ + volatile u32 PUADR; /* upper PCI address register */ + volatile u32 LADR; /* local address register */ + volatile u32 BCR; /* byte count register */ + volatile u32 DCR; /* descriptor control register */ +} dma_regs_t; + + +/* + * DMA channel structure. + */ + +typedef struct _dmac_ctrl_t +{ + dmach_t channel; /* channel */ + u32 lock; /* Device is allocated */ + struct list_head process_q; + struct list_head hold_q; + spinlock_t process_lock; /* process queue lock */ + spinlock_t hold_lock; /* hold queue lock */ + int ready; /* 1 if DMA can occur */ + int active; /* 1 if DMA is processing data */ + int irq; /* IRQ used by the channel */ + atomic_t ref_count; /* resource count for DMA */ +#ifndef REGMAP + struct /* register offset */ + { + volatile u32 *CCR; /* channel control register */ + volatile u32 *CSR; /* channel status register */ + volatile u32 *DAR; /* descriptor address register */ + volatile u32 *NDAR; /* next descriptor address register */ + volatile u32 *PADR; /* PCI address register */ + volatile u32 *PUADR; /* upper PCI address register */ + volatile u32 *LADR; /* local address register */ + volatile u32 *BCR; /* byte count register */ + volatile u32 *DCR; /* descriptor control register */ + } + reg_addr; +#endif + atomic_t last_dma_lock; /* last DMA descriptor lock */ + atomic_t irq_thresh; + wait_queue_head_t wait_q; /* wait queue for user to sleep on */ + struct tq_struct dma_task; /* tasklet */ + sw_dma_t *last_desc; /* last descriptor for DMAC */ + dma_regs_t *regs; /* points to DMA registers */ + const char *device_id; /* Device name */ +} iop310_dma_t; + +#define SW_ENTRY(list) list_entry((list), sw_dma_t, link) + +#endif + /*EOF*/ diff -Nru a/arch/arm/mach-iop3xx/iop310-irq.c b/arch/arm/mach-iop3xx/iop310-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iop310-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,110 @@ +/* + * linux/arch/arm/mach-iop3xx/iop310-irq.c + * + * Generic IOP310 IRQ handling functionality + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * Added IOP310 chipset and IQ80310 board demuxing, masking code. - DS + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +extern void xs80200_irq_mask(unsigned int); +extern void xs80200_irq_unmask(unsigned int); +extern void xs80200_init_irq(void); + +extern void do_IRQ(int, struct pt_regs *); + +u32 iop310_mask = 0; + +static void +iop310_irq_mask (unsigned int irq) +{ + iop310_mask |= (1 << (irq - IOP310_IRQ_OFS)); + + /* + * No mask bits on the 80312, so we have to + * mask everything from the outside! + */ + xs80200_irq_mask(IRQ_XS80200_EXTIRQ); +} + +static void +iop310_irq_unmask (unsigned int irq) +{ + iop310_mask &= ~(1 << (irq - IOP310_IRQ_OFS)); + + /* + * Check if all 80312 sources are unmasked now + */ + if(!iop310_mask) + { + xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); + + } +} + +void iop310_irq_demux(int irq, void *dev_id, + struct pt_regs *regs) +{ + u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR); + u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR); + unsigned int irqno = 0xdeadbeef; + + if(fiq1isr) + { + if(fiq1isr & 0x1) + irqno = IRQ_IOP310_DMA0; + if(fiq1isr & 0x2) + irqno = IRQ_IOP310_DMA1; + if(fiq1isr & 0x4) + irqno = IRQ_IOP310_DMA2; + if(fiq1isr & 0x10) + irqno = IRQ_IOP310_PMON; + if(fiq1isr & 0x20) + irqno = IRQ_IOP310_AAU; + } + else + { + if(fiq2isr & 0x2) + irqno = IRQ_IOP310_I2C; + if(fiq2isr & 0x4) + irqno = IRQ_IOP310_MU; + } + + if(irqno != 0xdeadbeef) + do_IRQ(irqno, regs); +} + +void __init iop310_init_irq(void) +{ + int i; + + for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++) + { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = iop310_irq_mask; + irq_desc[i].mask = iop310_irq_mask; + irq_desc[i].unmask = iop310_irq_unmask; + } + + xs80200_init_irq(); +} + diff -Nru a/arch/arm/mach-iop3xx/iop310-pci.c b/arch/arm/mach-iop3xx/iop310-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iop310-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,354 @@ +/* + * arch/arm/mach-iop3xx/iop310-pci.c + * + * PCI support for the Intel IOP310 chipset + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +int iop310_pci_abort_handler(unsigned long, unsigned long, struct pt_regs *); + +int iop310_host; + +void iop310_init(void) +{ + DBG("PCI: Intel 80312 PCI-to-PCI init code.\n"); + DBG("\tATU secondary: IOP310_SOMWVR=0x%04x, IOP310_SOIOWVR=0x%04x\n", + *IOP310_SOMWVR, + *IOP310_SOIOWVR); + DBG("\tATU secondary: IOP310_ATUCR=0x%08x\n", *IOP310_ATUCR); + DBG("\tATU secondary: IOP310_SIABAR=0x%08x IOP310_SIALR=0x%08x IOP310_SIATVR=%08x\n", *IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR); + + DBG("\tATU primary: IOP310_POMWVR=0x%04x, IOP310_POIOWVR=0x%04x\n", + *IOP310_POMWVR, + *IOP310_POIOWVR); + DBG("\tATU secondary: IOP310_PIABAR=0x%08x IOP310_PIALR=0x%08x IOP310_PIATVR=%08x\n", *IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR); + + DBG("\tP2P: IOP310_PCR=0x%04x IOP310_BCR=0x%04x IOP310_EBCR=0x%04x\n", *IOP310_PCR, *IOP310_BCR, *IOP310_EBCR); + + /* + * Windows have to be carefully opened via a nice set of calls + * here or just some direct register fiddling in the board + * specific init when we want transactions to occur between the + * two PCI hoses. + * + * To do this, we will have manage RETRY assertion between the + * firmware and the kernel. This will ensure that the host + * system's enumeration code is held off until we have tweaked + * the interrupt routing and public/private IDSELs. + * + * For now we will simply default to disabling the integrated type + * 81 P2P bridge. + */ + *IOP310_PCR &= 0xfff8; + + hook_fault_code(4, iop310_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(6, iop310_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(8, iop310_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); + hook_fault_code(10, iop310_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); + +} + +/* + * This routine builds either a type0 or type1 configuration command. If the + * bus is on the 80312 then a type0 made, else a type1 is created. + */ +static inline u32 iop310_pci_config_setup(struct pci_dev *dev, int where) +{ + volatile u32 *paddress; + volatile u32 *pdata; + struct pci_controller *hose; + + DBG("\tPCI: config_setup of bus %d\n", dev->bus->number); + + /* + * Get appropriate cfga/cfgd values from hose + */ + hose = pci_bus_to_hose(dev->bus->number); + paddress = (u32 *)hose->cfg_addr; + pdata = (u32 *)hose->cfg_data; + + /* locations must be dword-aligned */ + where &= ~3; + + /* + * For top bus generate a type 0 config, + * all others use a type 1 config + */ + if (dev->bus->number == hose->first_busno) + { + *paddress = ( (1 << (PCI_SLOT(dev->devfn) + 16)) | + (PCI_FUNC(dev->devfn) << 8) | where | 0 ); + } + else + { + *paddress = ( (dev->bus->number << 16) | + (PCI_SLOT(dev->devfn) << 11) | + (PCI_FUNC(dev->devfn) << 8) | where | 1 ); + } + + return (u32)pdata; +} + +/* + * This routine checks the status of the last configuration cycle. If an error + * was detected it returns a 1, else it returns a 0. The errors being checked + * are parity, master abort, target abort (master and target). These types of + * errors occure during a config cycle where there is no device, like during + * the discovery stage. + */ +static int iop310_pci_config_cleanup(u8 bus) +{ + u32 status = 0, err = 0; + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + + /* + * If our hose is using the primary CFGA then check the + * primary status registers, otherwise check the relevant + * secondary status registers. + */ + if (hose->cfg_addr == (unsigned int *)IOP310_POCCAR) + { + status = *IOP310_PATUSR; + if (status & 0xF900) + { + DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status); + err = 1; + *IOP310_PATUSR = status & 0xF980; + } + status = *IOP310_PATUISR; + if (status & 0x79F) + { + DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status); + err = 1; + *IOP310_PATUISR = status & 0x79f; + } + status = *IOP310_PSR; + if (status & 0xF900) + { + DBG("\t\t\tPCI: P2 - status = 0x%08x\n", status); + err = 1; + *IOP310_PSR = status & 0xF980; + } + status = *IOP310_PBISR; + if (status & 0x3F) + { + DBG("\t\t\tPCI: P3 - status = 0x%08x\n", status); + err = 1; + *IOP310_PBISR = status & 0x3F; + } + } + else + { + status = *IOP310_SATUSR; + if (status & 0xF900) + { + DBG("\t\t\tPCI: S0 - status = 0x%08x\n", status); + err = 1; + *IOP310_SATUSR = status & 0xF900; + } + status = *IOP310_SATUISR; + if (status & 0x69F) + { + DBG("\t\t\tPCI: S1 - status = 0x%08x\n", status); + err = 1; + *IOP310_SATUISR= status & 0x69F; + } + } + + return err; +} + +/* + * The read routines must check the error status of the last configuration + * cycle. If there was an error, the routine returns all hex f's. + */ +static int +iop310_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + u32 *pdata; + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + + *value = (u8) (((*pdata) >> ((where % 0x04) * 8)) & 0xff); + + if( iop310_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + u32 *pdata; + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + *value = (u16) (((*pdata) >> ((where % 0x04) * 8)) & 0xffff); + if( iop310_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xffff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + u32 *pdata; + u8 scratch_pad[5]; /* used to fix dword PCI problem */ + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + *value = *pdata; + + /* Workaround for timing problem errata on 80312 */ + sprintf(scratch_pad, "bugs"); + + if( iop310_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xffffffff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + u32 *pdata; + u32 mask; + u32 temp; + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + mask = ~(0x000000ff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where% 0x4) * 8)); + *pdata = (*pdata & mask) | temp; + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + u32 *pdata; + u32 mask; + u32 temp; + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + mask = ~(0x0000ffff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) * 8)); + *pdata = (*pdata & mask) | temp; + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + u32 *pdata; + + cli(); + + pdata = (u32 *)iop310_pci_config_setup(dev, where); + *pdata = value; + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops iop310_ops = { + iop310_read_config_byte, + iop310_read_config_word, + iop310_read_config_dword, + iop310_write_config_byte, + iop310_write_config_word, + iop310_write_config_dword, +}; + +/* + * When a PCI device does not exist during config cycles, the 80200 gets a + * bus error instead of returning 0xffffffff. This handler simply returns. + */ +int +iop310_pci_abort_handler(unsigned long addr, unsigned long fsr, struct pt_regs *regs) +{ + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return iop310_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) diff -Nru a/arch/arm/mach-iop3xx/iop321-irq.c b/arch/arm/mach-iop3xx/iop321-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iop321-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/mach-iop3xx/iop321-irq.c + * + * Generic IOP321 IRQ handling functionality + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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. + * + * Added IOP3XX chipset and IQ80321 board masking code. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static u32 iop321_mask = 0; + +static void +iop321_irq_mask (unsigned int irq) +{ + + iop321_mask &= ~(1 << (irq - IOP321_IRQ_OFS)); + + intctl_write(iop321_mask); +} + +static void +iop321_irq_unmask (unsigned int irq) +{ + iop321_mask |= (1 << (irq - IOP321_IRQ_OFS)); + + intctl_write(iop321_mask); +} + +void __init iop321_init_irq(void) +{ + int i; + + intctl_write(0); // disable all interrupts + intstr_write(0); // treat all as IRQ + + // all interrupts are inputs to chip + if(machine_is_iq80321() || machine_is_iq31244()) + *IOP321_PCIIRSR = 0x0f; + + for(i = IOP321_IRQ_OFS; i < NR_IOP321_IRQS; i++) + { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = iop321_irq_mask; + irq_desc[i].mask = iop321_irq_mask; + irq_desc[i].unmask = iop321_irq_unmask; + } +} + diff -Nru a/arch/arm/mach-iop3xx/iop321-pci.c b/arch/arm/mach-iop3xx/iop321-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iop321-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,314 @@ +/* + * arch/arm/mach-iop3xx/iop321-pci.c + * + * PCI support for the Intel IOP321 chipset + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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 +#include +#include + +// #define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +int iop321_pci_abort_handler(unsigned long, unsigned long, struct pt_regs *); + +void iop321_init(void) +{ + DBG("PCI: Intel 80321 PCI init code.\n"); + DBG("\tATU: IOP321_ATUCMD=0x%04x\n", *IOP321_ATUCMD); + DBG("\tATU: IOP321_OMWTVR0=0x%04x, IOP321_OIOWTVR=0x%04x\n", + *IOP321_OMWTVR0, + *IOP321_OIOWTVR); + DBG("\tATU: IOP321_ATUCR=0x%08x\n", *IOP321_ATUCR); + DBG("\tATU: IOP321_IABAR0=0x%08x IOP321_IALR0=0x%08x IOP321_IATVR0=%08x\n", *IOP321_IABAR0, *IOP321_IALR0, *IOP321_IATVR0); + DBG("\tATU: IOP321_ERBAR=0x%08x IOP321_ERLR=0x%08x IOP321_ERTVR=%08x\n", *IOP321_ERBAR, *IOP321_ERLR, *IOP321_ERTVR); + DBG("\tATU: IOP321_IABAR2=0x%08x IOP321_IALR2=0x%08x IOP321_IATVR2=%08x\n", *IOP321_IABAR2, *IOP321_IALR2, *IOP321_IATVR2); + DBG("\tATU: IOP321_IABAR3=0x%08x IOP321_IALR3=0x%08x IOP321_IATVR3=%08x\n", *IOP321_IABAR3, *IOP321_IALR3, *IOP321_IATVR3); + + hook_fault_code(4, iop321_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(6, iop321_pci_abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(8, iop321_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); + hook_fault_code(10, iop321_pci_abort_handler, SIGBUS, "external abort on non-line fetch\n"); +} + +/* + * This routine builds either a type0 or type1 configuration command. If the + * bus is on the 80321 then a type0 made, else a type1 is created. + */ +static inline u32 iop321_pci_config_setup(struct pci_dev *dev, int where) +{ + volatile u32 *paddress; + volatile u32 *pdata; + struct pci_controller *hose; + + DBG("\tPCI: config_setup of bus %d\n", dev->bus->number); + + /* + * Get appropriate cfga/cfgd values from hose + */ + hose = pci_bus_to_hose(dev->bus->number); + paddress = (u32 *)hose->cfg_addr; + pdata = (u32 *)hose->cfg_data; + + /* locations must be dword-aligned */ + where &= ~3; + + /* + * For top bus generate a type 0 config, + * all others use a type 1 config + * + */ + if (dev->bus->number == hose->first_busno) { + *paddress = ( (1 << (PCI_SLOT(dev->devfn) + 16)) | + (PCI_SLOT(dev->devfn) << 11) | + (PCI_FUNC(dev->devfn) << 8) | where | 0 ); + } else { + *paddress = ( (dev->bus->number << 16) | + (PCI_SLOT(dev->devfn) << 11) | + (PCI_FUNC(dev->devfn) << 8) | where | 1 ); + } + + return (u32)pdata; +} + +/* + * This routine checks the status of the last configuration cycle. If an error + * was detected it returns a 1, else it returns a 0. The errors being checked + * are parity, master abort, target abort (master and target). These types of + * errors occure during a config cycle where there is no device, like during + * the discovery stage. + */ +static int iop321_pci_config_cleanup(u8 bus) +{ + u32 status = 0, err = 0; + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + + /* + * Check the status registers. + */ + if (hose->cfg_addr == (unsigned int *)IOP321_OCCAR) + { + status = *IOP321_ATUSR; + if (status & 0xF900) + { + DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status); + err = 1; + *IOP321_ATUSR = status & 0xF900; + } + status = *IOP321_ATUISR; + if (status & 0x679F) + { + DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status); + err = 1; + *IOP321_ATUISR = status & 0x679f; + } + } + return err; +} + +/* + * The read routines must check the error status of the last configuration + * cycle. If there was an error, the routine returns all hex f's. + */ +static int +iop321_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + volatile u32 *pdata; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + *value = (u8) (((*pdata) >> ((where % 0x04) * 8)) & 0xff); + udelay(50); + + if( iop321_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop321_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + volatile u32 *pdata; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + *value = (u16) (((*pdata) >> ((where % 0x04) * 8)) & 0xffff); + udelay(50); + + if( iop321_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xffff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop321_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + volatile u32 *pdata; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + *value = *pdata; + udelay(50); + + if( iop321_pci_config_cleanup(dev->bus->number) ) + { + *value = 0xffffffff; + } /* IF END */ + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop321_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + volatile u32 *pdata; + u32 mask; + u32 temp; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + mask = ~(0x000000ff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where% 0x4) * 8)); + *pdata = (*pdata & mask) | temp; + udelay(50); + + iop321_pci_config_cleanup(dev->bus->number); + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop321_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + volatile u32 *pdata; + u32 mask; + u32 temp; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + mask = ~(0x0000ffff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) * 8)); + *pdata = (*pdata & mask) | temp; + udelay(50); + + iop321_pci_config_cleanup(dev->bus->number); + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop321_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + volatile u32 *pdata; + + cli(); + + pdata = (u32 *)iop321_pci_config_setup(dev, where); + udelay(50); + *pdata = value; + udelay(50); + + iop321_pci_config_cleanup(dev->bus->number); + + sti(); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops iop321_ops = { + iop321_read_config_byte, + iop321_read_config_word, + iop321_read_config_dword, + iop321_write_config_byte, + iop321_write_config_word, + iop321_write_config_dword, +}; + +/* + * When a PCI device does not exist during config cycles, the 80200 gets a + * bus error instead of returning 0xffffffff. This handler simply returns. + */ +int +iop321_pci_abort_handler(unsigned long addr, unsigned long fsr, struct pt_regs *regs) +{ + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + + return 0; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return iop321_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) diff -Nru a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iop321-time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,132 @@ +/* + * arch/arm/mach-iop3xx/iop321-time.c + * + * Timer code for IOP321 based systems + * + * Author: Deepak Saxena + * + * Copyright 2002 MontaVista Software Inc. + * + * 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 +#include + +#include +#include +#include + +#include +#include + +#include + +#define IOP321_TIME_SYNC 1 + +#define TM_THRESH (LATCH*2) + +static unsigned long iop321_gettimeoffset(void) +{ + unsigned long elapsed, usec; + u32 tisr1, tisr2; + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1)); + elapsed = *IOP321_TU_TCR0; + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2)); + + if(tisr1 & 1) + elapsed += LATCH; + else if (tisr2 & 1) + elapsed = LATCH + *IOP321_TU_TCR0; + + usec = (unsigned long)((LATCH - elapsed) * tick) / LATCH; + + return usec; +} + +static void iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 tisr; +#ifdef IOP321_TIME_SYNC + u32 flags, catchup = 0; + u32 passed; +#endif + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr)); + + tisr |= 1; + + asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr)); + +#ifdef IOP321_TIME_SYNC + passed = 0xffffffff - *IOP321_TU_TCR1; + do { +// local_irq_save(flags); + do_timer(regs); + if (passed < (LATCH*2)) + { + catchup = 0; + } + else + { + catchup = 1; + passed -= LATCH; + } +// local_irq_restore(flags); + } while(catchup); + + + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); +#else +// local_irq_save(flags); + do_timer(regs); +// local_irq_restore(flags); +#endif +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + name: "timer", +}; + +extern int setup_arm_irq(int, struct irqaction*); + +void __init setup_timer(void) +{ + u32 timer_ctl; + u32 latch = LATCH; + + gettimeoffset = iop321_gettimeoffset; + timer_irq.handler = iop321_timer_interrupt; + setup_arm_irq(IRQ_IOP321_TIMER0, &timer_irq); + + timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD | + IOP321_TMR_RATIO_1_1; + + asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH)); + + asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl)); + +#ifdef IOP321_TIME_SYNC + /* Setup second timer */ + /* setup counter */ + timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | + IOP321_TMR_RATIO_1_1; + asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff)); + /* setup control */ + asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl)); +#endif +} + + diff -Nru a/arch/arm/mach-iop3xx/iq31244-pci.c b/arch/arm/mach-iop3xx/iq31244-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iq31244-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,148 @@ +/* + * arch/arm/mach-iop3xx/iq31244-pci.c + * + * PCI support for the Intel IQ31244 reference board + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct pci_controller *hose = NULL; + +void iq31244_init(void*); +int iq31244_map_irq(struct pci_dev *, unsigned char, unsigned char); + + +struct hw_pci iq31244_pci __initdata = { + init: iq31244_init, + swizzle: common_swizzle, + map_irq: iq31244_map_irq, +}; + + +void __init +iq31244_init(void *data) +{ + struct pci_bus *bus; + struct pci_sys_data *sysdata = (struct pci_sys_data *)data; + struct resource *mem = + kmalloc(sizeof(struct resource), GFP_KERNEL); + unsigned long pci_mem_start = + *IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK; + + if(!mem) + printk(KERN_ERR "Could not allocate PCI resource\n"); + + /* IOP321 default setup */ + iop321_init(); + + hose = pcibios_alloc_controller(); + + if(!hose) + panic("Could not allocate PCI hose"); + + hose->first_busno = (*IOP321_PCIXSR >> 8) & 0xff; + + if (hose->first_busno == 0xff) + hose->first_busno = 0; + + hose->last_busno = 0xff; + hose->cfg_addr = (unsigned int *)IOP321_OCCAR; + hose->cfg_data = (unsigned char *)IOP321_OCCDR; + hose->io_space.start = IOP321_PCI_LOWER_IO; + hose->io_space.end = IOP321_PCI_UPPER_IO; + + // Need to update this for IQ31244, not a slave card + /* + * Since the IQ80321 is a slave card on a PC, we use + * BAR1 to reserve a portion of PCI memory space for + * use with the private devices on the secondary bus + * (GigE and PCI-X slot). We read BAR1 and configure + * our outbound translation windows to target that + * address range and assign all devices in that + * address range. Note that the same cannot be done + * with I/O space, so hopefully the host will stick to + * the lower 64K for PCI I/O and leave us alone. + */ + hose->mem_space.start = pci_mem_start; + hose->mem_space.end = pci_mem_start + IOP321_PCI_WINDOW_SIZE; + sysdata->mem_offset = IOP321_PCI_LOWER_MEM - pci_mem_start; + + /* Autoconfig the hose */ + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + + if(mem) + { + mem->flags = IORESOURCE_MEM; + mem->name = "IOP321 ATU"; + allocate_resource(&iomem_resource, mem, + IOP321_PCI_WINDOW_SIZE, + IOP321_PCI_LOWER_MEM, + 0xffffffff, + IOP321_PCI_LOWER_MEM + & 0xff000000, + NULL, NULL); + } + + /* Scan the hose */ + bus = pci_scan_bus(hose->first_busno, &iop321_ops, sysdata); +} + +#define INTA IRQ_IQ31244_INTA +#define INTB IRQ_IQ31244_INTB +#define INTC IRQ_IQ31244_INTC +#define INTD IRQ_IQ31244_INTD + +static inline int __init +iq31244_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + char ret; + + static char pci_irq_table[4][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTB, INTB, INTB, INTB}, // Not used + {INTC, INTC, INTC, INTC}, // GD31244 SATAs + {INTD, INTD, INTD, INTD}, // PCI-X Slot + {INTA, INTA, INTA, INTA}, // 82546 GigE + }; + ret = pci_irq_table[idsel%4][pin-1]; + + return ret; +} diff -Nru a/arch/arm/mach-iop3xx/iq80310-irq.c b/arch/arm/mach-iop3xx/iq80310-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iq80310-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,170 @@ +/* + * linux/arch/arm/mach-iop3xx/iq80310-irq.c + * + * IRQ hadling/demuxing for IQ80310 board + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * 2.4.7-rmk1-iop310.1 + * Moved demux from asm to C - DS + * Fixes for various revision boards - DS + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern void xs80200_irq_mask(unsigned int); +extern void xs80200_irq_unmask(unsigned int); +extern void xs80200_init_irq(void); + +extern void do_IRQ(int, struct pt_regs *); + +extern u32 iop310_mask; + +extern void iop310_irq_demux(int, void *, struct pt_regs *); + +extern int iop310_init_irq(void); + +static void +iq80310_irq_mask (unsigned int irq) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + *mask |= (1 << (irq - IQ80310_IRQ_OFS)); + + /* + * There's no mask for PCI INT A-C, so we just mask out all + * external interrupts on the CPU. + * + * We set a bit of the iop310 mask so that the iop310_irq_mask + * function does not unmask EXTINT + */ + if (irq > IRQ_IQ80310_INTD) + { + xs80200_irq_mask(IRQ_XS80200_EXTIRQ); + iop310_mask |= (0x80000000 >> (irq - IRQ_IQ80310_INTD)); + } +} + +static void +iq80310_irq_unmask (unsigned int irq) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + *mask &= ~(1 << (irq - IQ80310_IRQ_OFS)); + + /* + * See comment above + */ + if (irq > IRQ_IQ80310_INTD) + { + iop310_mask &= ~((0x80000000 >> (irq - IRQ_IQ80310_INTD))); + if(!iop310_mask) + xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); + } +} + +static void iq80310_cpld_irq_demux(int irq, void *dev_id, + struct pt_regs *regs) +{ + u8 irq_stat = *((volatile u8*)IQ80310_INT_STAT); + u8 irq_mask = *((volatile u8*)IQ80310_INT_MASK); + unsigned int irqno = 0xffffffff; + unsigned long intsrc, intctl; + + // Needed? If IRQ is masked, it shouldn't get through... + irq_stat &= ~irq_mask; + + if(irq_stat & 0x01) + irqno = IRQ_IQ80310_TIMER; + else if(irq_stat & 0x02) + irqno = IRQ_IQ80310_I82559; + else if(irq_stat & 0x04) + irqno = IRQ_IQ80310_UART1; + else if(irq_stat & 0x08) + irqno = IRQ_IQ80310_UART2; + else if(irq_stat & 0x10) + irqno = IRQ_IQ80310_INTD; + else if(system_rev) + { + irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 0xf; + + if(irq_stat & 0x1) + irqno = IRQ_IQ80310_INTA; + else if(irq_stat & 0x2) + irqno = IRQ_IQ80310_INTB; + else if(irq_stat & 0x4) + irqno = IRQ_IQ80310_INTC; + } + else /* Running on a REV D.1 or older, assume PCI INTA */ + irqno = IRQ_IQ80310_INTA; + + /* + * If we didn't read a CPLD interrupt, we assume it's from + * a device on the chipset itself. + */ + if(irqno == 0xffffffff) + { + iop310_irq_demux(irq, dev_id, regs); + return; + } + + /* + * If on a REV D.1 or lower board, we just assumed INTA since + * PCI is not routed, and it may actually be an on-chip interrupt. + * + * Note that we're giving on-chip interrupts slightly higher + * priority than PCI by handling them first. + */ + if(irqno == IRQ_IQ80310_INTA && !system_rev) + iop310_irq_demux(irq, dev_id, regs); + + do_IRQ(irqno, regs); +} + + +static struct irqaction iq80310_cpld_irq = { + name: "CPLD_IRQ", + handler: iq80310_cpld_irq_demux, + flags: SA_NOMASK +}; + +extern int setup_arm_irq(int, struct irqaction *); + +void __init iq80310_init_irq(void) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + unsigned int i; + + iop310_init_irq(); + + /* + * Setup PIRSR to route PCI interrupts into xs80200 + */ + *IOP310_PIRSR = 0xff; + *mask = 0xff; /* mask all sources */ + + for (i = IQ80310_IRQ_OFS; i < NR_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = iq80310_irq_mask; + irq_desc[i].mask = iq80310_irq_mask; + irq_desc[i].unmask = iq80310_irq_unmask; + } + + setup_arm_irq(IRQ_XS80200_EXTIRQ, &iq80310_cpld_irq); +} diff -Nru a/arch/arm/mach-iop3xx/iq80310-pci.c b/arch/arm/mach-iop3xx/iq80310-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iq80310-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,267 @@ +/* + * arch/arm/mach-iop3xx/iq80310-pci.c + * + * PCI support for the Intel IQ80310 reference board + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct pci_controller *sec_hose, *pri_hose = NULL; +static struct resource sec_mem, pri_mem, sec_io, pri_io; + +void __init +iq80310_init(void *sysdata) +{ + struct pci_bus *bus; + struct pci_dev *dev; + int host = *(volatile u32*)IQ80310_BACKPLANE & 0x1; + + system_rev = (*(volatile unsigned int*)0xfe830000) & 0x0f; + + if(system_rev) + system_rev = 0xF; + + if(host) + printk("PCI: IQ80310 is system controller\n"); + else + printk("PCI: IQ80310 is agent\n"); + + /* IOP310 default setup */ + iop310_init(); + + if(host) + { + pri_hose = pcibios_alloc_controller(); + + if(!pri_hose) + panic("Could not allocate PCI hose"); + + pri_hose->first_busno = 0; + pri_hose->last_busno = 0; + pri_hose->first_busno = 0; + pri_hose->last_busno = 0xff; + pri_hose->cfg_addr = (unsigned int *)IOP310_POCCAR; + pri_hose->cfg_data = (unsigned char *)IOP310_POCCDR; + pri_hose->io_space.start = IOP310_PCIPRI_LOWER_IO; + pri_hose->io_space.end = IOP310_PCIPRI_UPPER_IO; + pri_hose->mem_space.start = IOP310_PCIPRI_LOWER_MEM; + pri_hose->mem_space.end = IOP310_PCIPRI_UPPER_MEM; + + pri_hose->mem_resources[0].start = IOP310_PCIPRI_LOWER_MEM; + pri_hose->mem_resources[0].end = IOP310_PCIPRI_UPPER_MEM; + pri_hose->mem_resources[0].flags = IORESOURCE_MEM; + + pri_hose->io_resource.start = IOP310_PCIPRI_LOWER_IO; + pri_hose->io_resource.end = IOP310_PCIPRI_UPPER_IO; + pri_hose->io_resource.flags = IORESOURCE_IO; + + /* Autoconfig the hose */ + pri_hose->last_busno = pciauto_bus_scan(pri_hose, 0); + + /* Scan the hose */ + bus = pci_scan_bus(0, &iop310_ops, sysdata); + + bus->resource[0] = &pri_hose->io_resource; + bus->resource[1] = &pri_hose->mem_resources[0]; + + pri_hose->mem_resources[0].name = "IOP310 PATU PCI Mem"; + pri_hose->io_resource.name = "IOP310 PATU PCI I/O"; + } + else + { + /* + * If we're running in agent mode, we remap the + * SATU window to be at the same PCI location as + * the PATU window so that there are no collisions + * between the SATU PCI space and the host memory + * PCI space. This also allows us to have a single + * bus_to_virt/virt_to_bus for both hoses. + */ + + *IOP310_SIABAR = *IOP310_PIABAR; + } + + /* Always scan 2ndary hose */ + + sec_hose = pcibios_alloc_controller(); + + if (!sec_hose) + panic("Couldn't allocate a PCI hose"); + + /* + * Note that in agent mode, we can just tell the 2ndary + * hose that it is at 0 since it's a private configuration + * space from the primary bus. + */ + if(host) + sec_hose->first_busno = pri_hose->last_busno + 1; + else + sec_hose->first_busno = 0; + + sec_hose->last_busno = 0xff; + sec_hose->cfg_addr = (unsigned int *)IOP310_SOCCAR; + sec_hose->cfg_data = (unsigned char *)IOP310_SOCCDR; + sec_hose->io_space.start = IOP310_PCISEC_LOWER_IO; + sec_hose->io_space.end = IOP310_PCISEC_UPPER_IO; + sec_hose->mem_space.start = IOP310_PCISEC_LOWER_MEM; + sec_hose->mem_space.end = IOP310_PCISEC_UPPER_MEM; + + sec_hose->mem_resources[0].start = IOP310_PCISEC_LOWER_MEM; + sec_hose->mem_resources[0].end = IOP310_PCISEC_UPPER_MEM; + sec_hose->mem_resources[0].flags = IORESOURCE_MEM; + + sec_hose->io_resource.start = IOP310_PCISEC_LOWER_IO; + sec_hose->io_resource.end = IOP310_PCISEC_UPPER_IO; + sec_hose->io_resource.flags = IORESOURCE_IO; + + /* Autoconfig the hose */ + /* Autoconfig the hose */ + sec_hose->last_busno = + pciauto_bus_scan(sec_hose, sec_hose->first_busno); + + /* Scan the hose */ + bus = pci_scan_bus(sec_hose->first_busno, &iop310_ops, sysdata); + + bus->resource[0] = &sec_hose->io_resource; + bus->resource[1] = &sec_hose->mem_resources[0]; + + sec_hose->mem_resources[0].name = "IOP310 SATU PCI Mem"; + sec_hose->io_resource.name = "IOP310 SATU PCI I/O"; + + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(); +} + +#define INTA IRQ_IQ80310_INTA +#define INTB IRQ_IQ80310_INTB +#define INTC IRQ_IQ80310_INTC +#define INTD IRQ_IQ80310_INTD + +#define INTE IRQ_IQ80310_I82559 + +static inline int __init +iq80310_pri_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + const long min_idsel = 2, max_idsel = 3, irqs_per_slot = 4; + + /* + * On a Rev D.1 and older board, INT A-C are not routed, so we + * just fake it as INTA and than we take care of handling it + * correctly in the IRQ demux routine. + */ + if(!system_rev) + { + static char pci_irq_table[ ][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTA, INTD, INTA, INTA}, /* PCI Slot J3 */ + {INTD, INTA, INTA, INTA}, /* PCI Slot J4 */ + }; + return PCI_IRQ_TABLE_LOOKUP; + } + else + { + static char pci_irq_table[ ][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTC, INTD, INTA, INTB}, /* PCI Slot J3 */ + {INTD, INTA, INTB, INTC}, /* PCI Slot J4 */ + }; + return PCI_IRQ_TABLE_LOOKUP; + } +} + + +static inline int __init +iq80310_sec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + const long min_idsel = 0, max_idsel = 2, irqs_per_slot = 4; + + if(!system_rev) + { + static char pci_irq_table[ ][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTA, INTA, INTA, INTD}, /* PCI Slot J1 */ + {INTA, INTA, INTD, INTA}, /* PCI Slot J5 */ + {INTE, INTE, INTE, INTE}, /* P2P Bridge */ + }; + return PCI_IRQ_TABLE_LOOKUP; + } + else + { + static char pci_irq_table[ ][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTA, INTB, INTC, INTD}, /* PCI Slot J1 */ + {INTB, INTC, INTD, INTA}, /* PCI Slot J5 */ + {INTE, INTE, INTE, INTE}, /* P2P Bridge */ + }; + return PCI_IRQ_TABLE_LOOKUP; + } + +} + +static inline int __init +iq80310_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(dev->bus->number); + + if(hose == pri_hose) + return iq80310_pri_map_irq(dev, idsel, pin); + else + return iq80310_sec_map_irq(dev, idsel, pin); +} + + +struct hw_pci iq80310_pci __initdata = { + init: iq80310_init, + swizzle: common_swizzle, + map_irq: iq80310_map_irq, +}; diff -Nru a/arch/arm/mach-iop3xx/iq80310-time.c b/arch/arm/mach-iop3xx/iq80310-time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iq80310-time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,125 @@ +/* + * linux/arch/arm/mach-iop310/time-iq80310.c + * + * Timer functions for IQ80310 onboard timer + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 + +static void iq80310_write_timer (u_long val) +{ + volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0; + volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1; + volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2; + + *la0 = val; + *la1 = val >> 8; + *la2 = (val >> 16) & 0x3f; +} + +static u_long iq80310_read_timer (void) +{ + volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0; + volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1; + volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2; + volatile u_char *la3 = (volatile u_char *)IQ80310_TIMER_LA3; + u_long b0, b1, b2, b3, val; + + b0 = *la0; b1 = *la1; b2 = *la2; b3 = *la3; + b0 = (((b0 & 0x20) >> 1) | (b0 & 0x1f)); + b1 = (((b1 & 0x20) >> 1) | (b1 & 0x1f)); + b2 = (((b2 & 0x20) >> 1) | (b2 & 0x1f)); + b3 = (b3 & 0x0f); + val = ((b0 << 0) | (b1 << 6) | (b2 << 12) | (b3 << 18)); + return val; +} + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long iq80310_gettimeoffset (void) +{ + unsigned long elapsed, usec; + + /* We need elapsed timer ticks since last interrupt */ + elapsed = iq80310_read_timer(); + + /* Now convert them to usec */ + usec = (unsigned long)(elapsed*tick)/LATCH; + + return usec; +} + + +static void iq80310_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; + + /* clear timer interrupt */ + *timer_en &= ~2; + *timer_en |= 2; + + /* + * AHEM..HACK + * + * Since the timer interrupt is cascaded through the CPLD and + * the 80312 and the demux code calls do_IRQ, the irq count is + * going to be atleast 2 when we get here and this will cause the + * kernel to increment the system tick counter even if we're + * idle. This causes it to look like there's always 100% system + * time, which is not the case. To get around it, we just decrement + * the IRQ count before calling do_timer. We increment it again + * b/c otherwise it will go negative and than bad things happen. + * + * -DS + */ + irq_exit(smp_processor_id(), irq); + do_timer(regs); + irq_enter(smp_processor_id(), irq); +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + name: "timer", +}; + + +extern int setup_arm_irq(int, struct irqaction*); + +void __init setup_timer (void) +{ + volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; + + gettimeoffset = iq80310_gettimeoffset; + timer_irq.handler = iq80310_timer_interrupt; + setup_arm_irq(IRQ_IQ80310_TIMER, &timer_irq); + *timer_en = 0; + iq80310_write_timer(LATCH); + *timer_en |= 2; + *timer_en |= 1; +} + diff -Nru a/arch/arm/mach-iop3xx/iq80321-pci.c b/arch/arm/mach-iop3xx/iq80321-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/iq80321-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,148 @@ +/* + * arch/arm/mach-iop3xx/iq80321-pci.c + * + * PCI support for the Intel IQ80321 reference board + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct pci_controller *hose = NULL; + +void iq80321_init(void*); +int iq80321_map_irq(struct pci_dev *, unsigned char, unsigned char); + + +struct hw_pci iq80321_pci __initdata = { + init: iq80321_init, + swizzle: common_swizzle, + map_irq: iq80321_map_irq, +}; + + +void __init +iq80321_init(void *data) +{ + struct pci_bus *bus; + struct pci_sys_data *sysdata = (struct pci_sys_data *)data; + struct resource *mem = + kmalloc(sizeof(struct resource), GFP_KERNEL); + unsigned long pci_mem_start = + *IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK; + + if(!mem) + printk(KERN_ERR "Could not allocate PCI resource\n"); + + /* IOP321 default setup */ + iop321_init(); + + hose = pcibios_alloc_controller(); + + if(!hose) + panic("Could not allocate PCI hose"); + + hose->first_busno = (*IOP321_PCIXSR >> 8) & 0xff; + + if (hose->first_busno == 0xff) + hose->first_busno = 0; + + hose->last_busno = 0xff; + hose->cfg_addr = (unsigned int *)IOP321_OCCAR; + hose->cfg_data = (unsigned char *)IOP321_OCCDR; + hose->io_space.start = IOP321_PCI_LOWER_IO; + hose->io_space.end = IOP321_PCI_UPPER_IO; + + /* + * Since the IQ80321 is a slave card on a PC, we use + * BAR1 to reserve a portion of PCI memory space for + * use with the private devices on the secondary bus + * (GigE and PCI-X slot). We read BAR1 and configure + * our outbound translation windows to target that + * address range and assign all devices in that + * address range. Note that the same cannot be done + * with I/O space, so hopefully the host will stick to + * the lower 64K for PCI I/O and leave us alone. + */ + hose->mem_space.start = pci_mem_start; + hose->mem_space.end = pci_mem_start + IOP321_PCI_WINDOW_SIZE; + sysdata->mem_offset = IOP321_PCI_LOWER_MEM - pci_mem_start; + + /* Autoconfig the hose */ + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + + if(mem) + { + mem->flags = IORESOURCE_MEM; + mem->name = "IOP321 ATU"; + allocate_resource(&iomem_resource, mem, + IOP321_PCI_WINDOW_SIZE, + IOP321_PCI_LOWER_MEM, + 0xffffffff, + IOP321_PCI_LOWER_MEM + & 0xff000000, + NULL, NULL); + } + + /* Scan the hose */ + bus = pci_scan_bus(hose->first_busno, &iop321_ops, sysdata); +} + +#define INTA IRQ_IQ80321_INTA +#define INTB IRQ_IQ80321_INTB +#define INTC IRQ_IQ80321_INTC +#define INTD IRQ_IQ80321_INTD + +#define INTE IRQ_IQ80321_I82544 + +static inline int __init +iq80321_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + char ret; + + static char pci_irq_table[3][4] = + { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTE, INTE, INTE, INTE}, /* Gig-E */ + {INTD, INTC, INTD, INTA}, /* Unused */ + {INTC, INTD, INTA, INTB}, /* PCI-X Slot */ + }; + ret = pci_irq_table[idsel%4][pin-1]; + return ret; +} + diff -Nru a/arch/arm/mach-iop3xx/message.c b/arch/arm/mach-iop3xx/message.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/message.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,1432 @@ +/************************************************************************** + * arch/arm/mach-iop310/message.c + * + * Support functions for the Intel 80310 MU. + * (see also Documentation/arm/XScale/IOP310/message.txt) + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2001 Intel 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. + * + * Todos: Thorough Error handling + * + * History: (07/18/2001, DJ) Initial Creation + * (08/22/2001, DJ) changed spinlock calls to no save flags + * (08/27/2001, DJ) Added irq threshold handling + * (10/11/2001, DJ) Tested with host side driver. Circular + * Queues working. + * (10/12/2001, DJ) Rest of MU works now + *************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "message.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#include +#endif + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK(s, args...) printk("80310MU: " s, ## args) +#else +#define DPRINTK(s, args...) +#endif + +void *mu_mem = NULL; + +/* globals */ +static iop310_mu_t mu_dev; + +/* static prototypes */ +static int __init mu_init(void); +static void mu_irq_handler(int, void *, struct pt_regs *); +static void mu_msg_irq_task(void *); +static void mu_db_irq_task(void *); +static void mu_cq_irq_task(void *); +static void mu_ir_irq_task(void *); + +/*===========================MU Message Registers========================*/ + +/*=======================================================================*/ +/* Procedure: mu_msg_request() */ +/* */ +/* Description: This function is used to request the ownership of */ +/* MU Message Registers component ownership */ +/* */ +/* Parameters: *mu_context -- pass by reference int, written by API */ +/* */ +/* Returns: mu_context -- pointer to MU descriptor, ownership */ +/* granted. */ +/* NULL -- ownership denied */ +/* */ +/* Notes/Assumptions: The requester if successful will own the entire */ +/* MU message registers mechanism. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +int mu_msg_request(u32 * mu_context) +{ + iop310_mu_t *mu = &mu_dev; + mu_msg_t *msg = &mu->msg_desc; + int i; + mu_msg_desc_t *msg_desc = NULL; + + /* denied if already owned */ + if(atomic_read(&msg->in_use)) + { + return -EBUSY; + } + + /* set ownership flag */ + atomic_inc(&msg->in_use); + + /* if we haven't allocated resources */ + if(!atomic_read(&msg->res_init)) + { + /* allocate message descriptors */ + for(i = 0; i < MAX_MSG_DESC; i++) + { + /* allocate memory for message descriptor */ + msg_desc = (mu_msg_desc_t *) kmalloc(sizeof(mu_msg_desc_t), + GFP_KERNEL); + if(!msg_desc) + { + DPRINTK("Unable to allocate message descriptor for MU\n"); + return -ENOMEM; + } + + /* Init message descriptor */ + msg_desc->message = 0; + msg_desc->reg_num = INBOUND_REG_UNDEF; + + /* put descriptor on free stack */ + spin_lock_irq(&msg->free_lock); + list_add(&msg_desc->link, &msg->free_stack); + spin_unlock_irq(&msg->free_lock); + } + /* set resource init flag */ + atomic_inc(&msg->res_init); + } + + /* Unmask outbound interrupts */ + *(IOP310_MUOIMR) &= ~(MUOIMR_OBMSG_0_MASK | MUOIMR_OBMSG_1_MASK); + + *mu_context = (u32)mu; + return 0; +} /* end of mu_msg_request() */ + +/*=======================================================================*/ +/* Procedure: mu_msg_set_callback() */ +/* */ +/* Description: This function sets up the callback functions for the */ +/* Inbound message passing of the MR mechanism. The app */ +/* calls this can setup callback for either of the */ +/* inbound registers or have the same callback for both. */ +/* */ +/* */ +/* Parameters: mu_context - context to MU descriptor */ +/* reg - INBOUND_REG_BOTH, INBOUND_REG_0, INBOUND_REG_1 */ +/* func - pointer to callback */ +/* */ +/* Returns: 0: SUCCESS */ +/* -EINVAL - invalid parameters passed in */ +/* */ +/* Notes/Assumptions: The app owns the message registers mechanism. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_msg_set_callback(u32 mu_context, u8 reg, mu_msg_cb_t func) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_msg_t *msg = &mu->msg_desc; + + /* make sure callback valid and the correct register number passed in */ + if(!func || (!(reg & INBOUND_REG_0) && !(reg & INBOUND_REG_1))) + { + return -EINVAL; + } + + switch (reg) + { + case INBOUND_REG_BOTH: /* both inbound registers */ + msg->callback_0 = func; + msg->callback_1 = func; + /* unmask inbound INTs */ + *(IOP310_MUIIMR) &= ~(MUIIMR_IBMSG_0_MASK | MUIIMR_IBMSG_1_MASK); + break; + case INBOUND_REG_0: /* inbound register 0 */ + msg->callback_0 = func; + /* unmask inbound INT 0 */ + *(IOP310_MUIIMR) &= ~MUIIMR_IBMSG_0_MASK; + break; + case INBOUND_REG_1: /* inbound register 1 */ + msg->callback_1 = func; + /* unmask inbound INT 1 */ + *(IOP310_MUIIMR) &= ~MUIIMR_IBMSG_1_MASK; + break; + default: /* this should never be executed */ + printk("We should never get here\n"); + BUG(); + return -EINVAL; + } + + return 0; +} /* End of mu_msg_set_callback() */ + +/*=======================================================================*/ +/* Procedure: mu_msg_post() */ +/* */ +/* Description: This function allows the app to post outbound messages */ +/* by the desired register. */ +/* */ +/* */ +/* Parameters: mu_context - context to MU device descriptor */ +/* val - message value to post */ +/* cReg - OUTBOUND_REG_0, OUTBOUND_REG_1 */ +/* */ +/* Returns: 0 - success */ +/* -EINVAL - invalid parameter */ +/* -EBUSY - register busy */ +/* */ +/* Notes/Assumptions: The app will figure out which reg to use. The app */ +/* must already own the message registers. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_msg_post(u32 mu_context, u32 val, u8 reg) +{ + iop310_mu_t *mu = (iop310_mu_t *)mu_context; + /* check the parameters */ + if((reg != OUTBOUND_REG_0) && (reg != OUTBOUND_REG_1)) + { + DPRINTK("posting to wrong register\n"); + return -EINVAL; + } + + /* if we are posting on register 0 */ + if(reg == OUTBOUND_REG_0) + { + /* if outbound INT bit still asserted, previous message has not */ + /* been read. cannot write a new message */ + if(*(IOP310_MUOISR) & MUOISR_OBMSG_0_INT) + { + DPRINTK("INT 0 for register still asserted\n"); + return -EBUSY; + } + + /* write message to register */ + *(IOP310_MUOMR0) = val; + } + else /* we are posting register 1 */ + { + /* register busy */ + if(*(IOP310_MUOISR) & MUOISR_OBMSG_1_INT) + { + DPRINTK("INT 1 for register still asserted\n"); + return -EBUSY; + } + + /* post message */ + *(IOP310_MUOMR1) = val; + } + return 0; +} /* End of mu_msg_post() */ + +/*=======================================================================*/ +/* Procedure: mu_msg_irq_task() */ +/* */ +/* Description: This function is the "bottom half" task of the irq */ +/* handler that handles the message registers inbound */ +/* messages. It will attempt to pass the message to the */ +/* app via the provided callback function */ +/* */ +/* */ +/* Parameters: dev - pointer to MU device descriptor */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: The app is responsible for providing a mechanism */ +/* to store the messages via the callback function */ +/* when the task hands them off. This task is */ +/* scheduled by the MU irq handler. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +static void mu_msg_irq_task(void *dev) +{ + iop310_mu_t *mu = (iop310_mu_t *) dev; + mu_msg_t *msg = &mu->msg_desc; + mu_msg_desc_t *msg_desc = NULL; + + /* while we have message descriptors to process */ + while(!list_empty(&msg->process_q)) + { + /* get a message descriptor from process queue */ + spin_lock_irq(&msg->process_lock); + msg_desc = MSG_ENTRY(msg->process_q.next); + list_del(&msg_desc->link); + spin_unlock_irq(&msg->process_lock); + + /* if register 0 message */ + if((msg_desc->reg_num == INBOUND_REG_0) && msg->callback_0) + { + msg->callback_0(msg_desc); + } + /* or register 1 message */ + else if((msg_desc->reg_num == INBOUND_REG_1) && msg->callback_1) + { + msg->callback_1(msg_desc); + } + + /* reinit message descriptors */ + msg_desc->reg_num = INBOUND_REG_UNDEF; + msg_desc->message = 0; + + /* put descriptor back on stack */ + spin_lock_irq(&msg->free_lock); + list_add(&msg_desc->link, &msg->free_stack); + spin_unlock_irq(&msg->free_lock); + } +} /* End of msg_msg_irq_task() */ + +/*=======================================================================*/ +/* Procedure: mu_msg_free() */ +/* */ +/* Description: This function is called to release the ownership of */ +/* the message registers mechanism. Resource is dealloc */ +/* if requested via parameter */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* mode - MSG_FREE_SOFTMODE, MSG_FREE_HARDMODE */ +/* */ +/* Returns: 0 - success */ +/* -EPERM - permissione denied */ +/* */ +/* Notes/Assumptions: Only the owner of the message mechanism shall */ +/* call this function */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +int mu_msg_free(u32 mu_context, u8 mode) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_msg_t *msg = &mu->msg_desc; + mu_msg_desc_t *msg_desc = NULL; + + /* check ownership */ + if(!atomic_read(&msg->in_use)) + { + return -EPERM; + } + + /* return all the descriptors to free stack */ + while(!list_empty(&msg->process_q)) + { + spin_lock_irq(&msg->process_lock); + msg_desc = MSG_ENTRY(msg->process_q.next); + list_del(&msg_desc->link); + spin_unlock_irq(&msg->process_lock); + + msg_desc->reg_num = INBOUND_REG_UNDEF; + msg_desc->message = 0; + + spin_lock_irq(&msg->free_lock); + list_add(&msg_desc->link, &msg->free_stack); + spin_unlock_irq(&msg->free_lock); + } + + /* if hardmode we free all the descriptor memories */ + if(mode == MSG_FREE_HARDMODE) + { + while(!list_empty(&msg->free_stack)) + { + spin_lock_irq(&msg->free_lock); + msg_desc = MSG_ENTRY(msg->free_stack.next); + list_del(&msg_desc->link); + spin_unlock_irq(&msg->free_lock); + kfree(msg_desc); + } + /* unset resource init flag */ + atomic_dec(&msg->res_init); + } + + msg->callback_0 = NULL; + msg->callback_1 = NULL; + + /* mask inbound/outbound INTs */ + *(IOP310_MUIIMR) |= (MUIIMR_IBMSG_0_MASK | MUIIMR_IBMSG_1_MASK); + *(IOP310_MUOIMR) |= (MUOIMR_OBMSG_0_MASK | MUOIMR_OBMSG_1_MASK); + + /* reset ownership flag */ + atomic_dec(&msg->in_use); + return 0; +} /* End of mu_msg_free() */ + +/*==========================MU Doorbell Registers========================*/ + +/*=======================================================================*/ +/* Procedure: mu_db_request() */ +/* */ +/* Description: This function is used to request the ownership of the */ +/* MU doorbell registers mechanism. */ +/* */ +/* Parameters: NONE */ +/* */ +/* Returns: iop310_mu_t * - success */ +/* NULL - failed */ +/* */ +/* Notes/Assumptions: The requestor will own the entire MU db regs if */ +/* successful. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_db_request(u32 * mu_context) +{ + iop310_mu_t *mu = &mu_dev; + mu_db_t *db = &mu->db_desc; + + /* check ownership flag */ + if(atomic_read(&db->in_use)) + { + /* already owned */ + return -EBUSY; + } + + /* set usage flag */ + atomic_inc(&db->in_use); + + /* unmask outbound int */ + *(IOP310_MUOIMR) &= ~(MUOIMR_OBDB_MASK | MUOIMR_PCI_MASKA | + MUOIMR_PCI_MASKB | MUOIMR_PCI_MASKC | + MUOIMR_PCI_MASKD); + + *mu_context = (u32) mu; + return 0; +} /* End of mu_db_request() */ + +/*=======================================================================*/ +/* Procedure: mu_db_set_callback() */ +/* */ +/* Description: This function sets up the callback func that will rcv */ +/* the inbound doorbell messages. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* func - pointer to callback function */ +/* */ +/* Returns: -EINVAL - invalid parameter */ +/* 0 - success */ +/* */ +/* Notes/Assumptions: The app owns the db mechanism. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_db_set_callback(u32 mu_context, mu_db_cb_t func) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_db_t *db = &mu->db_desc; + + /* check parameter */ + if(!func) + { + return -EINVAL; + } + + /* set callback */ + db->callback = func; + + /* unmask inbound INTs */ + *(IOP310_MUIIMR) &= ~(MUIIMR_IBDB_FIQ2_MASK | MUIIMR_IBDB_IRQ_MASK); + + return 0; +} /* End of mu_db_set_callback() */ + +/*=======================================================================*/ +/* Procedure: mu_db_ring() */ +/* */ +/* Description: This funciton sets the outbound db reg bits requested */ +/* by the app */ +/* */ +/* Parameters: mu - pointer to MU device descriptor. */ +/* mask - doorbell value to set */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline void mu_db_ring(u32 mu_context, u32 mask) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + /* set outbound db register */ + *(IOP310_MUODR) |= mask; +} /* End of mu_db_ring() */ + +/*=======================================================================*/ +/* Procedure: mu_db_irq_task() */ +/* */ +/* Description: This function is the "bottom half" task for the irq hdl */ +/* that will pass the inbound doorbell register value to */ +/* the app via callback. */ +/* */ +/* Parameters: dev - pointer to MU device descriptor */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: The app is responsible for providing a mechanism */ +/* to parse the doorbell register value after recv */ +/* via callback. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +static void mu_db_irq_task(void *dev) +{ + iop310_mu_t *mu = (iop310_mu_t *) dev; + mu_db_t *db = &mu->db_desc; + u32 value; + + /* get latest inbound db value and reset hold var */ + spin_lock_irq(&db->reg_lock); + value = db->reg_val; + db->reg_val = 0; + spin_unlock_irq(&db->reg_lock); + + /* callback if exists */ + if(db->callback) + { + db->callback(value); + } +} /* End of mu_db_irq_task() */ + +/*=======================================================================*/ +/* Procedure: mu_db_free() */ +/* */ +/* Description: This function releases ownership of the db registers. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor. */ +/* */ +/* Returns: 0 - success */ +/* -EPERM - permission denied. */ +/* */ +/* Notes/Assumptions: Only the owner of db shall call this function. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_db_free(u32 mu_context) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_db_t *db = &mu->db_desc; + + /* check ownership */ + if(!atomic_read(&db->in_use)) + { + return -EPERM; + } + + /* reset usage flag */ + atomic_dec(&db->in_use); + + db->callback = NULL; + + /* reset store value */ + spin_lock_irq(&db->reg_lock); + db->reg_val = 0; + spin_unlock_irq(&db->reg_lock); + + /* mask inbound & outbound INTs */ + *(IOP310_MUIIMR) |= (MUIIMR_IBDB_FIQ2_MASK | MUIIMR_IBDB_IRQ_MASK); + *(IOP310_MUOIMR) |= (MUOIMR_OBDB_MASK | MUOIMR_PCI_MASKA | + MUOIMR_PCI_MASKB | MUOIMR_PCI_MASKC | + MUOIMR_PCI_MASKD); + return 0; +} /* End of mu_db_free() */ + +/*===========================MU Circular Queues==========================*/ + +/*=======================================================================*/ +/* Procedure: mu_cq_request() */ +/* */ +/* Description: This function is used to request the ownership of the */ +/* MU circular queues mechanism. */ +/* */ +/* Parameters: q_size - MUCR_QUEUE_4K, MUCR_QUEUE_8K, MUCR_QUEUE_16K, */ +/* MUCR_QUEUE_32K, MUCR_QUEUE_64K */ +/* */ +/* Returns: iop310_mu_t * - success */ +/* NULL - permission denied */ +/* */ +/* Notes/Assumptions: The request shall own entire cq if successful. */ +/* */ +/* History: Dave Jiang 08/17/01 Initial Creation */ +/*=======================================================================*/ +int mu_cq_request(u32 * mu_context, u32 q_size) +{ + iop310_mu_t *mu = &mu_dev; + mu_cq_t *cq = &mu->cq_desc; + u32 entry_size = 0; + u32 queue_cmd = 0; + + /* check ownership */ + if(atomic_read(&cq->in_use)) + { + DPRINTK("Already owned\n"); + return -EBUSY; + } + + /* set ownership flag */ + atomic_inc(&cq->in_use); + + /* set top of inbound free queue */ + cq->inb_free_q_top = virt_to_phys(mu_mem); + + /* set queue size */ + cq->q_size = q_size; + + /* set rest of queue pointers */ + switch (q_size) + { + case MUCR_QUEUE_4K: + entry_size = QUEUE_16K; + queue_cmd = MUCR_QUEUE_4K; + cq->num_entries = ENTRY_4K; + break; + case MUCR_QUEUE_8K: + entry_size = QUEUE_32K; + queue_cmd = MUCR_QUEUE_8K; + cq->num_entries = ENTRY_8K; + break; + case MUCR_QUEUE_16K: + entry_size = QUEUE_64K; + queue_cmd = MUCR_QUEUE_16K; + cq->num_entries = ENTRY_16K; + break; + case MUCR_QUEUE_32K: + entry_size = QUEUE_128K; + queue_cmd = MUCR_QUEUE_32K; + cq->num_entries = ENTRY_32K; + break; + case MUCR_QUEUE_64K: + entry_size = QUEUE_256K; + queue_cmd = MUCR_QUEUE_64K; + cq->num_entries = ENTRY_64K; + break; + default: + /* wrong queue size from parameter */ + return -EINVAL; + } + + cq->inb_post_q_top = entry_size; + cq->outb_post_q_top = entry_size * 2; + cq->outb_free_q_top = entry_size * 3; + cq->inb_free_q_end = cq->inb_post_q_top - 4; + cq->inb_post_q_end = cq->outb_post_q_top - 4; + cq->outb_post_q_end = cq->outb_free_q_top; + cq->outb_free_q_end = (entry_size * 4) - 4; + *(IOP310_MUMUCR) = queue_cmd; + + cpu_dcache_clean_range((u32)mu_mem, ((u32)mu_mem + entry_size)); + + /* Set head pointers and tail pointers */ + /* equal since they are empty */ + *(IOP310_MUIFHPR) = cq->inb_free_q_top; + *(IOP310_MUIFTPR) = cq->inb_free_q_top; + *(IOP310_MUIPHPR) = cq->inb_post_q_top; + *(IOP310_MUIPTPR) = cq->inb_post_q_top; + *(IOP310_MUOPHPR) = cq->outb_post_q_top; + *(IOP310_MUOPTPR) = cq->outb_post_q_top; + *(IOP310_MUOFHPR) = cq->outb_free_q_top; + *(IOP310_MUOFTPR) = cq->outb_free_q_top; + + *mu_context = (u32) mu; + return 0; +} /* End of mu_cq_request() */ + +/*=======================================================================*/ +/* Procedure: mu_cq_inbound_init() */ +/* */ +/* Description: This function sets up the inbound queues. The caller of */ +/* the function will pass down a linked list of MFA addrs. */ +/* The function will put all the mfa in the free ib queue. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* list - pointer to list of message frame address */ +/* size - number of entries in list */ +/* func - pointer to callback function */ +/* */ +/* Returns: 0 - success */ +/* -EINVAL - invalid parameter */ +/* */ +/* Notes/Assumptions: Only to be called by owner of CQ. */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +int mu_cq_inbound_init(u32 mu_context, mfa_list_t * list, u32 size, + mu_cq_cb_t func) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_cq_t *cq = &mu->cq_desc; + mfa_list_t *tmp_list = list; + u32 mem_offset = 0; + u32 *mem = NULL; + u32 limit; + + /* check parameters */ + if(!list || !func) + { + return -EINVAL; + } + + /* if list size larger than queue size */ + if(size > cq->num_entries) + { + DPRINTK("More MFA entries than inbound free queue can hold!\n"); + return -EINVAL; + } + + /* Get Address Limit */ + limit = *(IOP310_PIALR); + + /* put all MFA in list on free queue */ + while(tmp_list) + { + mem_offset = *IOP310_MUIFHPR & 0xfffff; + mem = (u32 *)((u32)mu_mem + mem_offset); + + /* The MFA value is the offset of the Primary Inbound ATU Base Address */ + *mem = (u32)virt_to_phys(tmp_list->mfa) & ~limit; + + /* move 32 bits to next pointer */ + *(IOP310_MUIFHPR) += sizeof(u32); + + /* if we are at top of queue wrap around */ + if(*(IOP310_MUIFHPR) == cq->inb_free_q_end) + { + DPRINTK("wrap around\n"); + *(IOP310_MUIFHPR) = cq->inb_free_q_top; + } + + /* if the head and tail meet, we have no more space */ + if(*(IOP310_MUIFHPR) == *(IOP310_MUIFTPR)) + { + break; + } + + tmp_list = tmp_list->next_list; + } /* end of while */ + + /* set resource init flag */ + atomic_inc(&cq->init_ref); + /* set callback */ + cq->callback = func; + + return 0; +} /* End of mu_cq_inbound_init() */ + +/*=======================================================================*/ +/* Procedure: mu_cq_enable() */ +/* */ +/* Description: This function enables the circular queues and unmask */ +/* the INTs. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor. */ +/* */ +/* Returns: -EPERM - permission denied */ +/* 0 - success */ +/* */ +/* Notes/Assumptions: Only called after iq80310MuCqIbInit(). */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_cq_enable(u32 mu_context) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_cq_t *cq = &mu->cq_desc; + + /* if no resource init fail */ + if(!atomic_read(&cq->init_ref) || !atomic_read(&cq->in_use)) + { + DPRINTK("Resources not initialized\n"); + return -EPERM; + } + + /* enable circular queues */ + *(IOP310_MUMUCR) |= MUCR_QUEUE_ENABLE; + /* unmask inbound ints */ + *(IOP310_MUIIMR) &= ~(MUIIMR_IBPQ_MASK | MUIIMR_IBFQF_MASK); + /* unmask outbound ints */ + /* the host should unmask this when it sends down */ + /* message frames */ + /* *(IOP310_MUOIMR) &= ~MUOIMR_OBPQ_MASK; */ + + /* enable PATU memory access response */ + *(IOP310_PATUCMD) |= 0x2; + + return 0; +} + +/*=======================================================================*/ +/* Procedure: mu_cq_get_frame() */ +/* */ +/* Description: This function will attempt to retrieve a free message */ +/* frame from the outbound free queue. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* */ +/* Returns: free frame address */ +/* 0xFFFFFFFF - no frame available */ +/* */ +/* Notes/Assumptions: N/A */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline u32 mu_cq_get_frame(u32 mu_context) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_cq_t *cq = &mu->cq_desc; + u32 mem_offset = 0; + u32 *mfa_ptr = NULL; + + spin_lock_irq(&cq->ob_free_lock); + if(*(IOP310_MUOFTPR) == *(IOP310_MUOFHPR)) + { + DPRINTK("No outbound frames!\n"); + spin_unlock_irq(&&cq->ob_free_lock); + return FULL_MASK; + } + /* get address from outbound free tail pointer register */ + mem_offset = *(IOP310_MUOFTPR) & 0xfffff; + /* wrap around if need to */ + *(IOP310_MUOFTPR) += sizeof(u32); + if(*(IOP310_MUOFTPR) == cq->outb_free_q_end) + { + *(IOP310_MUOFTPR) = cq->outb_free_q_top; + } + spin_unlock_irq(&cq->ob_free_lock); + + mfa_ptr = (u32 *)((u8 *)mu_mem + mem_offset); + cpu_dcache_invalidate_range((u32)mfa_ptr, (u32)mfa_ptr+4); + + return *mfa_ptr; +} + +/*=======================================================================*/ +/* Procedure: mu_cq_post_frame() */ +/* */ +/* Description: This function attempt to post the message frame prov by */ +/* the user onto the outbound post qeuue. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* nMfa - message frame address */ +/* */ +/* Returns: -EBUSY - outbound queue full */ +/* 0 - success */ +/* */ +/* Notes/Assumptions: Only the owner of cq shall call this function. */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_cq_post_frame(u32 mu_context, u32 mfa) +{ + iop310_mu_t *mu = (iop310_mu_t *)mu_context; + mu_cq_t *cq = &mu->cq_desc; + u32 irq_assert = 0; + u8 ptr_equal = 0; + u32 mem_offset = 0; + u32 *mem = NULL; + + spin_lock_irq(&cq->ob_post_lock); + + /* see if queue full */ + irq_assert = *(IOP310_MUOISR) & MUOISR_OBPQ_INT; + ptr_equal = (*(IOP310_MUOPHPR) == *(IOP310_MUOPTPR)) ? 1 : 0; + + /* if queue full condition */ + if(irq_assert && ptr_equal) + { + spin_unlock_irq(&cq->ob_post_lock); + return -EBUSY; + } + + mem_offset = *IOP310_MUOPHPR & 0xfffff; + mem = (u32 *)((u8 *)mu_mem + mem_offset); + *mem = (u32)virt_to_bus(mfa); + cpu_dcache_clean_range((u32)mem, (u32)mem+4); + /* move 32 bits to next pointer */ + *(IOP310_MUOPHPR) += sizeof(u32); + + /* if we are at top of queue wrap around */ + if(*(IOP310_MUOPHPR) == cq->outb_post_q_end) + { + DPRINTK("wrap around\n"); + *(IOP310_MUOPHPR) = cq->outb_post_q_top; + } + + spin_unlock_irq(&cq->ob_post_lock); + return 0; +} + +/*=======================================================================*/ +/* Procedure: mu_cq_irq_task() */ +/* */ +/* Description: This funciton is scheduled by the MU irq hdlr. It */ +/* removes all inbound message frames from the ib post q. */ +/* It then passes them to the app. Then it put the mfa */ +/* back on the free queue */ +/* */ +/* Parameters: dev - pointer to MU device descriptor */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: The content of message frame must be perserved */ +/* by app when passed back. Once callback return */ +/* the message frame is considered free. */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +static void mu_cq_irq_task(void *dev) +{ + iop310_mu_t *mu = (iop310_mu_t *)dev; + mu_cq_t *cq = &mu->cq_desc; + u32 *mfa_ptr = NULL; + u32 mem_offset = 0; + u32 *mem = NULL; + + DPRINTK("Entering cq irq task\n"); + + while(*(IOP310_MUIPTPR) != *(IOP310_MUIPHPR)) + { + spin_lock_irq(&cq->ib_post_lock); + /* move tail pointer, wrap if neccesary */ + /* remove MFA from post queue */ + mem_offset = *IOP310_MUIPTPR & 0xfffff; + *(IOP310_MUIPTPR) += sizeof(u32); + if(*(IOP310_MUIPTPR) == mu->cq_desc.inb_post_q_end) + { + *(IOP310_MUIPTPR) = mu->cq_desc.inb_post_q_top; + } + spin_unlock_irq(&cq->ib_post_lock); + + mfa_ptr = (u32 *)((u8 *)mu_mem + mem_offset); + cpu_dcache_invalidate_range((u32)mfa_ptr, (u32)mfa_ptr+4); + + if(cq->callback) + { + DPRINTK("Calling callback\n"); + /* pass frame to app */ + cq->callback(*mfa_ptr | *(IOP310_PIATVR)); + } + + /* put frame back to free queue */ + spin_lock_irq(&cq->ib_free_lock); + mem_offset = *IOP310_MUIFHPR & 0xfffff; + mem = (u32 *)((u32)mu_mem + mem_offset); + *mem = (u32)virt_to_bus(*mfa_ptr); + *(IOP310_MUIFHPR) += sizeof(u32); + if(*(IOP310_MUIFHPR) == cq->inb_free_q_end) + { + *(IOP310_MUIFHPR) = cq->inb_free_q_top; + } + spin_unlock_irq(&cq->ib_free_lock); + } + + *(IOP310_MUIIMR) &= ~MUIIMR_IBPQ_MASK; +} + +/*=======================================================================*/ +/* Procedure: mu_cq_free() */ +/* */ +/* Description: This function is called to release ownership of CQ. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor. */ +/* */ +/* Returns: 0 - success */ +/* -EPERM - permission denied. */ +/* */ +/* Notes/Assumptions: Only the owner of CQ shall call this. */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_cq_free(u32 mu_context) +{ + iop310_mu_t *mu = (iop310_mu_t *)mu_context; + mu_cq_t *cq = &mu->cq_desc; + + /* check ownership */ + if(!atomic_read(&cq->in_use)) + { + return -EPERM; + } + + /* reset variables */ + atomic_dec(&cq->in_use); + atomic_dec(&cq->init_ref); + cq->callback = NULL; + + /* disable CQ and mask inbound/outbound CQ INTs */ + *(IOP310_MUMUCR) = NULL_MASK; + *(IOP310_MUIIMR) |= MUIIMR_IBPQ_MASK | MUIIMR_IBFQF_MASK; + *(IOP310_MUOIMR) |= MUOIMR_OBPQ_MASK; + + return 0; +} + + +/*===========================MU Index Registers==========================*/ + +/*=======================================================================*/ +/* Procedure: mu_ir_request() */ +/* */ +/* Description: This function is used to request the ownership of the */ +/* Index Registers mechanism. */ +/* */ +/* Parameters: NONE */ +/* */ +/* Returns: iop310_mu_t * - success */ +/* NULL - failed */ +/* */ +/* Notes/Assumptions: The requestor will own IR mechanism if successful */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_ir_request(u32 * mu_context) +{ + iop310_mu_t *mu = &mu_dev; + mu_ir_t *ir = &mu->ir_desc; + + /* if onwed already */ + if(atomic_read(&ir->in_use)) + { + return -EBUSY; + } + + /* set ownership */ + atomic_inc(&ir->in_use); + *mu_context = (u32)mu; + return 0; +} + +/*=======================================================================*/ +/* Procedure: mu_ir_set_callback() */ +/* */ +/* Description: This function sets the callback function used to recv */ +/* incoming messages. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* func - pointer to callback */ +/* */ +/* Returns: 0 - success */ +/* -EINVAL - invalid parameter */ +/* */ +/* Notes/Assumptions: called after claiming ownership of IR */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_ir_set_callback(u32 mu_context, mu_ir_cb_t func) +{ + iop310_mu_t *mu = (iop310_mu_t *) mu_context; + mu_ir_t *ir = &mu->ir_desc; + + /* check parameter */ + if(!func) + { + return -EINVAL; + } + + /* set parameter */ + ir->callback = func; + + /* unmask INTs */ + *(IOP310_MUIIMR) &= ~MUIIMR_IR_MASK; + + return 0; +} + +/*=======================================================================*/ +/* Procedure: mu_ir_irq_task() */ +/* */ +/* Description: This function retrieves the offset from temp store in */ +/* the IR descriptor and computes the message address. */ +/* After passing the address it unmasks the INT bit. */ +/* */ +/* Parameters: dev - pointer to MU device descriptor */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: NONE */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline static void mu_ir_irq_task(void *dev) +{ + iop310_mu_t *mu = (iop310_mu_t *)dev; + mu_ir_t *ir = &mu->ir_desc; + u32 addr_val = 0; + u32 *mem = NULL; + + /* calculate message address */ + /* start from Primary Inbound Address Translation Value Register */ + addr_val = ir->offset + *(IOP310_PIATVR); + + mem = phys_to_virt(addr_val); + /* pass value to callback */ + if(ir->callback) + { + ir->callback(*mem); + } + + /* Unmask the inbound INT */ + *(IOP310_MUIIMR) &= ~MUIIMR_IR_MASK; +} + +/*=======================================================================*/ +/* Procedure: mu_ir_free() */ +/* */ +/* Description: This function releases ownership of IR. */ +/* */ +/* Parameters: mu - pointer to MU device descriptor */ +/* */ +/* Returns: -EPERM - permission denied */ +/* 0 - success */ +/* */ +/* Notes/Assumptions: Only called by the owner of IR. */ +/* */ +/* History: Dave Jiang 08/20/01 Initial Creation */ +/*=======================================================================*/ +inline int mu_ir_free(u32 mu_context) +{ + iop310_mu_t *mu = (iop310_mu_t *)mu_context; + mu_ir_t *ir = &mu->ir_desc; + + /* check ownership */ + if(!atomic_read(&ir->in_use)) + { + return -EPERM; + } + + /* unset owner */ + atomic_dec(&ir->in_use); + + + ir->callback = NULL; + + /* mask INT */ + *(IOP310_MUIIMR) |= MUIIMR_IR_MASK; + + return 0; +} + + +/*===========================MU Common Functions=========================*/ + +/*=======================================================================*/ +/* Procedure: mu_irq_handler() */ +/* */ +/* Description: This function is the interrupt handler for MU. It */ +/* checks for MU int bit asserted and then schedules the */ +/* proper bottom half task to take care of the INTs. */ +/* */ +/* Parameters: irq - IRQ number (not used) */ +/* dev_id - pointer to MU device descriptor */ +/* regs - CPU registers (not used) */ +/* */ +/* Returns: NONE */ +/* */ +/* Notes/Assumptions: This function is only called by XScale IRQ hdlr. */ +/* */ +/* History: Dave Jiang 08/16/01 Initial Creation */ +/*=======================================================================*/ +static void mu_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + iop310_mu_t *mu = (iop310_mu_t *)dev_id; + u32 irq_status; + u32 iisr; + volatile u32 *reg_val_ptr; + u8 msg_reg = 0; + u32 mask = 0; + mu_msg_desc_t *msg_desc = NULL; + int thresh; + + /* get inbound irq status */ + iisr = *(IOP310_MUIISR); + + thresh = atomic_read(&mu->irq_thresh); + + do + { + /* if message registers INT */ + if(iisr & (MUIISR_IBMSG_0_INT | MUIISR_IBMSG_1_INT)) + { + if(!list_empty(&mu->msg_desc.free_stack)) + { + /* get message descriptor from free stack */ + spin_lock(&mu->msg_desc.free_lock); + msg_desc = MSG_ENTRY(mu->msg_desc.free_stack.next); + list_del(&msg_desc->link); + spin_unlock(&mu->msg_desc.free_lock); + } + else + { + DPRINTK("Out of message descriptors!\n"); + return; + } + + /* if inbound register 0 */ + if(iisr & MUIISR_IBMSG_0_INT) + { + msg_reg = INBOUND_REG_0; + reg_val_ptr = IOP310_MUIMR0; + mask = MUIISR_IBMSG_0_INT; + } + else /* or inbound register 1 */ + { + msg_reg = INBOUND_REG_1; + reg_val_ptr = IOP310_MUIMR1; + mask = MUIISR_IBMSG_1_INT; + } + + /* set register number */ + msg_desc->reg_num = msg_reg; + + /* record register value */ + msg_desc->message = *(reg_val_ptr); + + /* put message descriptor on process queue */ + spin_lock(&mu->msg_desc.process_lock); + list_add_tail(&msg_desc->link, &mu->msg_desc.process_q); + spin_unlock(&mu->msg_desc.process_lock); + + /* read/clear INT */ + *(IOP310_MUIISR) |= ~mask; + /* schedule bottom half tasklet */ + mu->msg_desc.msg_task.data = (void *)mu; + /* task goes to the immediate task queue */ + queue_task(&mu->msg_desc.msg_task, &tq_immediate); + } + + /* if doorbell INT */ + if(iisr & (MUIISR_IBDB_FIQ2_INT | MUIISR_IBDB_IRQ_INT)) + { + spin_lock(&mu->db_desc.reg_lock); + /* get register value */ + mu->db_desc.reg_val |= *(IOP310_MUIDR); + /* read clear register, this clear INTs */ + *(IOP310_MUIDR) |= mu->db_desc.reg_val; + spin_unlock(&mu->db_desc.reg_lock); + + /* schedule bottom half tasklet */ + mu->db_desc.db_task.data = (void *)mu; + /* task goes to the immediate task queue */ + queue_task(&mu->db_desc.db_task, &tq_immediate); + } + + /* if inbound post queue */ + if(iisr & MUIISR_IBPQ_INT) + { + /* ack INT bit , read/clear */ + *(IOP310_MUIISR) |= MUIISR_IBPQ_INT; + *(IOP310_MUIIMR) |= MUIIMR_IBPQ_MASK; + /* schedule task */ + mu->cq_desc.cq_task.data = (void *)mu; + queue_task(&mu->cq_desc.cq_task, &tq_immediate); + } + + /* if inbound free queue full */ + if(iisr & MUIISR_IBFQF_INT) + { + /* ack INT bit */ + *(IOP310_MUIISR) &= ~(MUIISR_IBFQF_INT); + } + + /* if index register */ + if(iisr & MUIISR_IR_INT) + { + /* mask interrupt bit */ + /* store offset */ + /* read/clear interrupt status */ + *(IOP310_MUIIMR) |= MUIIMR_IR_MASK; + mu->ir_desc.offset = *(IOP310_MUIAR); + /* read clear INT */ + *(IOP310_MUIISR) |= MUIISR_IR_INT; + /* queue task */ + mu->ir_desc.ir_task.data = (void *)mu; + queue_task(&mu->ir_desc.ir_task, &tq_immediate); + } + + /* get int status */ + iisr = *(IOP310_MUIISR); + + /* get FIQ status */ + irq_status = *(IOP310_FIQ2ISR); + } + while(irq_status && --thresh); + + /* mark IMMEDIATE BH for execute */ + mark_bh(IMMEDIATE_BH); +} + +/*=======================================================================*/ +/* Procedure: mu_init() */ +/* */ +/* Description: This function initializes the MU to pre-own state. */ +/* */ +/* Parameters: NONE */ +/* */ +/* Returns: 0 - success */ +/* -ENOMEM - no memory allocated for circular queues */ +/* -EBUSY - cannot alloc irq */ +/* */ +/* Notes/Assumptions: This function is only called by kernel at init. */ +/* */ +/* History: Dave Jiang 08/16/01 Initial Creation */ +/*=======================================================================*/ +static int __init mu_init(void) +{ + iop310_mu_t *mu = &mu_dev; + int err = 0; + + printk("Intel 80310 MU Copyright(c) 2001 Intel Corporation\n"); + + /* check to see if we allocated QBAR at 0x100000 align, 0x100000 size */ + if(!mu_mem) + { + DPRINTK("No memory allocated for circular queue\n"); + return -ENOMEM; + } + +#ifdef REGMAP + mu->regs = (mu_regs_t *)IOP310_MUIMR0; +#endif + + /* mask all INTs */ + *(IOP310_MUIIMR) = FULL_MASK; + *(IOP310_MUOIMR) = FULL_MASK; + + /* set irq */ + mu->irq = IRQ_IOP310_MU; + + /* setup message registers */ + mu->msg_desc.callback_0 = NULL; + mu->msg_desc.callback_1 = NULL; + spin_lock_init(&mu->msg_desc.free_lock); + spin_lock_init(&mu->msg_desc.process_lock); + INIT_LIST_HEAD(&mu->msg_desc.free_stack); + INIT_LIST_HEAD(&mu->msg_desc.process_q); + atomic_set(&mu->msg_desc.res_init, 0); + atomic_set(&mu->msg_desc.in_use, 0); + mu->msg_desc.msg_task.sync = 0; + mu->msg_desc.msg_task.routine = mu_msg_irq_task; + + + /* setup doorbell registers */ + mu->db_desc.reg_val = 0; + mu->db_desc.callback = NULL; + atomic_set(&mu->db_desc.in_use, 0); + spin_lock_init(&mu->db_desc.reg_lock); + mu->db_desc.db_task.sync = 0; + mu->db_desc.db_task.routine = mu_db_irq_task; + + /* setup circular queues */ + mu->cq_desc.q_size = 0; + mu->cq_desc.callback = NULL; + spin_lock_init(&mu->cq_desc.ib_free_lock); + spin_lock_init(&mu->cq_desc.ib_post_lock); + spin_lock_init(&mu->cq_desc.tObFreeQLock); + spin_lock_init(&mu->cq_desc.ob_post_lock); + atomic_set(&mu->cq_desc.init_ref, 0); + atomic_set(&mu->cq_desc.in_use, 0); + mu->cq_desc.cq_task.sync = 0; + mu->cq_desc.cq_task.routine = mu_cq_irq_task; + + /* set QBAR */ + *(IOP310_MUQBAR) = (u32)virt_to_phys(mu_mem); + + /* setup index registers */ + mu->ir_desc.offset = 0; + mu->ir_desc.callback = NULL; + atomic_set(&mu->ir_desc.in_use, 0); + mu->ir_desc.ir_task.sync = 0; + mu->ir_desc.ir_task.routine = mu_ir_irq_task; + + + /* request IRQ for the MU */ + err = request_irq(mu->irq, mu_irq_handler, SA_INTERRUPT, + "i80310 MU", (void *)mu); + if(err < 0) + { + printk(KERN_ERR "%s: unable to request IRQ %d for MU: %d\n", + "i80310 MU", mu->irq, err); + /* reset ref count */ + return -EBUSY; + } + + /* set irq threshold */ + atomic_set(&mu->irq_thresh, DEFAULT_MU_IRQ_THRESH); + + return 0; +} + +/*=======================================================================*/ +/* Procedure: mu_set_irq_threshold() */ +/* */ +/* Description: This function readjust the threshold for the irq. */ +/* */ +/* Parameters: mu: pointer to mu device descriptor */ +/* value: value of new irq threshold */ +/* */ +/* Returns: N/A */ +/* */ +/* Notes/Assumptions: default is set at 10 */ +/* */ +/* History: Dave Jiang 08/27/01 Initial Creation */ +/*=======================================================================*/ +void mu_set_irq_threshold(u32 mu_context, int thresh) +{ + iop310_mu_t *mu = (iop310_mu_t *)mu_context; + + atomic_set(&mu->irq_thresh, thresh); +}/* End of mu_set_irq_threshold() */ + + +EXPORT_SYMBOL_NOVERS(mu_msg_request); +EXPORT_SYMBOL_NOVERS(mu_msg_set_callback); +EXPORT_SYMBOL_NOVERS(mu_msg_post); +EXPORT_SYMBOL_NOVERS(mu_msg_free); +EXPORT_SYMBOL_NOVERS(mu_db_request); +EXPORT_SYMBOL_NOVERS(mu_db_set_callback); +EXPORT_SYMBOL_NOVERS(mu_db_ring); +EXPORT_SYMBOL_NOVERS(mu_db_free); +EXPORT_SYMBOL_NOVERS(mu_cq_request); +EXPORT_SYMBOL_NOVERS(mu_cq_inbound_init); +EXPORT_SYMBOL_NOVERS(mu_cq_enable); +EXPORT_SYMBOL_NOVERS(mu_cq_get_frame); +EXPORT_SYMBOL_NOVERS(mu_cq_post_frame); +EXPORT_SYMBOL_NOVERS(mu_cq_free); +EXPORT_SYMBOL_NOVERS(mu_ir_request); +EXPORT_SYMBOL_NOVERS(mu_ir_set_callback); +EXPORT_SYMBOL_NOVERS(mu_ir_free); +EXPORT_SYMBOL_NOVERS(mu_set_irq_threshold); + +module_init(mu_init); + diff -Nru a/arch/arm/mach-iop3xx/message.h b/arch/arm/mach-iop3xx/message.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/message.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,185 @@ +/* + * Private Definitions for IOP310 MU + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2001 Intel 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. + * + */ + +#ifndef _MU_PRIVATE_H_ +#define _MU_PRIVATE_H_ + +#include + +#define DEFAULT_MU_IRQ_THRESH 10 + +#define FULL_MASK 0xffffffff +#define NULL_MASK 0x00000000 + +#define MAX_MSG_DESC 32 +#define MAX_MFA_DESC 128 + +#define FIQ2ISR_MU 0x00000004 +#define IRQISR_MU 0x00000100 + +#define INBOUND_REG_UNDEF 0x00 +#define INBOUND_REG_0 0x01 +#define INBOUND_REG_1 0x02 +#define INBOUND_REG_BOTH (INBOUND_REG_0 | INBOUND_REG_1) + +#define OUTBOUND_REG_0 0x01 +#define OUTBOUND_REG_1 0x02 + +#define MSG_FREE_HARDMODE 0x01 +#define MSG_FREE_SOFTMODE 0x02 + +#define MUIISR_IBMSG_0_INT 0x0001 +#define MUIISR_IBMSG_1_INT 0x0002 +#define MUIISR_IBDB_FIQ2_INT 0x0004 +#define MUIISR_IBDB_IRQ_INT 0x0008 +#define MUIISR_IBPQ_INT 0x0010 +#define MUIISR_IBFQF_INT 0x0020 +#define MUIISR_IR_INT 0x0040 + +#define MUIIMR_IBMSG_0_MASK 0x0001 +#define MUIIMR_IBMSG_1_MASK 0x0002 +#define MUIIMR_IBDB_FIQ2_MASK 0x0004 +#define MUIIMR_IBDB_IRQ_MASK 0x0008 +#define MUIIMR_IBPQ_MASK 0x0010 +#define MUIIMR_IBFQF_MASK 0x0020 +#define MUIIMR_IR_MASK 0x0040 + +#define MUOISR_OBMSG_0_INT 0x0001 +#define MUOISR_OBMSG_1_INT 0x0002 +#define MUOISR_OBDB_INT 0x0004 +#define MUOISR_OBPQ_INT 0x0008 +#define MUOISR_PCI_INTA 0x0010 +#define MUOISR_PCI_INTB 0x0020 +#define MUOISR_PCI_INTC 0x0040 +#define MUOISR_PCI_INTD 0x0080 + +#define MUOIMR_OBMSG_0_MASK 0x0001 +#define MUOIMR_OBMSG_1_MASK 0x0002 +#define MUOIMR_OBDB_MASK 0x0004 +#define MUOIMR_OBPQ_MASK 0x0008 +#define MUOIMR_PCI_MASKA 0x0010 +#define MUOIMR_PCI_MASKB 0x0020 +#define MUOIMR_PCI_MASKC 0x0040 +#define MUOIMR_PCI_MASKD 0x0080 + +/* MU hardware registers */ +typedef struct _mu_regs +{ + volatile u32 IMR0; + volatile u32 IMR1; + volatile u32 OMR0; + volatile u32 OMR1; + volatile u32 IDR; + volatile u32 IISR; + volatile u32 IIMR; + volatile u32 ODR; + volatile u32 OISR; + volatile u32 OIMR; + u32 reserved_0[7]; + volatile u32 MUCR; + volatile u32 QBAR; + u32 reserved_1[3]; + volatile u32 IFHPR; + volatile u32 IFTPR; + volatile u32 IPHPR; + volatile u32 IPTPR; + volatile u32 OFHPR; + volatile u32 OFTPR; + volatile u32 OPHPR; + volatile u32 OPTPR; + volatile u32 IAR; +} mu_regs_t; + +/** MU Message Registers **/ + + +/* MU Message Registers Descriptor */ +typedef struct _mu_msgreg +{ + atomic_t in_use; /* usage flag */ + atomic_t res_init; /* resource usage flag */ + struct list_head free_stack; /* free descriptor stack */ + struct list_head process_q; /* process queue */ + spinlock_t free_lock; /* free stack spinlock */ + spinlock_t process_lock; /* process queue spinlock */ + mu_msg_cb_t callback_0; /* callback for inbound 0 */ + mu_msg_cb_t callback_1; /* callback for inbound 1 */ + struct tq_struct msg_task; /* message task */ +} mu_msg_t; + +/** MU Doorbell Registers **/ + +/* MU Doorbell Registers descriptor */ +typedef struct _mu_dbreg +{ + atomic_t in_use; /* usage flag */ + mu_db_cb_t callback; /* callback */ + u32 reg_val; /* register value */ + spinlock_t reg_lock; /* register value spinlock */ + struct tq_struct db_task; /* doorbell task */ +} mu_db_t; + +/** Circular Queues registers **/ + +/* MU circular queues registers descriptor */ +typedef struct _mu_cqreg +{ + atomic_t in_use; /* usage flag */ + atomic_t init_ref; /* Initialization reference count */ + u32 q_size; /* Size of the queues */ + u32 num_entries; /* Number of entries in Q */ + spinlock_t ib_free_lock; /* spinlock for Inbound free queue */ + spinlock_t ib_post_lock; /* spinlock for Inbound free queue */ + spinlock_t ob_free_lock; /* spinlock for Outbound free queue */ + spinlock_t ob_post_lock; /* spinlock for Outbound post queue */ + mu_cq_cb_t callback; /* Inbound callback function */ + struct tq_struct cq_task; /* circular queues task */ + u32 inb_free_q_top; /* Inbound free queue top */ + u32 inb_free_q_end; /* Inbound free queue bottom */ + u32 inb_post_q_top; /* Inbound post queue top */ + u32 inb_post_q_end; /* Inbound post queue bottom */ + u32 outb_free_q_top; /* Outbound free queue top */ + u32 outb_free_q_end; /* Outbound free queue bottom */ + u32 outb_post_q_top; /* Outbound post queue top */ + u32 outb_post_q_end; /* Outbound post queue bottom */ +} mu_cq_t; + +/* MU Index Registers */ + +/* MU Index Registers Descriptor */ +typedef struct _mu_ir_reg +{ + atomic_t in_use; /* Usage flag */ + mu_ir_cb_t callback; /* callback function */ + u32 offset; /* offset of address */ + struct tq_struct ir_task; /* Index Registers task */ +} mu_ir_t; + + +/* MU device descriptor */ +typedef struct _mu_desc +{ + u32 irq; /* interrupt number */ + mu_regs_t *regs; /* MU local mapped registers */ + atomic_t irq_thresh; /* irq threshold */ + mu_msg_t msg_desc; /* MU Msg Register */ + mu_db_t db_desc; /* MU Doorbell registers */ + mu_cq_t cq_desc; /* MU Circular Queues Registers */ + mu_ir_t ir_desc; /* MU INDEX Registers */ +} iop310_mu_t; + + +#define MSG_ENTRY(list) list_entry((list), mu_msg_desc_t, link) + +extern void *mu_mem; + +#endif diff -Nru a/arch/arm/mach-iop3xx/mm-321.c b/arch/arm/mach-iop3xx/mm-321.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/mm-321.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/mach-iop3xx/mm.c + * + * Low level memory intialization for IOP321 based systems + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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 + + +/* + * Standard IO mapping for all IOP321 based systems + */ +static struct map_desc iop80321_std_desc[] __initdata = { + /* virtual physical length domain r w c b */ + + /* mem mapped registers */ + { 0xfff00000, 0xffffe000, 0x00002000, DOMAIN_IO, 0, 1, 0, 0}, + + /* PCI IO space */ + { 0xfe000000, 0x90000000, 0x00020000, DOMAIN_IO, 0, 1, 0, 0}, + LAST_DESC +}; + +void __init iop321_map_io(void) +{ + iotable_init(iop80321_std_desc); +} + +/* + * IQ80321 & IQ31244 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ +#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244) +static struct map_desc iq80321_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + + /* on-board devices */ + { 0xfe800000, 0xfe800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0}, + LAST_DESC +}; + +void __init iq80321_map_io(void) +{ + iop321_map_io(); + + iotable_init(iq80321_io_desc); +} +#endif // CONFIG_ARCH_IQ80321 || CONFIG_ARCH_IQ31244 + diff -Nru a/arch/arm/mach-iop3xx/mm.c b/arch/arm/mach-iop3xx/mm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/mm.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-iop310/mm.c + * + * Low level memory intialization for IOP310 based systems + * + * Author: Nicolas Pitre + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 + +#ifdef CONFIG_IOP310_MU +#include "message.h" +#endif + +/* + * Standard IO mapping for all IOP310 based systems + */ +static struct map_desc iop80310_std_desc[] __initdata = { + /* virtual physical length domain r w c b */ + // IOP310 Memory Mapped Registers + { 0xe8001000, 0x00001000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + // PCI I/O Space + { 0xfe000000, 0x90000000, 0x00020000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init iop310_map_io(void) +{ +#ifdef CONFIG_IOP310_MU + /* acquiring 1MB of memory aligned on 1MB boundary for MU */ + mu_mem = __alloc_bootmem(0x100000, 0x100000, 0); +#endif + + iotable_init(iop80310_std_desc); +} + +/* + * IQ80310 specific IO mappings + */ +#ifdef CONFIG_ARCH_IQ80310 +static struct map_desc iq80310_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + // IQ80310 On-Board Devices + { 0xfe800000, 0xfe800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init iq80310_map_io(void) +{ + iop310_map_io(); + + iotable_init(iq80310_io_desc); +} +#endif // CONFIG_ARCH_IQ80310 + diff -Nru a/arch/arm/mach-iop3xx/pci-auto.c b/arch/arm/mach-iop3xx/pci-auto.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/pci-auto.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,380 @@ +/* + * arch/arm/mach-iop310/pci-auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 + +// #define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int bar_limit) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask, bar_nr = 0; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + DBG("PCI Autoconfig: Bridge %d. IO_FILTER = %#010x..%#010x\n", + current_bus, + (pciauto_upper_iospc & 0x0000f000) >> 8, + pciauto_upper_iospc >> 16); + + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) + { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + /* If config space read fails from this device, move on */ + if (early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + DBG("Vendor id %#06x\n", vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } + else + { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_5); + } + } + } + return sub_bus; +} diff -Nru a/arch/arm/mach-iop3xx/pci.c b/arch/arm/mach-iop3xx/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,250 @@ +/* + * arch/arm/mach-iop310/pci.c + * + * Generic PCI support functionality that should eventually move to + * arch/arm/kernel/bios32.c. Derived from support in ppc and alpha. + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +/* + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * some boards that don't follow the PCI spec's suggestion so we + * break this piece out separately. + */ +static inline u8 +bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +u8 __init +common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(dev->bus->number); + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +/* + * Null PCI config access functions, for the case when we can't + * find a hose. + */ +#define NULL_PCI_OP(rw, size, type) \ +static int \ +null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + return PCIBIOS_DEVICE_NOT_FOUND; \ +} + + NULL_PCI_OP(read, byte, u8 *) + NULL_PCI_OP(read, word, u16 *) + NULL_PCI_OP(read, dword, u32 *) + NULL_PCI_OP(write, byte, u8) + NULL_PCI_OP(write, word, u16) +NULL_PCI_OP(write, dword, u32) + +static struct pci_ops null_pci_ops = +{ + null_read_config_byte, + null_read_config_word, + null_read_config_dword, + null_write_config_byte, + null_write_config_word, + null_write_config_dword +}; + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +struct pci_dev * +fake_pci_dev(struct pci_controller *hose, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + if (hose == 0) { + hose = pci_bus_to_hose(busnr); + if (hose == 0) + printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); + } + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose? hose->ops: &null_pci_ops; + return &dev; +} + +static int next_controller_index; + +struct pci_controller * __init +pcibios_alloc_controller(void) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *)kmalloc(sizeof(*hose), GFP_KERNEL); + memset(hose, 0, sizeof(struct pci_controller)); + + *hose_tail = hose; + hose_tail = &hose->next; + + hose->index = next_controller_index++; + + return hose; +} + +struct pci_controller * +pci_bus_to_hose(int bus) +{ + struct pci_controller *hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +void __init +pci_exclude_device(unsigned char bus, unsigned char devfn) +{ + struct pci_dev *dev, *pdev = NULL; + + /* Walk the pci device list */ + pci_for_each_dev(dev) + { + if ((dev->bus->number == bus) && (dev->devfn == devfn)) + { + /* + * Remove the device from the global and + * bus lists. + */ + list_del(&(dev->global_list)); + list_del(&(dev->bus_list)); + + /* Free the pci_dev structure */ + kfree(dev); + + break; + } + pdev = dev; + } +} + +static inline void __init alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + pr = pci_find_parent_resource(dev, r); + if(!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Can not allocate resource region %d" \ + " of device %s\n", idx, dev->slot_name); + r->end -= r->start; + r->start = 0; + } +} + +void __init +pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + int i; + struct resource *res, *pr; + + if(!bus_list) return; + + /* Depth-First Search on bus tree */ + for (ln = bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + pci_read_bridge_bases(bus); + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Can not allocate resource region " + "%d of PCI bridge %d\n", i, bus->number); + DBG("PCI: resource is %lx..%lx (%lx)\n", + res->start, res->end, res->flags); + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +void __init pcibios_allocate_resources(void) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r; + + pci_for_each_dev(dev) + { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) + { + r = &dev->resource[idx]; + + if(r->parent) + continue; + if(!r->start) + continue; + + alloc_resource(dev, idx); + } + } +} + + diff -Nru a/arch/arm/mach-iop3xx/pmon.c b/arch/arm/mach-iop3xx/pmon.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/pmon.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,285 @@ +/* + * linux/arch/arm/mach-iop310/pmon.c + * + * Support functions for the Intel 80312 Performance Monitor Unit + * See Documentation/arm/XScale/IOP310/pmon.txt for API + * + * Author: Chen Chen (chen.chen@intel.com) + * Copyright (C) 2001 Intel 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. + * + * History: 07/23/2001 Chen Chen + * Initial Creation + * 07/27/2001 Chen Chen + * Add interrupt routine + * 09/28/2001 dsaxena + * API and code cleanup, merge into iop310 tree + * + *************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#include +#endif + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK(s, args...) printk("80310PMON: " s, ## args) +#else +#define DPRINTK(s, args...) +#endif + +#define ENABLE_INTERRUPT 0x00000001 +#define ENABLE_COUNTERS 0xFFFFFFFB +#define OVERFLOW 0xFFFFFFFF +#define NUM_OF_PECR 14 +#define EMISR_SHIFT 1 +#define EMISR_MASK 0x00000001 +#define PMON_INT_MASK 0x00000010 + +static atomic_t usage; +static int claim_id; +iop310_pmon_res_t pmon_results; + + +/* static prototypes */ +static void pmon_irq_handler(int, void *, struct pt_regs *); + +/*=======================================================================*/ +/* Procedure: pmon_irq_handler() */ +/* */ +/* Description: This function is the interrupt handler for the intel */ +/* 80312 PMON. When overflow occurs in PECR and GTSR */ +/* registers, an interrupt is generated to the intel */ +/* 80200 chip. This function handles the interrupt. */ +/* It increments the overflow counts and records it into */ +/* the device data structure. */ +/* */ +/* Parameters: int nIrq -- not used */ +/* void * pDevId -- not used */ +/* pt_regs * pRegs -- not used */ +/* */ +/* Returns: void */ +/* */ +/* Notes/Assumptions: none */ +/* */ +/* History: Chen Chen 07/27/2001 */ +/* Initial Creation */ +/* dsaxena 09/28/2001 */ +/* Removed looping and checking on FIQISR1 */ +/*=======================================================================*/ +static void pmon_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 em_isr_status = 0; + u32 i = 0; + + DPRINTK("enter pmon_irq_handler()\n"); + + /* get EMISR status */ + em_isr_status = *(IOP310_PMONEMISR); + + /* clear interrupts by writing back to it */ + /* since this is a read-clear register */ + *(IOP310_PMONEMISR) |= em_isr_status; + + /* if global timer overflows, increment the counter */ + if(em_isr_status & EMISR_MASK) + { + pmon_results.timestamp_overflow++; + } + + /* shift register value to look at the next bit */ + em_isr_status = em_isr_status >> 1; + + /*loop to look at each PECR to see if overflow occurred */ + for(i = 0; i < NUM_OF_PECR; i++) + { + /* if overflow occurred, increment the counter */ + if(em_isr_status & EMISR_MASK) + { + pmon_results.event_overflow[i]++; + } + /* shift register value to look at the next bit */ + em_isr_status = em_isr_status >> 1; + } + + DPRINTK("exit pmon_irq_handler()\n"); +} + +/*=======================================================================*/ +/* Procedure: iop310_pmon_claim() */ +/* */ +/* Description: This function allows the user to claim the usage of */ +/* PMON. The function returns an identifier. When the */ +/* user is done using the PMON, the user has to */ +/* call iop310_pmon_release with this identifier to */ +/* release the PMON. */ +/* */ +/* Parameters: None */ +/* */ +/* Returns: success: Int -- identifier being returned to the user */ +/* failure: -EBUSY */ +/* */ +/* History: Chen Chen 07/23/2001 Initial Creation */ +/*=======================================================================*/ +int iop310_pmon_claim(void) +{ + int err; + + DPRINTK("enter pmon_claim()\n"); + + /* if unable to read the usage variable, return with busy */ + if(atomic_read(&usage)) + { + return -EBUSY; + } + + /* increment the usage variable */ + atomic_inc(&usage); + + /* register the interrupt handler */ + err = request_irq(IRQ_IOP310_PMON, pmon_irq_handler, + SA_INTERRUPT, "IOP310 PMON", &pmon_results); + + /* return if unable to register the interrupt handler */ + if(err < 0) + { + DPRINTK(KERN_ERR "unable to request IRQ for PMON: %d\n", err); + return err; + } + + memzero(&pmon_results, sizeof(pmon_results)); + + DPRINTK("exit pmon_claim()\n"); + + return ++claim_id; +} + +/*=======================================================================*/ +/* Procedure: pmon_release() */ +/* */ +/* Description: When this function is called, it will release the PMON.*/ +/* When the user is done with the PMON, the user need to */ +/* call this function with the identifier they got from */ +/* calling the i80312PmuClaim() to release the PMON. */ +/* */ +/* Parameters: u32 nClaimId */ +/* The identifier user got when calling i80312PmuClaim() */ +/* */ +/* Returns: success: 0 */ +/* failure: -EPERM */ +/* */ +/* Notes/Assumptions: The user will release the PMON when done monitoring*/ +/* */ +/* History: Chen Chen 07/23/2001 Initial Creation */ +/*=======================================================================*/ +int iop310_pmon_release(int claim) +{ + DPRINTK("enter pmon_release()\n"); + + /* if the passed in id number doesn't match local id number, */ + /* return with wrong parameter */ + if(claim != claim_id) + { + return -EPERM; + } + + atomic_dec(&usage); + + /* un-register the interrupt handler */ + free_irq(IRQ_IOP310_PMON, NULL); + + DPRINTK("exit pmon_release()\n"); + + return 0; +} + +/*=======================================================================*/ +/* Procedure: iop310_pmon_start() */ +/* */ +/* Description: Each mode allows the user to monitor a set of events. */ +/* The user need to call this function with a mode to */ +/* start the PMON monitoring process. There are eight */ +/* monitored mode specified in the Event Select Register.*/ +/* */ +/* Parameters: u32 nClaimID */ +/* The identifier user got when calling i80312PmuClaim() */ +/* u32 nMode */ +/* The mode user would like to monitor in */ +/* */ +/* Returns: success: 0 */ +/* failure: -EPERM */ +/* */ +/* Notes/Assumptions: None */ +/* */ +/* History: Chen Chen 07/23/2001 Initial Creation */ +/* Dave Jiang 08/27/01 Combied Int enable & counter */ +/*=======================================================================*/ +int iop310_pmon_start(int claim, int mode) +{ + DPRINTK("enter pmon_start()\n"); + + if(claim != claim_id) + { + return -EPERM; + } + + /* enable interrupt bit in Global Timer Mode Register */ + /* enable all counters in Global Timer Mode Register */ + *IOP310_PMONGTMR |= (ENABLE_INTERRUPT | ENABLE_COUNTERS); + + /* set the Event Select Register to the appropriate mode */ + /* (writing to ESR, also cause GTSR to reset to 0) */ + *IOP310_PMONESR |= mode; + + DPRINTK("exit pmon_start()\n"); + + return 0; +} + +/*=======================================================================*/ +/* Procedure: pmon_stop() */ +/* */ +/* Description: When this function is called, the PMON will stop */ +/* monitoring the events. It will read all registers, */ +/* and record them into pPmuResult. */ +/* */ +/* Parameters: struct i80312PmuResults pPmuResult */ +/* the place to write the result back to */ +/* */ +/* Returns: success: 0 */ +/* */ +/* Notes/Assumptions: None */ +/* */ +/* History: Chen Chen 07/23/2001 Initial Creation */ +/*=======================================================================*/ +int iop310_pmon_stop(iop310_pmon_res_t *pmon_result) +{ + DPRINTK("enter pmon_stop()\n"); + + memcpy(pmon_result, &pmon_results, sizeof(iop310_pmon_res_t)); + + /* reset the monitoring mode back to 0 -- disable monitor */ + *IOP310_PMONESR = IOP310_PMON_MODE0; + + DPRINTK("exit pmon_stop()\n"); + + return 0; +} + +EXPORT_SYMBOL_NOVERS(iop310_pmon_claim); +EXPORT_SYMBOL_NOVERS(iop310_pmon_release); +EXPORT_SYMBOL_NOVERS(iop310_pmon_start); +EXPORT_SYMBOL_NOVERS(iop310_pmon_stop); + diff -Nru a/arch/arm/mach-iop3xx/xs80200-irq.c b/arch/arm/mach-iop3xx/xs80200-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-iop3xx/xs80200-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,69 @@ +/* + * linux/arch/arm/mach-iop310/xs80200-irq.c + * + * Generic IRQ handling for the XS80200 XScale core. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 + +void +xs80200_irq_mask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; + case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void +xs80200_irq_unmask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; + case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void __init xs80200_init_irq(void) +{ + int i; + long intstr; + + for (i = 0; i < NR_XS80200_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = xs80200_irq_mask; + irq_desc[i].mask = xs80200_irq_mask; + irq_desc[i].unmask = xs80200_irq_unmask; + } + + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (0)); +} + + diff -Nru a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/Makefile Thu Dec 4 16:24:26 2003 @@ -0,0 +1,28 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := ixp2000.o + +# Object file lists. + +obj-y := arch.o mm.o ixp2000-irq.o ixp2000-pci.o pci.o slowport.o ixp2000-gpio.o time.o +obj-m := +obj-n := +obj- := + +export-objs := ixp2000-gpio.o + +obj-$(CONFIG_ARCH_IXDP2400) += ixdp2400-irq.o ixdp2400-pci.o time.o + +obj-$(CONFIG_ARCH_IXDP2800) += ixdp2800-irq.o ixdp2800-pci.o pci-auto.o + +leds-$(CONFIG_ARCH_IXDP2800) += ixdp2800-leds.o +obj-$(CONFIG_LEDS) += $(leds-y) + +include $(TOPDIR)/Rules.make diff -Nru a/arch/arm/mach-ixp2000/arch.c b/arch/arm/mach-ixp2000/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/arch.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,63 @@ +/* + * linux/arch/arm/mach-ixp2000/arch.c + * + * Copyright (C) 2002 Intel Corp. + * + * Maintainer: Deepak Saxena + * + * 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 + + + +static void __init +fixup_ixp2000(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + + if(machine_is_ixdp2400() || machine_is_ixdp2800()) + { + mi->bank[0].start = PHYS_SDRAM_BASE; + mi->bank[0].size = PHYS_SDRAM_SIZE; + mi->bank[0].node = 0; + mi->nr_banks = 1; + } +} + +#ifdef CONFIG_ARCH_IXDP2400 +extern void ixdp2400_map_io(void); +extern void ixdp2400_init_irq(void); + +MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_SDRAM_BASE, 0xc0030000, IXP2000_UART_BASE)/*pram,pio,vio*/ + FIXUP(fixup_ixp2000) + MAPIO(ixdp2400_map_io) + INITIRQ(ixdp2400_init_irq) +MACHINE_END +#elif defined (CONFIG_ARCH_IXDP2800) +extern void ixdp2800_map_io(void); +extern void ixdp2800_init_irq(void); + +MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_SDRAM_BASE, 0xc0030000, IXP2000_UART_BASE)/*pram,pio,vio*/ + FIXUP(fixup_ixp2000) + MAPIO(ixdp2800_map_io) + INITIRQ(ixdp2800_init_irq) +MACHINE_END +#else +#error No board defined! +#endif diff -Nru a/arch/arm/mach-ixp2000/ixdp2400-irq.c b/arch/arm/mach-ixp2000/ixdp2400-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixdp2400-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,119 @@ +/* + * arch/arm/mach-ixp2000/ixdp2400-irq.c + * + * Interrupt code for IXDP2400 board + * + * Author: Naeem Afzal + * Copyright 2002 Intel Corp. + * + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include + +extern void do_IRQ(int, struct pt_regs *); +extern int setup_arm_irq(int, struct irqaction *); +extern void ixp2000_init_irq(void); + +/* + * Slowport configuration for accessing CPLD registers + */ +static struct slowport_cfg slowport_cpld_cfg = { + CCR: SLOWPORT_CCR_DIV_2, + WTC: 0x00000070, + RTC: 0x00000070, + PCR: SLOWPORT_MODE_FLASH, + ADC: SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8 +}; + +static void ext_irq_mask(unsigned int irq) +{ + unsigned long dummy; + + acquire_slowport(&slowport_cpld_cfg); + dummy = *IXDP2400_CPLD_INT_MASK; + ixp_reg_write(IXDP2400_CPLD_INT_MASK, dummy | (1 << (irq - NR_IXP2000_IRQS))); + release_slowport(); +} + +static void ext_irq_unmask(unsigned int irq) +{ + unsigned long dummy; + + acquire_slowport(&slowport_cpld_cfg); + dummy = *IXDP2400_CPLD_INT_MASK; + ixp_reg_write(IXDP2400_CPLD_INT_MASK, dummy & ~(1 << (irq - NR_IXP2000_IRQS))); + release_slowport(); +} + +static void ext_irq_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile u32 ex_interrupt = 0; + int i; + + acquire_slowport(&slowport_cpld_cfg); + ex_interrupt = *(IXDP2400_CPLD_INT) & 0xff; + release_slowport(); + + if(!ex_interrupt) { + printk(KERN_ERR "Spurious IXDP2400 CPLD interrupt!\n"); + return; + } + + for(i = 0; i < 8; i++) { + if(ex_interrupt & (1 << i)) + do_IRQ(IRQ_IXDP2400(0) + i, regs); + } +} + +static struct irqaction ext_irq = { + name: "IXDP2400 CPLD", + handler: ext_irq_demux, + flags: SA_INTERRUPT +}; + +/* + * We only do anything if we are the master NPU on the board. + * The slave NPU only has the ethernet chip going directly to + * the PCIB interrupt input. + */ +void __init ixdp2400_init_irq(void) +{ + int i = 0; + + /* initialize chip specific interrupts */ + ixp2000_init_irq(); + + if (npu_is_master()) { + + /* Disable all CPLD interrupts */ + acquire_slowport(&slowport_cpld_cfg); + *IXDP2400_CPLD_INT_MASK = 0xff; + release_slowport(); + + for(i = NR_IXP2000_IRQS; i < NR_IXDP2400_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = ext_irq_mask; + irq_desc[i].mask = ext_irq_mask; + irq_desc[i].unmask = ext_irq_unmask; + } + + /* Hook into PCI interrupts */ + setup_arm_irq(IRQ_IXP2000_PCIB, &ext_irq); + } +} diff -Nru a/arch/arm/mach-ixp2000/ixdp2400-pci.c b/arch/arm/mach-ixp2000/ixdp2400-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixdp2400-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,151 @@ +/* + * arch/arm/mach-ixp2000/ixmb2400-pci.c + * + * PCI routines for IXDP2400 board + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +//#define DEBUG 1 + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +extern void ixp2000_pci_init(void *); +extern struct pci_ops ixp2000_ops; + +/* + * This board does not do normal PCI IRQ routing, or any + * sort of swizzling, so we just need to check where on the + * bus the device is and figure out what CPLD pin it's + * being routed to. + */ +static int __init +ixdp2400_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + + if (npu_is_master()) { + + /* + * Root bus devices. Slave NPU is only one with interrupt. + * Everything else, we just return -1 which is invalid. + */ + if(!dev->bus->self) { + if(dev->devfn == 0x0028 ) + return IRQ_IXDP2400_INGRESS_NPU; + + return -1; + } + + /* + * We have a bridge behind the PMC slot + * NOTE: Only INTA from the PMC slot is routed. + */ + if(PCI_SLOT(dev->bus->self->devfn) == 0x7 && + PCI_SLOT(dev->bus->parent->self->devfn) == 0x4 && + !dev->bus->parent->self->bus->parent) + return IRQ_IXDP2400_PMC; + + /* + * Device behind the first bridge + */ + if(PCI_SLOT(dev->bus->self->devfn) == 0x4) { + switch(PCI_SLOT(dev->devfn)) { + case 0x4: // Master ethernet + return IRQ_IXDP2400_METHERNET; + + case 0x5: // Media interface + return IRQ_IXDP2400_MEDIA_PCI; + + case 0x6: // Switch fabric + return IRQ_IXDP2400_SF_PCI; + + case 0x7: // PMC slot + return IRQ_IXDP2400_PMC; + } + } + + return 0; + + } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */ +} + +extern void ixp2000_pci_init(void *); + +void __init ixdp2400_pci_init(void *sysdata) +{ + ixp2000_pci_init(sysdata); + + /* + * All I/O > 1MB, PCI MEM starting at 0. + */ + ixp_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000); + + pci_scan_bus(0, &ixp2000_ops, sysdata); + + /* + * Exclude devices depending on whether we are the master + * or slave NPU. Sigh... + * + * NOTE TO HW DESIGNERS: DO NOT PUT MULTIPLE PCI HOST CPUS + * ON THE SAME BUS SEGMENT. THAT'S WHAT NON-TRANSPARENT + * BRIDGES ARE FOR. + */ + if (npu_is_master()) { + pci_exclude_device(0x01, 0x18); /* Remove slave's NIC*/ + pci_exclude_device(0x0, 0x38); /* Remove self */ + } else { + int i; + + pci_exclude_device(0x01, 0x38); /* Remove PMC site */ + pci_exclude_device(0x01, 0x20); /* Remove master NIC*/ + pci_exclude_device(0x0, 0x20); /* Remove remove 21154*/ + pci_exclude_device(0x0, 0x30); /* Remove 21555*/ + pci_exclude_device(0x0, 0x28); /* Remove Self */ + + /* + * In case there's a bridge on the PMC, we remove everything + * on bus 2. + */ + for(i = 0; i < 0xff; i++) + pci_exclude_device(0x2, i); + } +} + +struct hw_pci ixdp2400_pci __initdata = { + init: ixdp2400_pci_init, + swizzle: no_swizzle, + map_irq: ixdp2400_map_irq, + mem_offset: 0xe0000000 +}; + + diff -Nru a/arch/arm/mach-ixp2000/ixdp2800-irq.c b/arch/arm/mach-ixp2000/ixdp2800-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixdp2800-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,85 @@ +/* + * arch/arm/mach-ixp2000/ixdp2800-irq.c + * + * Interrupt code for IXDP2800 board + * + * Author: Jeff Daly + * Copyright 2002 Intel Corp. + * + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include + +extern void do_IRQ(int, struct pt_regs *); +extern int setup_arm_irq(int, struct irqaction *); +extern void ixp2000_init_irq(void); + +static void ext_irq_mask(unsigned int irq) +{ + *IXDP2800_CPLD_INT_MASK &= ~(1 << (irq - NR_IXP2000_IRQS)); +} + +static void ext_irq_unmask(unsigned int irq) +{ + *IXDP2800_CPLD_INT_MASK |= (1 << (irq - NR_IXP2000_IRQS)); +} + +static void ext_irq_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile u32 ex_interrupt = 0; + int irqno = 0, i = 0; + + ex_interrupt = *(IXDP2800_CPLD_INT); + + for(i = 0; i < 6; i++) { + if(ex_interrupt & (1 << i)) + do_IRQ(IRQ_IXDP2800(i), regs); + } +} + +static struct irqaction ext_irq = { + name: "IXDP2800 CPLD", + handler: ext_irq_demux, + flags: SA_INTERRUPT +}; + +void __init ixdp2800_init_irq(void) +{ + int i = 0; + + *IXDP2800_CPLD_INT_MASK = 0; /* turn off interrupts */ + + /* initialize chip specific interrupts */ + ixp2000_init_irq(); + + /* + * Slave only has NIC routed to it, so we don't init everything + */ + if (npu_is_master()) { + for(i = NR_IXP2000_IRQS; i < NR_IXDP2800_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = ext_irq_mask; + irq_desc[i].mask = ext_irq_mask; + irq_desc[i].unmask = ext_irq_unmask; + } + + /* init PCI interrupts */ + setup_arm_irq(IRQ_IXP2000_PCIB, &ext_irq); + } +} diff -Nru a/arch/arm/mach-ixp2000/ixdp2800-leds.c b/arch/arm/mach-ixp2000/ixdp2800-leds.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixdp2800-leds.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,117 @@ +/* + * arch/arm/mach-ixp2000/ixdp2800-leds.c + * + * Code to manipulate led display on IXDP2800 + * + * Author: Jeff Daly + * Modified from arch/arm/mach-footbridge/ebsa285-leds.c + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static char hw_led_state0; +static char hw_led_state1 = 0x1; +static char hw_led_state2 = ' '; +static char hw_led_state3 = ' '; + +static char spinner[] = {'|','/','-','\\'}; +static int spincnt = 0; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +static void ixdp2800_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + { + hw_led_state0 = spinner[spincnt]; + spincnt++; + spincnt %= 4; + } + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state1 = ' '; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state1 = '*'; + break; +#endif + + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state0 = 'H'; + hw_led_state1 = 'A'; + hw_led_state2 = 'L'; + hw_led_state3 = 'T'; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + { + *IXDP2800_LED0_REG = hw_led_state0; + *IXDP2800_LED1_REG = hw_led_state1; + *IXDP2800_LED2_REG = hw_led_state2; + *IXDP2800_LED3_REG = hw_led_state3; + } + + spin_unlock_irqrestore(&leds_lock, flags); +} + +static int __init leds_init(void) +{ + /* clear leds */ + *IXDP2800_LED0_REG = ' '; + *IXDP2800_LED1_REG = ' '; + *IXDP2800_LED2_REG = ' '; + *IXDP2800_LED3_REG = ' '; + + leds_event = ixdp2800_leds_event; + + leds_event(led_start); + + return 0; +} + +__initcall(leds_init); diff -Nru a/arch/arm/mach-ixp2000/ixdp2800-pci.c b/arch/arm/mach-ixp2000/ixdp2800-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixdp2800-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,172 @@ +/* + * arch/arm/mach-ixp2000/ixmb2800-pci.c + * + * PCI routines for IXDP2800 board + * + * Author: Jeff Daly + * + * Copyright 2002-2003 Intel Corp. + * + * 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. + * + * TODO: This is almost identical to IXDP2400..may consider merging the two. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +// #define DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +extern void ixp2000_pci_init(void *); +extern struct pci_ops ixp2000_ops; +static struct pci_controller *hose; + +/* + * This board does not do normal PCI IRQ routing, or any + * sort of swizzling, so we just need to check where on the + * bus the device is and figure out what CPLD pin it's + * being routed to. + */ +static int __init +ixdp2800_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + + if (npu_is_master()) { + + /* + * Root bus devices. Slave NPU is only one with interrupt. + * Everything else, we just return -1 which is invalid. + */ + if(!dev->bus->self) { + if(dev->devfn == 0x0028 ) + return IRQ_IXDP2800_INGRESS_NPU; + + return -1; + } + + /* + * We have a bridge behind the PMC slot + * NOTE: Only INTA from the PMC slot is routed. + */ + if(PCI_SLOT(dev->bus->self->devfn) == 0x7 && + PCI_SLOT(dev->bus->parent->self->devfn) == 0x4 && + !dev->bus->parent->self->bus->parent) + return IRQ_IXDP2800_PMC_PCI; + + /* + * Device behind the first bridge + */ + if(PCI_SLOT(dev->bus->self->devfn) == 0x4) { + switch(PCI_SLOT(dev->devfn)) { + case 0x2: // Master PMC + return IRQ_IXDP2800_PMC_PCI; + + case 0x3: // Ethernet + return IRQ_IXDP2800_EGRESS_NIC; + + case 0x5: // Switch fabric + return IRQ_IXDP2800_FABRIC; + } + } + + return 0; + + } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */ +} + +extern void ixp2000_pci_init(void *); + +void __init ixdp2800_pci_init(void *sysdata) +{ + ixp2000_pci_init(sysdata); + + *IXP2000_PCI_CMDSTAT = 0; + *IXP2000_PCI_ADDR_EXT = 0x0000e000; + + *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x20000000 - 1) & ~0xfffff; + *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff; + + DBG("allocating hose\n"); + hose = pcibios_alloc_controller(); + if (!hose) + panic("Could not allocate PCI hose"); + + hose->first_busno = 0; + hose->last_busno = 0; + hose->io_space.start = 0x00000000; + hose->io_space.end = 0x0000ffff; + hose->mem_space.start = 0xe0000000; + hose->mem_space.end = 0xffffffff; + + /* + * Scan bus and exclude devices depending on whether we are the + * master or slave NPU. Sigh... + * + * NOTE TO HW DESIGNERS: DO NOT PUT MULTIPLE PCI HOST CPUS + * ON THE SAME BUS SEGMENT. THAT'S WHAT NON-TRANSPARENT + * BRIDGES ARE FOR. + */ + if (npu_is_master()) { + *IXP2000_PCI_SDRAM_BAR = PHYS_OFFSET; + + *IXP2000_PCI_CMDSTAT = (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + hose->last_busno = pciauto_bus_scan(hose, 0); + + pci_scan_bus(0,&ixp2000_ops, sysdata); + + pci_exclude_device(0x01, 0x20); /* Remove slave's NIC*/ + pci_exclude_device(0x0, 0x38); /* Remove self XXX FIXME*/ + } else { + int i; + + /* Wait for the master NPU to enable us */ + while(!(*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER)); + pci_scan_bus(0, &ixp2000_ops, sysdata); + + pci_exclude_device(0x01, 0x38); /* Remove PMC site */ + pci_exclude_device(0x01, 0x18); /* Remove master NIC*/ + pci_exclude_device(0x0, 0x20); /* Remove remove 21154*/ + pci_exclude_device(0x0, 0x30); /* Remove 21555*/ + pci_exclude_device(0x0, 0x28); /* Remove Self XXX FIXME */ + + /* + * In case there's a bridge on the PMC, we remove everything + * on bus 2. + */ + for(i = 0; i < 0xff; i++) + pci_exclude_device(0x2, i); + } +} + +struct hw_pci ixdp2800_pci __initdata = { + init: ixdp2800_pci_init, + swizzle: no_swizzle, + map_irq: ixdp2800_map_irq, +}; + + diff -Nru a/arch/arm/mach-ixp2000/ixp2000-gpio.c b/arch/arm/mach-ixp2000/ixp2000-gpio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixp2000-gpio.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,115 @@ +/* + * arch/arm/mach-ixp2000/ixp2000-gpio.c + * + * GPIO code for IXP2000 board + * + * Author: Jeff Daly + * Using mach-ixp425/ixp425-gpio.c as a model + * + * Copyright 2002 Intel Corp. + * + * 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 + +static int GPIO_IRQ_rising_edge; +static int GPIO_IRQ_falling_edge; +static int GPIO_IRQ_level_low; +static int GPIO_IRQ_level_high; + +void set_GPIO_IRQ_edge(int gpio_nr, int edge) +{ + long flags; + + local_irq_save(flags); + ixp_reg_write(IXP2000_GPIO_PDCR, (1 << gpio_nr)); + + if (edge & GPIO_FALLING_EDGE) + GPIO_IRQ_falling_edge |= (1 << gpio_nr); + else + GPIO_IRQ_falling_edge &= ~(1 << gpio_nr); + if (edge & GPIO_RISING_EDGE) + GPIO_IRQ_rising_edge |= (1 << gpio_nr); + else + GPIO_IRQ_rising_edge &= ~(1 << gpio_nr); + GPIO_IRQ_level_high &= ~(GPIO_IRQ_falling_edge | GPIO_IRQ_rising_edge); + GPIO_IRQ_level_low &= ~(GPIO_IRQ_falling_edge | GPIO_IRQ_rising_edge); + + ixp_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); + ixp_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); + ixp_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); + ixp_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); + + irq_desc[gpio_nr+IRQ_IXP2000_GPIO0].valid = 1; + + local_irq_restore(flags); +} + +void set_GPIO_IRQ_level(int gpio_nr, int level) +{ + long flags; + + local_irq_save(flags); + ixp_reg_write(IXP2000_GPIO_PDCR, (1 << gpio_nr)); + + if (level & GPIO_LEVEL_LOW) { + GPIO_IRQ_level_low |= (1 << gpio_nr); + GPIO_IRQ_level_high &= ~(1 << gpio_nr); + } + else { + GPIO_IRQ_level_low &= ~(1 << gpio_nr); + GPIO_IRQ_level_high |= (1 << gpio_nr); + } + GPIO_IRQ_rising_edge &= ~(GPIO_IRQ_level_low | GPIO_IRQ_level_high); + GPIO_IRQ_falling_edge &= ~(GPIO_IRQ_level_low | GPIO_IRQ_level_high); + + ixp_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); + ixp_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); + ixp_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); + ixp_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); + + irq_desc[gpio_nr+IRQ_IXP2000_GPIO0].valid = 1; + + local_irq_restore(flags); +} + + +void gpio_line_config(int line, int style) +{ + int flags; + + local_irq_save(flags); + + if(style == GPIO_OUT) { + /* if it's an output, it ain't an interrupt anymore */ + ixp_reg_write(IXP2000_GPIO_PDSR, (1 << line)); + GPIO_IRQ_falling_edge &= ~(1 << line); + GPIO_IRQ_rising_edge &= ~(1 << line); + GPIO_IRQ_level_low &= ~(1 << line); + GPIO_IRQ_level_high &= ~(1 << line); + ixp_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); + ixp_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); + ixp_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); + ixp_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); + irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0; + } else if(style == GPIO_IN) { + ixp_reg_write(IXP2000_GPIO_PDCR, (1 << line)); + } + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(set_GPIO_IRQ_edge); +EXPORT_SYMBOL(set_GPIO_IRQ_level); +EXPORT_SYMBOL(gpio_line_config); + + diff -Nru a/arch/arm/mach-ixp2000/ixp2000-irq.c b/arch/arm/mach-ixp2000/ixp2000-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixp2000-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,197 @@ +/* + * arch/arm/mach-ixp2000/ixp2000-irq.c + * + * Interrupt code for IXDP2400 board + * + * Original Author: Naeem Afzal + * Maintainer: Deepak Saxena + * + * Copyright (c) 2002 Intel Corp. + * Copyright (c) 2003 MontaVista Software, Inc. + * + * 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 +#include +#include + +#include + +extern void do_IRQ(int, struct pt_regs *); +extern int setup_arm_irq(int, struct irqaction *); + +static void ixp_irq_mask(unsigned int irq) +{ + ixp_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); +} + +static void ixp_irq_unmask(unsigned int irq) +{ + ixp_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); +} + +/* + * Install handler for GPIO interrupts + */ +static void ixp_GPIO_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + + while ((irq = (*IXP2000_GPIO_INST & 0xff))) { + for (i = 0; i<=7;i++) { + if (irq & (1< + * + * Copyright 2002 Intel Corp. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#undef BASE_BAUD +#undef RS_TABLE_SIZE + +/* + * IXP2400 uses 50MHz clock for uart + */ + +#define BASE_BAUD ( 50000000 / 16 ) + +#define RS_TABLE_SIZE 1 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_IXP2000_UART, \ + flags: STD_COM_FLAGS, \ + iomem_base: IXP2000_UART_BASE, \ + io_type: SERIAL_IO_MEM \ + } /* ttyS0 */ + + +static struct serial_state ports[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS +}; + +static short port = 0; +static volatile unsigned char *serial_base = NULL; + +void kgdb_serial_init(void) +{ + + // TODO: Make port number a config or cmdline option + port = 1; + + serial_base = ports[port].iomem_base; + + serial_base[UART_LCR] = 0x80; /* enable access to divisor reg */ + serial_base[UART_DLL] = 0x36; /*divisor latch LSB baud rate 57600 */ + serial_base[UART_DLM] = 0; /* divisor latch MSB */ + serial_base[UART_LCR] = 0x03; /* 8 data, 1 stop bit, no parity */ + serial_base[UART_FCR] = 0x07; /* turn FIFOs on */ + serial_base[UART_IER] = 40; /* enable UART and disable interrupts */ + + return; +} + +void kgdb_serial_putchar(unsigned char ch) +{ + unsigned char status; + + do + { + status = serial_base[UART_LSR]; + } while ((status & (UART_LSR_TEMT|UART_LSR_THRE)) != + (UART_LSR_TEMT|UART_LSR_THRE)); + + *serial_base = ch; +} + +unsigned char kgdb_serial_getchar(void) +{ + unsigned char ch; + + while(!(serial_base[UART_LSR] & 0x1)); + + ch = *serial_base; + + return ch; +} + diff -Nru a/arch/arm/mach-ixp2000/ixp2000-pci.c b/arch/arm/mach-ixp2000/ixp2000-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/ixp2000-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,307 @@ +/* + * arch/arm/mach-ixp2000/ixp2000-pci.c + * + * PCI routines for IXDP2400/IXDP2800 boards + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +//#include +#include + +static int pci_master_aborts = 0; + +// #define DEBUG 1 + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + + +int clear_master_aborts(void); + +static u32* +ixp2000_pci_config_setup(struct pci_dev *dev, int where) +{ + u32 *paddress; + + if ( PCI_SLOT(dev->devfn) > 7 ) + return 0; + + /* Must be dword aligned */ + + where &= ~3; + + /* + * For top bus, generate type 0, else type 1 + */ + if(!dev->bus->number) { + /* only bits[23:16] are used for IDSEL */ + paddress = (u32 *)(PCI_CFG0_VIRT_BASE + | (1 << (PCI_SLOT(dev->devfn)+16)) + | (PCI_FUNC(dev->devfn) << 8) | where); + } else { + paddress = (u32 *)(PCI_CFG1_VIRT_BASE + | (dev->bus->number << 16) + | (PCI_SLOT(dev->devfn) << 11) + | (PCI_FUNC(dev->devfn) << 8) | where | 0); + } + + return paddress; +} + +static int +ixp2000_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + u32 *address; + + DBG("In config_read_byte %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = ixp2000_pci_config_setup(dev, where); + + if ( !address ) { + *value = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + + } + + *value = (u8)(((*address) >> ((where % 0x04) * 8)) & 0xff); + if (pci_master_aborts) { + pci_master_aborts = 0; + *value = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int +ixp2000_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + u32 *address; + + DBG("config_read_word %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = ixp2000_pci_config_setup(dev, where); + + if ( !address ) { + *value = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + + } + *value = (u16)(((*address) >> ((where % 0x04) *8)) & 0xffff); + + if (pci_master_aborts) { + pci_master_aborts = 0; + *value = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int +ixp2000_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + u32 *address; + + DBG("config_read_dword %d from dev %d:%d:%d\n", where, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + + address = ixp2000_pci_config_setup(dev, where); + + if ( !address ) { + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + + } + *value = *address; + + if (pci_master_aborts) { + pci_master_aborts = 0; + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + + return PCIBIOS_SUCCESSFUL; +} + +/* + * We don't do error checking on the address for writes. + * It's assumed that the user checked for the device existing first + * by doing a read first. + */ +static int +ixp2000_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + u32 *address; + u32 mask; + u32 temp; + + address = ixp2000_pci_config_setup(dev, where); + + mask = ~(0x000000ff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) *8)); + *address = (*address & mask) | temp; + + clear_master_aborts(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +ixp2000_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + u32 *address; + u32 mask; + u32 temp; + + address = ixp2000_pci_config_setup(dev, where); + + mask = ~(0x0000ffff << ((where % 0x4) * 8)); + temp = (u32)(((u32)value) << ((where % 0x4) * 8)); + *address = (*address & mask) | temp; + + clear_master_aborts(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +ixp2000_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + u32 *address; + + address = ixp2000_pci_config_setup(dev, where); + + *address = value; + clear_master_aborts(); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops ixp2000_ops = { + ixp2000_read_config_byte, + ixp2000_read_config_word, + ixp2000_read_config_dword, + ixp2000_write_config_byte, + ixp2000_write_config_word, + ixp2000_write_config_dword, +}; + +int +abort_handler(unsigned long addr, unsigned long fsr, struct pt_regs *regs) +{ + + volatile u32 temp; + + pci_master_aborts = 1; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1<<8) | (1<<5))) { /* master abort and cmd tgt err */ + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1<<29) ) { + while (temp & (1<<29) ) {/* Rx_MA recv abort with master*/ + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + sti(); + + return 0; +} + + +int clear_master_aborts(void) +{ + volatile u32 temp; + + cli(); + temp = *(IXP2000_PCI_CONTROL); + if (temp & ((1<<8) | (1<<5))) { /* master abort and cmd tgt err */ + *(IXP2000_PCI_CONTROL) = temp; + } + + temp = *(IXP2000_PCI_CMDSTAT); + if (temp & (1<<29) ) { + while (temp & (1<<29) ) {/* Rx_MA recv abort with master*/ + *(IXP2000_PCI_CMDSTAT) = temp; + temp = *(IXP2000_PCI_CMDSTAT); + } + } + sti(); + + return 0; +} + +void __init ixp2000_pci_init(void *sysdata) +{ + /* hook in our fault handler for PCI errors */ + hook_fault_code(4, abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(6, abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(8, abort_handler, SIGBUS, "external abort on non-line fetch\n"); + hook_fault_code(10, abort_handler, SIGBUS, "external abort on non-line fetch\n"); + + DBG("ixp200_pci_init Done\n"); +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return ixp2000_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + diff -Nru a/arch/arm/mach-ixp2000/mm.c b/arch/arm/mach-ixp2000/mm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/mm.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,137 @@ +/* + * linux/arch/arm/mach-ixp2000/mm.c + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2003 MontaVista Software, Inc. + * + * Maintainer: Deepak Saxena + * + * 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 + + +/* + * Chip specific mappings shared by all IXP2000 systems + */ +static struct map_desc ixp2000_io_desc[] __initdata = { + { + GLOBAL_REG_VIRT_BASE, + GLOBAL_REG_PHYS_BASE, + GLOBAL_REG_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + GPIO_VIRT_BASE, + GPIO_PHYS_BASE, + GPIO_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + TIMER_VIRT_BASE, + TIMER_PHYS_BASE, + TIMER_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + UART_VIRT_BASE, + UART_PHYS_BASE, + UART_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + SLOWPORT_CSR_VIRT_BASE, + SLOWPORT_CSR_PHYS_BASE, + SLOWPORT_CSR_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + INTCTL_VIRT_BASE, + INTCTL_PHYS_BASE, + INTCTL_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + PCI_CREG_VIRT_BASE, + PCI_CREG_PHYS_BASE, + PCI_CREG_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + PCI_CSR_VIRT_BASE, + PCI_CSR_PHYS_BASE, + PCI_CSR_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + PCI_CFG0_VIRT_BASE, + PCI_CFG0_PHYS_BASE, + PCI_CFG0_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + PCI_CFG1_VIRT_BASE, + PCI_CFG1_PHYS_BASE, + PCI_CFG1_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + { + PCI_IO_VIRT_BASE, + PCI_IO_PHYS_BASE, + PCI_IO_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + LAST_DESC +}; + + +/* + * Board specific mappings + */ +#ifdef CONFIG_ARCH_IXDP2400 +static struct map_desc ixdp2400_io_desc[] __initdata = { + { + IXDP2400_VIRT_CPLD_BASE, + IXDP2400_PHY_CPLD_BASE, + IXDP2400_CPLD_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + LAST_DESC +}; + +void __init ixdp2400_map_io(void) +{ + iotable_init(ixp2000_io_desc); + + iotable_init(ixdp2400_io_desc); +} +#endif + +#ifdef CONFIG_ARCH_IXDP2800 +static struct map_desc ixdp2800_io_desc[] __initdata = { + { + IXDP2800_VIRT_CPLD_BASE, + IXDP2800_PHY_CPLD_BASE, + IXDP2800_CPLD_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + }, + LAST_DESC +}; +void __init ixdp2800_map_io(void) +{ + iotable_init(ixp2000_io_desc); + + iotable_init(ixdp2800_io_desc); +} +#endif diff -Nru a/arch/arm/mach-ixp2000/pci-auto.c b/arch/arm/mach-ixp2000/pci-auto.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/pci-auto.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,379 @@ +/* + * arch/arm/mach-ixp2000/pci-auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 + +// #define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int bar_limit) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask, bar_nr = 0; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + DBG("PCI Autoconfig: Bridge %d. IO_FILTER = %#010x..%#010x\n", + current_bus, + (pciauto_upper_iospc & 0x0000f000) >> 8, + pciauto_upper_iospc >> 16); + + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) + { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + /* If config space read fails from this device, move on */ + if (early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } + else + { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_5); + } + } + } + return sub_bus; +} diff -Nru a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,249 @@ +/* + * arch/arm/mach-ixdp2400/pci.c + * + * Generic PCI support functionality that should eventually move to + * arch/arm/kernel/bios32.c. Derived from support in ppc and alpha. + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 DEBUG 1 + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +/* + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * some boards that don't follow the PCI spec's suggestion so we + * break this piece out separately. + */ +static inline u8 +bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +u8 __init +common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(dev->bus->number); + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +/* + * Null PCI config access functions, for the case when we can't + * find a hose. + */ +#define NULL_PCI_OP(rw, size, type) \ +static int \ +null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + return PCIBIOS_DEVICE_NOT_FOUND; \ +} + + NULL_PCI_OP(read, byte, u8 *) + NULL_PCI_OP(read, word, u16 *) + NULL_PCI_OP(read, dword, u32 *) + NULL_PCI_OP(write, byte, u8) + NULL_PCI_OP(write, word, u16) +NULL_PCI_OP(write, dword, u32) + +static struct pci_ops null_pci_ops = +{ + null_read_config_byte, + null_read_config_word, + null_read_config_dword, + null_write_config_byte, + null_write_config_word, + null_write_config_dword +}; + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +struct pci_dev * +fake_pci_dev(struct pci_controller *hose, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + if (hose == 0) { + hose = pci_bus_to_hose(busnr); + if (hose == 0) + printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); + } + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose? hose->ops: &null_pci_ops; + return &dev; +} + +static int next_controller_index; + +struct pci_controller * __init +pcibios_alloc_controller(void) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *)kmalloc(sizeof(*hose), GFP_KERNEL); + memset(hose, 0, sizeof(struct pci_controller)); + + *hose_tail = hose; + hose_tail = &hose->next; + + hose->index = next_controller_index++; + + return hose; +} + +struct pci_controller * +pci_bus_to_hose(int bus) +{ + struct pci_controller *hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +void __init +pci_exclude_device(unsigned char bus, unsigned char devfn) +{ + struct pci_dev *dev, *pdev = NULL; + + /* Walk the pci device list */ + pci_for_each_dev(dev) + { + if ((dev->bus->number == bus) && (dev->devfn == devfn)) + { + /* + * Remove the device from the global and + * bus lists. + */ + list_del(&(dev->global_list)); + list_del(&(dev->bus_list)); + + /* Free the pci_dev structure */ + kfree(dev); + + break; + } + pdev = dev; + } +} + +static inline void __init alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + pr = pci_find_parent_resource(dev, r); + if(!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Can not allocate resource region %d" \ + " of device %s\n", idx, dev->slot_name); + r->end -= r->start; + r->start = 0; + } +} + +void __init +pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + int i; + struct resource *res, *pr; + + if(!bus_list) return; + + /* Depth-First Search on bus tree */ + for (ln = bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + pci_read_bridge_bases(bus); + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Can not allocate resource region " + "%d of PCI bridge %d\n", i, bus->number); + DBG("PCI: resource is %lx..%lx (%lx)\n", + res->start, res->end, res->flags); + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +void __init pcibios_allocate_resources(void) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r; + + pci_for_each_dev(dev) + { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) + { + r = &dev->resource[idx]; + + if(r->parent) + continue; + if(!r->start) + continue; + + alloc_resource(dev, idx); + } + } +} + diff -Nru a/arch/arm/mach-ixp2000/slowport.c b/arch/arm/mach-ixp2000/slowport.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/slowport.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,57 @@ +/* + * arch/arm/mach-ixp2000/slowport.c + * + * Slowport access functions. We could make these inlines, but then + * we would have a global spinlock floating around and that's ugly. + * + * Copyright (c) 2002 MontaVista Software, Inc. + */ + + +#include +#include +#include +#include +#include +#include +#include + +static spinlock_t slowport_lock = SPIN_LOCK_UNLOCKED; +static struct slowport_cfg old_cfg; +static unsigned long flags; + +/* + * The only reason we need to save/restore the state is b/c + * the CCR register affects the state of both device 1 and + * device 2. This means that we could really screw up the + * flash access if the CCR is not restored. + */ +void acquire_slowport(struct slowport_cfg *new_cfg) +{ + spin_lock_irqsave(&slowport_lock, flags); + + old_cfg.CCR = *IXP2000_SLOWPORT_CCR; + old_cfg.WTC = *IXP2000_SLOWPORT_WTC2; + old_cfg.RTC = *IXP2000_SLOWPORT_RTC2; + old_cfg.PCR = *IXP2000_SLOWPORT_PCR; + old_cfg.ADC = *IXP2000_SLOWPORT_ADC; + + ixp_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR); + ixp_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); + ixp_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); + ixp_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); + ixp_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); +} + +void release_slowport(void) +{ + ixp_reg_write(IXP2000_SLOWPORT_CCR, old_cfg.CCR); + ixp_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg.WTC); + ixp_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg.RTC); + ixp_reg_write(IXP2000_SLOWPORT_PCR, old_cfg.PCR); + ixp_reg_write(IXP2000_SLOWPORT_ADC, old_cfg.ADC); + + spin_unlock_irqrestore(&slowport_lock, flags); +} + + diff -Nru a/arch/arm/mach-ixp2000/time.c b/arch/arm/mach-ixp2000/time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp2000/time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,108 @@ +/* + * arch/arm/mach-ixp2000/time.c + * + * Original Authors: Naeem M Afzal + * Jeff Daly + * + * Copyright (c) 2002-2003 Intel Corp. + * Copyright (c) 2003 MontaVista Software, Inc. + * + * 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 +#include + +#include +#include +#include + +#include +#include + +#include + + +#ifdef CONFIG_LEDS_TIMER +extern void do_leds(void); +#endif + +static unsigned ticks_per_jiffy; +static unsigned ticks_per_usec; + +static inline unsigned long ixdp2400_ext_oscillator(void) +{ + int numerator, denominator; + int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8}; + + numerator = (*(IXDP2400_CPLD_SYS_CLK_M) & 0xFF) *2; + denominator = denom_array[(*(IXDP2400_CPLD_SYS_CLK_N) & 0x7)]; + + return ((3125000 * numerator) / (denominator)); +} + +static unsigned long ixp2000_gettimeoffset (void) +{ + unsigned long elapsed; + + /* Get ticks since last perfect jiffy */ + elapsed = ticks_per_jiffy - *IXP2000_T1_CSR; + + return elapsed / ticks_per_usec; +} +static void ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + + /* clear timer 1 */ + ixp_reg_write(IXP2000_T1_CLR, 1); + +#ifdef CONFIG_LEDS_TIMER + do_leds(); +#endif + do_timer(regs); +} + +static struct irqaction ixp2000_timer_irq = { + + handler:ixp2000_timer_interrupt, + name:"timer tick", +}; + +extern unsigned long (*gettimeoffset)(void); +extern int setup_arm_irq(int, struct irqaction *); + +void setup_timer (void) +{ + gettimeoffset = ixp2000_gettimeoffset; + + ixp_reg_write(IXP2000_T1_CLR, 0); + + if(machine_is_ixdp2800()) { // Default 50MhZ APB + ticks_per_jiffy = LATCH; + ticks_per_usec = CLOCK_TICK_RATE / 1000000; + } else if (machine_is_ixdp2400()) { + ticks_per_jiffy = ((ixdp2400_ext_oscillator()/2) + HZ/2) / HZ; + ticks_per_usec = (ixdp2400_ext_oscillator()/2) / 1000000; + } + + ixp_reg_write(IXP2000_T1_CLD, ticks_per_jiffy); + ixp_reg_write(IXP2000_T1_CTL, (1 << 7)); + + /* register for interrupt */ + setup_arm_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq); +} + diff -Nru a/arch/arm/mach-ixp425/Makefile b/arch/arm/mach-ixp425/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/Makefile Thu Dec 4 16:24:26 2003 @@ -0,0 +1,29 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := ixp425.o + +# Object file lists. + +obj-y := arch.o mm.o ixp425-irq.o ixp425-pci.o pci.o \ + pci-auto.o gpio.o pci-io.o \ + ixp425-time.o pcibuf.o +obj-m := +obj-n := +obj- := + +export-objs := pcibuf.o pci-io.o gpio.o + +obj-$(CONFIG_ARCH_IXDP425) += ixdp425-pci.o +obj-$(CONFIG_ARCH_PRPMC1100) += prpmc1100-pci.o +obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o + +obj-$(CONFIG_KGDB) += kgdb.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/arm/mach-ixp425/arch.c b/arch/arm/mach-ixp425/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/arch.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,68 @@ +/* + * arch/arm/mach-ixp425/arch.c + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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 + +extern void ixp425_map_io(void); +extern void ixp425_init_irq(void); + +#ifdef CONFIG_ARCH_IXDP425 +MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_OFFSET, IXP425_PERIPHERAL_BASE_PHYS, + IXP425_PERIPHERAL_BASE_VIRT) + MAPIO(ixp425_map_io) + INITIRQ(ixp425_init_irq) + BOOT_PARAMS(0x0100) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_IXCDP1100 +MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_OFFSET, IXP425_PERIPHERAL_BASE_PHYS, + IXP425_PERIPHERAL_BASE_VIRT) + MAPIO(ixp425_map_io) + INITIRQ(ixp425_init_irq) + BOOT_PARAMS(0x0100) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_PRPMC1100 +MACHINE_START(PRPMC1100, "Motorola PrPMC 1100") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_OFFSET, IXP425_PERIPHERAL_BASE_PHYS, + IXP425_PERIPHERAL_BASE_VIRT) + MAPIO(ixp425_map_io) + INITIRQ(ixp425_init_irq) + BOOT_PARAMS(0x0100) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_ADI_COYOTE +MACHINE_START(ADI_COYOTE, "ADI Coyote Residential Gateway") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_OFFSET, IXP425_PERIPHERAL_BASE_PHYS, + IXP425_PERIPHERAL_BASE_VIRT) + MAPIO(ixp425_map_io) + INITIRQ(ixp425_init_irq) + BOOT_PARAMS(0x0100) +MACHINE_END +#endif + + diff -Nru a/arch/arm/mach-ixp425/coyote-pci.c b/arch/arm/mach-ixp425/coyote-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/coyote-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,60 @@ +/* + * arch/arm/mach-ixp425/coyote-pci.c + * + * ADI Coyote PCI initialization + * + * Copyright (C) 2002 Intel 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 + + +/* PCI controller pin mappings */ +#define INTA_PIN IXP425_GPIO_PIN_11 +#define INTB_PIN IXP425_GPIO_PIN_6 + +#define IXP425_PCI_RESET_GPIO IXP425_GPIO_PIN_12 +#define IXP425_PCI_CLK_PIN IXP425_GPIO_CLK_0 +#define IXP425_PCI_CLK_ENABLE IXP425_GPIO_CLK0_ENABLE +#define IXP425_PCI_CLK_TC_LSH IXP425_GPIO_CLK0TC_LSH +#define IXP425_PCI_CLK_DC_LSH IXP425_GPIO_CLK0DC_LSH + +void __init coyote_pci_init(void *sysdata) +{ + gpio_line_config(INTA_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTB_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(INTA_PIN); + gpio_line_isr_clear(INTB_PIN); + + ixp425_pci_init(sysdata); +} + +static int __init coyote_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if(slot == 15) + return IRQ_COYOTE_PCI_INTA; + else if(slot == 14) + return IRQ_COYOTE_PCI_INTB; + else return -1; +} + +struct hw_pci coyote_pci __initdata = { + init: coyote_pci_init, + swizzle: common_swizzle, + map_irq: coyote_map_irq, +}; + diff -Nru a/arch/arm/mach-ixp425/gpio.c b/arch/arm/mach-ixp425/gpio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/gpio.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,108 @@ +/* + * arch/arm/mach-ixp425/ixp425-gpio.c + * + * GPIO configuration APIs for IXP425 based systems + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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 + +#define IXP425_GPIO_INTSTYLE_MASK 0x7C /* Bits [6:2] define interrupt style */ + +/* Interrupt styles, these refer to actual values used in reg */ +#define IXP425_GPIO_STYLE_ACTIVE_HIGH 0x0 +#define IXP425_GPIO_STYLE_ACTIVE_LOW 0x1 +#define IXP425_GPIO_STYLE_RISING_EDGE 0x2 +#define IXP425_GPIO_STYLE_FALLING_EDGE 0x3 +#define IXP425_GPIO_STYLE_TRANSITIONAL 0x4 + +/* Mask used to clear interrupt styles */ +#define IXP425_GPIO_STYLE_CLEAR 0x7 +#define IXP425_GPIO_STYLE_SIZE 3 + +void gpio_line_isr_clear(u8 line) +{ + *IXP425_GPIO_GPISR = BIT(line); +} + +void gpio_line_get(u8 line, int *value) +{ + *value = (*IXP425_GPIO_GPINR >> line) & 0x1; +} + +void gpio_line_set(u8 line, int value) +{ + if (value == IXP425_GPIO_HIGH) + *IXP425_GPIO_GPOUTR |= BIT(line); + else if (value == IXP425_GPIO_LOW) + *IXP425_GPIO_GPOUTR &= ~BIT(line); +} + +void gpio_line_config(u8 line, u32 style) +{ + u32 enable; + volatile u32 *int_reg; + u32 int_style; + + enable = *IXP425_GPIO_GPOER; + + if (style & IXP425_GPIO_OUT) { + enable &= ~BIT(line); + } else if (style & IXP425_GPIO_IN) { + enable |= BIT(line); + + switch (style & IXP425_GPIO_INTSTYLE_MASK) + { + case (IXP425_GPIO_ACTIVE_HIGH): + int_style = IXP425_GPIO_STYLE_ACTIVE_HIGH; + break; + case (IXP425_GPIO_ACTIVE_LOW): + int_style = IXP425_GPIO_STYLE_ACTIVE_LOW; + break; + case (IXP425_GPIO_RISING_EDGE): + int_style = IXP425_GPIO_STYLE_RISING_EDGE; + break; + case (IXP425_GPIO_FALLING_EDGE): + int_style = IXP425_GPIO_STYLE_FALLING_EDGE; + break; + case (IXP425_GPIO_TRANSITIONAL): + int_style = IXP425_GPIO_STYLE_TRANSITIONAL; + break; + default: + int_style = IXP425_GPIO_STYLE_ACTIVE_HIGH; + break; + } + + if (line >= 8) { /* pins 8-15 */ + line -= 8; + int_reg = IXP425_GPIO_GPIT2R; + } + else { /* pins 0-7 */ + int_reg = IXP425_GPIO_GPIT1R; + } + + /* Clear the style for the appropriate pin */ + *int_reg &= ~(IXP425_GPIO_STYLE_CLEAR << + (line * IXP425_GPIO_STYLE_SIZE)); + + /* Set the new style */ + *int_reg |= (int_style << (line * IXP425_GPIO_STYLE_SIZE)); + } + + *IXP425_GPIO_GPOER = enable; +} + +EXPORT_SYMBOL(gpio_line_config); +EXPORT_SYMBOL(gpio_line_set); +EXPORT_SYMBOL(gpio_line_get); +EXPORT_SYMBOL(gpio_line_isr_clear); + diff -Nru a/arch/arm/mach-ixp425/ixdp425-pci.c b/arch/arm/mach-ixp425/ixdp425-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/ixdp425-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,92 @@ +/* + * arch/arm/mach-ixdp425/ixdp425-pci.c + * + * IXDP425 PCI initialization + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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 + + +/* PCI controller pin mappings */ +#define INTA_PIN IXP425_GPIO_PIN_11 +#define INTB_PIN IXP425_GPIO_PIN_10 +#define INTC_PIN IXP425_GPIO_PIN_9 +#define INTD_PIN IXP425_GPIO_PIN_8 + +#define IXP425_PCI_RESET_GPIO IXP425_GPIO_PIN_13 +#define IXP425_PCI_CLK_PIN IXP425_GPIO_CLK_0 +#define IXP425_PCI_CLK_ENABLE IXP425_GPIO_CLK0_ENABLE +#define IXP425_PCI_CLK_TC_LSH IXP425_GPIO_CLK0TC_LSH +#define IXP425_PCI_CLK_DC_LSH IXP425_GPIO_CLK0DC_LSH + +void __init ixdp425_pci_init(void *sysdata) +{ + gpio_line_config(INTA_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTB_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTC_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTD_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(INTA_PIN); + gpio_line_isr_clear(INTB_PIN); + gpio_line_isr_clear(INTC_PIN); + gpio_line_isr_clear(INTD_PIN); + + ixp425_pci_init(sysdata); +} + + +/* + * Interrupt mapping + */ +#define INTA IRQ_IXDP425_PCI_INTA +#define INTB IRQ_IXDP425_PCI_INTB +#define INTC IRQ_IXDP425_PCI_INTC +#define INTD IRQ_IXDP425_PCI_INTD + +#define IXP425_PCI_MAX_DEV 4 +#define IXP425_PCI_IRQ_LINES 4 + +static int __init ixdp425_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[IXP425_PCI_MAX_DEV][IXP425_PCI_IRQ_LINES] = + { + {INTA, INTB, INTC, INTD}, + {INTB, INTC, INTD, INTA}, + {INTC, INTD, INTA, INTB}, + {INTD, INTA, INTB, INTC} + }; + + int irq = -1; + + if (slot >= 1 && slot <= IXP425_PCI_MAX_DEV && + pin >= 1 && pin <= IXP425_PCI_IRQ_LINES) + { + irq = pci_irq_table[slot-1][pin-1]; + } + + return irq; +} + +struct hw_pci ixdp425_pci __initdata = { + init: ixdp425_pci_init, + swizzle: common_swizzle, + map_irq: ixdp425_map_irq, +}; + diff -Nru a/arch/arm/mach-ixp425/ixp425-irq.c b/arch/arm/mach-ixp425/ixp425-irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/ixp425-irq.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,74 @@ +/* + * arch/arm/mach-ixp425/ixp425-irq.c + * + * Generic IRQ routines for IXP425 based systems + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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 + +static void ixp425_irq_mask(unsigned int irq) +{ + *IXP425_ICMR &= ~BIT(irq); +} + +static void ixp425_irq_mask_ack(unsigned int irq) +{ + static int irq2gpio[NR_IRQS] = { + -1, -1, -1, -1, -1, -1, 0, 1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, -1, -1, + }; + int line = irq2gpio[irq]; + + if (line > 0) + gpio_line_isr_clear(line); + + ixp425_irq_mask(irq); +} + +static void ixp425_irq_unmask(unsigned int irq) +{ + *IXP425_ICMR |= BIT(irq); +} + +void __init ixp425_init_irq(void) +{ + int i = 0; + + /* Route all sources to IRQ instead of FIQ */ + *IXP425_ICLR = 0x0; + /* Disable all interrupt */ + *IXP425_ICMR = 0x0; + + for(i = 0; i < NR_IRQS; i++) + { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = ixp425_irq_mask_ack; + irq_desc[i].mask = ixp425_irq_mask; + irq_desc[i].unmask = ixp425_irq_unmask; + } +} diff -Nru a/arch/arm/mach-ixp425/ixp425-pci.c b/arch/arm/mach-ixp425/ixp425-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/ixp425-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,523 @@ +/* + * arch/arm/mach-ixp425/ixp425-pci.c + * + * IXP425 PCI routines + * + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002 Intel 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 +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +# define DBG(x...) printk(__FILE__": "x) +#else +# define DBG(x...) +#endif + +int (*ixp425_pci_read)(u32 addr, u32 cmd, u32* data); + +/* + * PCI cfg an I/O routines are done by programming a + * command/byte enable register, and then read/writing + * the data from a data regsiter. We need to ensure + * these transactions are atomic or we will end up + * with corrupt data on the bus or in a driver. + */ +static spinlock_t ixp425_pci_lock = SPIN_LOCK_UNLOCKED; + +/* + * Read from PCI config space + */ +static void crp_read(u32 ad_cbe, u32 *data) +{ + unsigned long flags; + spin_lock_irqsave(&ixp425_pci_lock, flags); + *PCI_CRP_AD_CBE = ad_cbe; + *data = *PCI_CRP_RDATA; + spin_unlock_irqrestore(&ixp425_pci_lock, flags); +} + +/* + * Write to PCI config space + */ +static void crp_write(u32 ad_cbe, u32 data) +{ + unsigned long flags; + spin_lock_irqsave(&ixp425_pci_lock, flags); + *PCI_CRP_AD_CBE = CRP_AD_CBE_WRITE | ad_cbe; + *PCI_CRP_WDATA = data; + spin_unlock_irqrestore(&ixp425_pci_lock, flags); +} + +static int local_read_config_byte(int where, u8 *value) +{ + u32 n, data; + DBG("local_read_config_byte from %d\n", where); + n = where % 4; + crp_read(where & ~3, &data); + *value = data >> (8*n); + DBG("local_read_config_byte read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int local_read_config_word(int where, u16 *value) +{ + u32 n, data; + DBG("local_read_config_word from %d\n", where); + n = where % 4; + crp_read(where & ~3, &data); + *value = data >> (8*n); + DBG("local_read_config_word read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int local_read_config_dword(int where, u32 *value) +{ + DBG("local_read_config_dword from %d\n", where); + crp_read(where & ~3, value); + DBG("local_read_config_dword read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int local_write_config_byte(int where, u8 value) +{ + u32 n, byte_enables, data; + DBG("local_write_config_byte %#x to %d\n", value, where); + n = where % 4; + byte_enables = (0xf & ~BIT(n)) << CRP_AD_CBE_BESL; + data = value << (8*n); + crp_write((where & ~3) | byte_enables, data); + return PCIBIOS_SUCCESSFUL; +} + +static int local_write_config_word(int where, u16 value) +{ + u32 n, byte_enables, data; + DBG("local_write_config_word %#x to %d\n", value, where); + n = where % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL; + data = value << (8*n); + crp_write((where & ~3) | byte_enables, data); + return PCIBIOS_SUCCESSFUL; +} + +static int local_write_config_dword(int where, u32 value) +{ + DBG("local_write_config_dword %#x to %d\n", value, where); + crp_write(where & ~3, value); + return PCIBIOS_SUCCESSFUL; +} + +static inline int check_master_abort(void) +{ + /* check Master Abort bit after access */ + unsigned long isr = *PCI_ISR; + + if (isr & PCI_ISR_PFE) + { + /* make sure the Master Abort bit is reset */ + *PCI_ISR = PCI_ISR_PFE; + DBG(__FUNCTION__" failed\n"); + return 1; + } + + return 0; +} + +int ixp425_pci_read_errata(u32 addr, u32 cmd, u32* data) +{ + unsigned long flags; + int retval = 0; + int i; + + spin_lock_irqsave(&ixp425_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* + * PCI workaround - only works if NP PCI space reads have + * no side effects!!! Read 8 times. last one will be good. + */ + for (i = 0; i < 8; i++) + { + *PCI_NP_CBE = cmd; + *data = *PCI_NP_RDATA; + *data = *PCI_NP_RDATA; + } + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp425_pci_lock, flags); + return retval; +} + +int ixp425_pci_read_no_errata(u32 addr, u32 cmd, u32* data) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&ixp425_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* set up and execute the read */ + *PCI_NP_CBE = cmd; + + /* the result of the read is now in NP_RDATA */ + *data = *PCI_NP_RDATA; + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp425_pci_lock, flags); + return retval; +} + +int ixp425_pci_write(u32 addr, u32 cmd, u32 data) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&ixp425_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* set up the write */ + *PCI_NP_CBE = cmd; + + /* execute the write by writing to NP_WDATA */ + *PCI_NP_WDATA = data; + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp425_pci_lock, flags); + return retval; +} + +static u32 ixp425_config_addr(u8 bus_num, u16 devfn, int where) +{ + u32 addr; + if (!bus_num) + { + /* type 0 */ + addr = BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | + (where & ~3); + } + else + { + /* type 1 */ + addr = (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | + ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; + } + return addr; +} + +static int read_config_byte(u8 bus_num, u16 devfn, int where, u8 *value) +{ + u32 n, byte_enables, addr, data; + DBG("read_config_byte from %d dev %d:%d:%d\n", where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + n = where % 4; + byte_enables = (0xf & ~BIT(n)) << 4; + addr = ixp425_config_addr(bus_num, devfn, where); + if (ixp425_pci_read(addr, byte_enables | NP_CMD_CONFIGREAD, &data)) + { + *value = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *value = data >> (8*n); + DBG("read_config_byte read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int read_config_word(u8 bus_num, u16 devfn, int where, u16 *value) +{ + u32 n, byte_enables, addr, data; + DBG("read_config_word from %d dev %d:%d:%d\n", where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + n = where % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << 4; + addr = ixp425_config_addr(bus_num, devfn, where); + if (ixp425_pci_read(addr, byte_enables | NP_CMD_CONFIGREAD, &data)) + { + *value = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *value = data >> (8*n); + DBG("read_config_word read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + + +static int read_config_dword(u8 bus_num, u16 devfn, int where, u32 *value) +{ + u32 addr; + DBG("read_config_dword from %d dev %d:%d:%d\n", where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + addr = ixp425_config_addr(bus_num, devfn, where); + if (ixp425_pci_read(addr, NP_CMD_CONFIGREAD, value)) + { + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + DBG("read_config_dword read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_byte(u8 bus_num, u16 devfn, int where, u8 value) +{ + u32 n, byte_enables, addr, data; + DBG("write_config_byte %#x to %d dev %d:%d:%d\n", value, where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + n = where % 4; + byte_enables = (0xf & ~BIT(n)) << 4; + addr = ixp425_config_addr(bus_num, devfn, where); + data = value << (8*n); + if (ixp425_pci_write(addr, byte_enables | NP_CMD_CONFIGWRITE, data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_word(u8 bus_num, u16 devfn, int where, u16 value) +{ + u32 n, byte_enables, addr, data; + DBG("write_config_word %#x to %d dev %d:%d:%d\n", value, where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + n = where % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << 4; + addr = ixp425_config_addr(bus_num, devfn, where); + data = value << (8*n); + if (ixp425_pci_write(addr, byte_enables | NP_CMD_CONFIGWRITE, data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static int write_config_dword(u8 bus_num, u16 devfn, int where, u32 value) +{ + u32 addr; + DBG("write_config_dword %#x to %d dev %d:%d:%d\n", value, where, bus_num, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + addr = ixp425_config_addr(bus_num, devfn, where); + if (ixp425_pci_write(addr, NP_CMD_CONFIGWRITE, value)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + + +/* + * We have different access functions for local (IXP425) and + * bus devices. This macro nicely hides that fact from the + * layers above. + */ +#define IXP425_PCI_OP(rw, size, type) \ +static int ixp425_##rw##_config_##size(struct pci_dev *dev, int where, \ + type value) \ +{ \ + if (!dev->bus->number && !PCI_SLOT(dev->devfn)) \ + return local_##rw##_config_##size(where, value); \ + else \ + return rw##_config_##size(dev->bus->number, dev->devfn, where, value); \ +} + +IXP425_PCI_OP(read, byte, u8 *) +IXP425_PCI_OP(read, word, u16 *) +IXP425_PCI_OP(read, dword, u32 *) +IXP425_PCI_OP(write, byte, u8) +IXP425_PCI_OP(write, word, u16) +IXP425_PCI_OP(write, dword, u32) + +struct pci_ops ixp425_ops = +{ + ixp425_read_config_byte, + ixp425_read_config_word, + ixp425_read_config_dword, + ixp425_write_config_byte, + ixp425_write_config_word, + ixp425_write_config_dword, +}; + +/* + * PCI abort handler + */ +static int abort_handler(unsigned long addr, unsigned long fsr, struct pt_regs *regs) +{ + u32 isr; + u16 status; + + isr = *PCI_ISR; + local_read_config_word(PCI_STATUS, &status); + printk("!!!abort_handler addr = %#lx, isr = %#x, status = %#x\n", addr, + isr, status); + + /* make sure the Master Abort bit is reset */ + *PCI_ISR = PCI_ISR_PFE; + status |= PCI_STATUS_REC_MASTER_ABORT; + local_write_config_word(PCI_STATUS,status); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +static struct pci_controller *hose; + +int __init ixp425_pci_is_host(void) +{ + u32 csr; + + csr = *PCI_CSR; + return csr & PCI_CSR_HOST; +} + +void __init ixp425_pci_init(void *sysdata) +{ + unsigned long processor_id; + + asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); + + if(!(processor_id & 0xf)) { + printk("IXP425 PCI: A0 silicon detected - PCI Non-Prefetch Workaround Enabled\n"); + ixp425_pci_read = ixp425_pci_read_errata; + } else + ixp425_pci_read = ixp425_pci_read_no_errata; + + /* hook in our fault handler for PCI errors */ + hook_fault_code(4, abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(6, abort_handler, SIGBUS, "external abort on line fetch\n"); + hook_fault_code(8, abort_handler, SIGBUS, "external abort on non-line fetch\n"); + hook_fault_code(10, abort_handler, SIGBUS, "external abort on non-line fetch\n"); + + /* + * We use identity AHB->PCI address translation + * in the 0x48000000 address space + */ + DBG("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n"); + *PCI_PCIMEMBASE = 0x48494A4B; + + /* + * We also use identity PCI->AHB address translation + * in 4 16MB BARs that begin at the physical memory start + */ + *PCI_AHBMEMBASE = (PHYS_OFFSET & 0xFF000000) + + ((PHYS_OFFSET & 0xFF000000) >> 8) + + ((PHYS_OFFSET & 0xFF000000) >> 16) + + ((PHYS_OFFSET & 0xFF000000) >> 24) + + 0x00010203; + + if (ixp425_pci_is_host()) + { + DBG("setup BARs in controller\n"); + + /* + * We configure the PCI inbound memory windows to be 1:1 mapped to SDRAM + */ + local_write_config_dword(PCI_BASE_ADDRESS_0, PHYS_OFFSET + 0x00000000); + local_write_config_dword(PCI_BASE_ADDRESS_1, PHYS_OFFSET + 0x01000000); + local_write_config_dword(PCI_BASE_ADDRESS_2, PHYS_OFFSET + 0x02000000); + local_write_config_dword(PCI_BASE_ADDRESS_3, PHYS_OFFSET + 0x03000000); + + /* + * Disable our CSR and I/O windows from responding + * to anything. Since we're the master, no one should + * be fiddling with our internals. + */ + local_write_config_dword(PCI_BASE_ADDRESS_4, 0xffffffff); + local_write_config_dword(PCI_BASE_ADDRESS_5, 0xffffffff); + } + + DBG("clear error bits in ISR\n"); + *PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE; + + /* + * Set Initialize Complete in PCI Control Register: allow IXP425 to + * respond to PCI configuration cycles. Specify that the AHB bus is + * operating in big endian mode. Set up byte lane swapping between + * little-endian PCI and the big-endian AHB bus + */ +#ifdef __ARMEB__ + *PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS; +#else + *PCI_CSR = PCI_CSR_IC; +#endif + + if (ixp425_pci_is_host()) + { + local_write_config_word(PCI_COMMAND, PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY); + + DBG("allocating hose\n"); + hose = pcibios_alloc_controller(); + if (!hose) + panic("Could not allocate PCI hose"); + + hose->first_busno = 0; + hose->last_busno = 0; + hose->io_space.start = 0; + hose->io_space.end = 0xffffffff; + hose->mem_space.start = 0x48000000; + hose->mem_space.end = 0x4bffffff; + + /* autoconfig the bus */ DBG("AUTOCONFIG\n"); + hose->last_busno = pciauto_bus_scan(hose, 0); + + /* scan the bus */ + DBG("SCANNING THE BUS\n"); + pci_scan_bus(0, &ixp425_ops, sysdata); + } + + DBG("DONE\n"); +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ + int devfn, int offset, type value) \ +{ \ + return ixp425_##rw##_config_##size(fake_pci_dev(hose, bus, devfn), \ + offset, value); \ +} + + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) diff -Nru a/arch/arm/mach-ixp425/ixp425-time.c b/arch/arm/mach-ixp425/ixp425-time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/ixp425-time.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,94 @@ +/* + * arch/arm/mach-ixp425/ixp425-time.c + * + * Timer tick for IXP425 based sytems. We use OS timer1 on the CPU for + * the timer tick and the timestamp counter to account for missed jiffies. + * + * Author: Peter Barry + * Copyright: (C) 2001 Intel Corporation. + * (C) 2002-2003 MontaVista Software, Inc. + * + * Maintainer: Deepak Saxena + * + * 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 + +extern int setup_arm_irq(int, struct irqaction *); +static unsigned volatile last_jiffy_time; + +#define USEC_PER_SEC 1000000 +#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC) + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long ixp425_gettimeoffset(void) +{ + u32 elapsed, usec, curr, reload; + volatile u32 stat1, stat2; + + elapsed = *IXP425_OSTS - last_jiffy_time; + + return elapsed / CLOCK_TICKS_PER_USEC; +} + +static void ixp425_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + + /* Clear Pending Interrupt by writing '1' to it */ + *IXP425_OSST = IXP425_OSST_TIMER_1_PEND; + + /* + * Catch up with the real idea of time + */ + while((*IXP425_OSTS - last_jiffy_time) > LATCH) { + do_timer(regs); + last_jiffy_time += LATCH; + } +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + name: "Timer Tick", + flags: SA_INTERRUPT +}; + +void __init setup_timer(void) +{ + gettimeoffset = ixp425_gettimeoffset; + timer_irq.handler = ixp425_timer_interrupt; + + /* Clear Pending Interrupt by writing '1' to it */ + *IXP425_OSST = IXP425_OSST_TIMER_1_PEND; + + /* Setup the Timer counter value */ + *IXP425_OSRT1 = (LATCH & ~IXP425_OST_RELOAD_MASK) | IXP425_OST_ENABLE; + + /* Reset time-stamp counter */ + *IXP425_OSTS = 0; + last_jiffy_time = 0; + + /* Connect the interrupt handler and enable the interrupt */ + setup_arm_irq(IRQ_IXP425_TIMER1, &timer_irq); +} + + diff -Nru a/arch/arm/mach-ixp425/kgdb.c b/arch/arm/mach-ixp425/kgdb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/kgdb.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define UART_BASE ((volatile u32*)IXP425_UART2_BASE_VIRT) +#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE) + +void kgdb_serial_init(void) +{ + /* Enable access to DLL/DLM */ + UART_BASE[UART_LCR] = 0x80; + /* Set baud rate devisors */ + UART_BASE[UART_DLL] = IXP425_DEF_UART_BAUD_DLL; + UART_BASE[UART_DLM] = IXP425_DEF_UART_BAUD_DLM; + /* 8N1 */ + UART_BASE[UART_LCR] = 0x3; + /* DMAE=0 (no DMA), UUE(Unit enble)=1 */ + UART_BASE[UART_IER] = 0x40; + /* RESESTTF | RESESTRF | TRFIFOE + * - reset Tx&Rx and enable tx/rx FIFO + */ + UART_BASE[UART_FCR] = 0x7; + /* Enable interrupt */ + UART_BASE[UART_MCR] = 0x8; + return; +} + +void kgdb_serial_putchar(unsigned char ch) +{ + /* Check THRE and TEMT bits before we transmit the character. + */ + while ((UART_BASE[UART_LSR] & TX_DONE) != TX_DONE); + *UART_BASE = ch; +} + +unsigned char kgdb_serial_getchar(void) +{ + /* Wait for incomming char */ + while (!(UART_BASE[UART_LSR] & UART_LSR_DR)); + return (u8)*UART_BASE; +} diff -Nru a/arch/arm/mach-ixp425/mm.c b/arch/arm/mach-ixp425/mm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/mm.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,70 @@ +/* + * arch/arm/mach-ixp425/mm.c + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003 MontaVista Sofwtare, Inc. + * + * 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 + +/* See asm/arch/ixp425.h for a detailed memory map */ + +/* Common mappings */ +static struct map_desc ixp425_io_desc[] __initdata = { + /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACS, USB .... */ + { + IXP425_PERIPHERAL_BASE_VIRT, + IXP425_PERIPHERAL_BASE_PHYS, + IXP425_PERIPHERAL_REGION_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + /* r w c b */ + }, + /* PCI Config Registers */ + { + IXP425_PCI_CFG_BASE_VIRT, + IXP425_PCI_CFG_BASE_PHYS, + IXP425_PCI_CFG_REGION_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + /* r w c b */ + }, + /* Expansion Bus Config Registers */ + { + IXP425_EXP_CFG_BASE_VIRT, + IXP425_EXP_CFG_BASE_PHYS, + IXP425_EXP_CFG_REGION_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + /* r w c b */ + }, + /* Queue Manager - Required for Intel CSR and NPE access */ + { + IXP425_QMGR_BASE_VIRT, + IXP425_QMGR_BASE_PHYS, + IXP425_QMGR_REGION_SIZE, + DOMAIN_IO, 0, 1, 0, 0 + /* r w c b */ + }, + LAST_DESC +}; + + + +void __init ixp425_map_io(void) +{ + /* Common Mapping */ + iotable_init(ixp425_io_desc); +} + diff -Nru a/arch/arm/mach-ixp425/pci-auto.c b/arch/arm/mach-ixp425/pci-auto.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/pci-auto.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,379 @@ +/* + * arch/arm/mach-iop310/pci-auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 + +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int bar_limit) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask, bar_nr = 0; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) + { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) + { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr); + } + else + { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) + { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + bar_nr++; + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + DBG("PCI Autoconfig: Bridge %d. IO_FILTER = %#010x..%#010x\n", + current_bus, + (pciauto_upper_iospc & 0x0000f000) >> 8, + pciauto_upper_iospc >> 16); + + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) + { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn=0; pci_devfn<0xff; pci_devfn++) + { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + /* If config space read fails from this device, move on */ + if (early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) + { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) + { + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } + else + { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) + { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) + { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_5); + } + } + } + return sub_bus; +} diff -Nru a/arch/arm/mach-ixp425/pci-io.c b/arch/arm/mach-ixp425/pci-io.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/pci-io.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,127 @@ +/* + * arch/arm/mach-ixp425/ixp425-io.c + * + * PCI I/O routines for IXP425. IXP425 does not have an outbound + * I/O window, so we need to manually convert each operation into + * a set of register acceses to configure the PCI byye lanes + * that we want enabled, and then do the transaction. + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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. + * + * TODO: We probably want to at least inline these, and maybe + * even ix425_pci_write? + */ + +#include +#include +#include + +void ixp425_outb(u8 v, u32 p) +{ + u32 n, byte_enables, data; + n = p % 4; + byte_enables = (0xf & ~BIT(n)) << IXP425_PCI_NP_CBE_BESL; + data = v << (8*n); + ixp425_pci_write(p, byte_enables | NP_CMD_IOWRITE, data); +} + +void ixp425_outw(u16 v, u32 p) +{ + u32 n, byte_enables, data; + n = p % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << IXP425_PCI_NP_CBE_BESL; + data = v << (8*n); + ixp425_pci_write(p, byte_enables | NP_CMD_IOWRITE, data); +} + +void ixp425_outl(u32 v, u32 p) +{ + ixp425_pci_write(p, NP_CMD_IOWRITE, v); +} + +u8 ixp425_inb(u32 p) +{ + u32 n, byte_enables, data; + n = p % 4; + byte_enables = (0xf & ~BIT(n)) << IXP425_PCI_NP_CBE_BESL; + if (ixp425_pci_read(p, byte_enables | NP_CMD_IOREAD, &data)) + return 0xff; + + return data >> (8*n); +} + +u16 ixp425_inw(u32 p) +{ + u32 n, byte_enables, data; + n = p % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << IXP425_PCI_NP_CBE_BESL; + if (ixp425_pci_read(p, byte_enables | NP_CMD_IOREAD, &data)) + return 0xffff; + + return data>>(8*n); +} + +u32 ixp425_inl(u32 p) +{ + u32 data; + if (ixp425_pci_read(p, NP_CMD_IOREAD, &data)) + return 0xffffffff; + + return data; +} + +void ixp425_outsb(u32 p, u8 *addr, u32 count) +{ + while (count--) + outb(*addr++, p); +} + +void ixp425_outsw(u32 p, u16 *addr, u32 count) +{ + while (count--) + outw(*addr++, p); +} + +void ixp425_outsl(u32 p, u32 *addr, u32 count) +{ + while (count--) + outl(*addr++, p); +} + +void ixp425_insb(u32 p, u8 *addr, u32 count) +{ + while (count--) + *addr++ = inb(p); +} + +void ixp425_insw(u32 p, u16 *addr, u32 count) +{ + while (count--) + *addr++ = inw(p); +} + +void ixp425_insl(u32 p, u32 *addr, u32 count) +{ + while (count--) + *addr++ = inl(p); +} + +EXPORT_SYMBOL(ixp425_outb); +EXPORT_SYMBOL(ixp425_outw); +EXPORT_SYMBOL(ixp425_outl); +EXPORT_SYMBOL(ixp425_inb); +EXPORT_SYMBOL(ixp425_inw); +EXPORT_SYMBOL(ixp425_inl); +EXPORT_SYMBOL(ixp425_outsb); +EXPORT_SYMBOL(ixp425_outsw); +EXPORT_SYMBOL(ixp425_outsl); +EXPORT_SYMBOL(ixp425_insb); +EXPORT_SYMBOL(ixp425_insw); +EXPORT_SYMBOL(ixp425_insl); + diff -Nru a/arch/arm/mach-ixp425/pci.c b/arch/arm/mach-ixp425/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,250 @@ +/* + * arch/arm/mach-iop310/pci.c + * + * Generic PCI support functionality that should eventually move to + * arch/arm/kernel/bios32.c. Derived from support in ppc and alpha. + * + * Matt Porter + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct pci_controller* hose_head; +struct pci_controller** hose_tail = &hose_head; + +/* + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * some boards that don't follow the PCI spec's suggestion so we + * break this piece out separately. + */ +static inline u8 +bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +u8 __init +common_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(dev->bus->number); + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the slot of the last bridge. */ + } + + return PCI_SLOT(dev->devfn); +} + +/* + * Null PCI config access functions, for the case when we can't + * find a hose. + */ +#define NULL_PCI_OP(rw, size, type) \ +static int \ +null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ +{ \ + return PCIBIOS_DEVICE_NOT_FOUND; \ +} + + NULL_PCI_OP(read, byte, u8 *) + NULL_PCI_OP(read, word, u16 *) + NULL_PCI_OP(read, dword, u32 *) + NULL_PCI_OP(write, byte, u8) + NULL_PCI_OP(write, word, u16) +NULL_PCI_OP(write, dword, u32) + +static struct pci_ops null_pci_ops = +{ + null_read_config_byte, + null_read_config_word, + null_read_config_dword, + null_write_config_byte, + null_write_config_word, + null_write_config_dword +}; + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +struct pci_dev * +fake_pci_dev(struct pci_controller *hose, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + if (hose == 0) { + hose = pci_bus_to_hose(busnr); + if (hose == 0) + printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); + } + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose? hose->ops: &null_pci_ops; + return &dev; +} + +static int next_controller_index; + +struct pci_controller * __init +pcibios_alloc_controller(void) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *)kmalloc(sizeof(*hose), GFP_KERNEL); + memset(hose, 0, sizeof(struct pci_controller)); + + *hose_tail = hose; + hose_tail = &hose->next; + + hose->index = next_controller_index++; + + return hose; +} + +struct pci_controller * +pci_bus_to_hose(int bus) +{ + struct pci_controller *hose = hose_head; + + for (; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + return NULL; +} + +void __init +pci_exclude_device(unsigned char bus, unsigned char devfn) +{ + struct pci_dev *dev, *pdev = NULL; + + /* Walk the pci device list */ + pci_for_each_dev(dev) + { + if ((dev->bus->number == bus) && (dev->devfn == devfn)) + { + /* + * Remove the device from the global and + * bus lists. + */ + list_del(&(dev->global_list)); + list_del(&(dev->bus_list)); + + /* Free the pci_dev structure */ + kfree(dev); + + break; + } + pdev = dev; + } +} + +static inline void __init alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + pr = pci_find_parent_resource(dev, r); + if(!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Can not allocate resource region %d" \ + " of device %s\n", idx, dev->slot_name); + r->end -= r->start; + r->start = 0; + } +} + +void __init +pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct list_head *ln; + struct pci_bus *bus; + int i; + struct resource *res, *pr; + + if(!bus_list) return; + + /* Depth-First Search on bus tree */ + for (ln = bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + pci_read_bridge_bases(bus); + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Can not allocate resource region " + "%d of PCI bridge %d\n", i, bus->number); + DBG("PCI: resource is %lx..%lx (%lx)\n", + res->start, res->end, res->flags); + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +void __init pcibios_allocate_resources(void) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r; + + pci_for_each_dev(dev) + { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) + { + r = &dev->resource[idx]; + + if(r->parent) + continue; + if(!r->start) + continue; + + alloc_resource(dev, idx); + } + } +} + + diff -Nru a/arch/arm/mach-ixp425/pcibuf.c b/arch/arm/mach-ixp425/pcibuf.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/pcibuf.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,238 @@ +/* + * arch/arm/mach-ixp425/ixp425-pcibuf.c + * + * IXP425 PCI bounce buffer routines. The IXP425 only has a 64MB inbound + * PCI window, but allows for up 256MB of SDRAM. This means that if + * running with > 64MB of memory, we need to bounce buffers between the + * safe and unsafe areas. An attempt was made to port the SA1111 bounce + * routines to this platform but that does not work due to the fact that + * EEPro100 (and probably others) PCI driver calls pci_map_single() while + * handling interrupts to refill Rx buffers. The sa1111 implementation + * of bounce buffering uses pci_pools which call pci_alloc_consistent + * which calls consistent_alloc which is not interrupt safe on 2.4. + * We're basically doing the same, except that we are using our own + * object cache instead of relying on the PCI layer to take care of + * it for us. + * + * This file we be killed in 2.5 and replaced with the sa1111 style + * implementation. + * + * Maintainer: Deepak Saxena + * + * Copyright (C) 2003 MontaVista Software, Inc. + * Copyright (C) 2002 Intel 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 + +// #define DEBUG +#ifdef DEBUG +# define DBG(x...) printk(KERN_DEBUG __FILE__": "x) +#else +# define DBG(x...) +#endif + +/* + * From SA1111 implementation + */ +struct safe_buffer { + struct list_head node; + + /* Original request */ + void *ptr; + size_t size; + + /* Safe buffer information */ + void *safe; + dma_addr_t safe_dma_addr; +}; + +LIST_HEAD(safe_buffers); + +static spinlock_t pcibuf_lock = SPIN_LOCK_UNLOCKED; + +static inline void * +alloc_safe_buffer(void *unsafe, int size, dma_addr_t *dma_addr) +{ + struct safe_buffer *safe_buf; + unsigned long flags; + + DBG("alloc_safe_buffer(size=%d)\n", size); + + /* + * This should really be it's own object cache... + */ + safe_buf = kmalloc(sizeof(*safe_buf), GFP_ATOMIC); + if(!safe_buf) + return 0; + + safe_buf->safe = kmalloc(size, GFP_DMA | GFP_ATOMIC); + + if (!safe_buf->safe) { + kfree(safe_buf); + return 0; + } + + safe_buf->ptr = unsafe; + safe_buf->size = size; + *dma_addr = safe_buf->safe_dma_addr = virt_to_bus(safe_buf->safe); + + spin_lock_irqsave(&pcibuf_lock, flags); + list_add(&safe_buf->node, &safe_buffers); + spin_unlock_irqrestore(&pcibuf_lock, flags); + + return safe_buf->safe; +} + +static inline void +free_safe_buffer(struct safe_buffer *safe_buf) +{ + unsigned long flags; + + spin_lock_irqsave(&pcibuf_lock, flags); + list_del(&safe_buf->node); + kfree(safe_buf->safe); + kfree(safe_buf); + spin_unlock_irqrestore(&pcibuf_lock, flags); +} + +static inline void* +find_safe_buffer(dma_addr_t dma_addr, void **unsafe) +{ + struct list_head *entry; + struct safe_buffer *safe_buf; + unsigned long flags; + + spin_lock_irqsave(&pcibuf_lock, flags); + list_for_each(entry, &safe_buffers) { + safe_buf = list_entry(entry, struct safe_buffer, node); + + if(safe_buf->safe_dma_addr == dma_addr) { + *unsafe = safe_buf->ptr; + spin_unlock_irqrestore(&pcibuf_lock, flags); + return safe_buf; + } + } + spin_unlock_irqrestore(&pcibuf_lock, flags); + + return 0; +} + +dma_addr_t ixp425_map_single(void *virt, size_t size, int direction) +{ + dma_addr_t dma_addr; + unsigned long flags; + void *safe; + + DBG("ixp425_map_single(virt=%p,size=%d,dir=%x)\n", + virt, size, direction); + + /* + * FIX ME: We are assuming we are in host mode and therefore + * the inbound BAR is set to 0. + * + * Need to check (dma_addr + size ) > (BAR0 + SZ_64M) + */ + dma_addr = virt_to_bus(virt); + + if((dma_addr+size) >= SZ_64M) { + safe = alloc_safe_buffer(virt, size, &dma_addr); + if (!safe) { + printk(KERN_ERR "%s: Could not allocate safe buffer", + __FILE__); + return 0; + } + + DBG("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", virt, + (void *)virt_to_phys(virt), safe, (void *)dma_addr); + + /* + * Only need to copy if DMAing to device + */ + if((direction == PCI_DMA_TODEVICE) || + (direction == PCI_DMA_BIDIRECTIONAL)) { + memcpy(safe, virt, size); + } + consistent_sync(safe, size, direction); + } + else + consistent_sync(virt, size, direction); + + return dma_addr; +} + +void ixp425_unmap_single(dma_addr_t dma_addr, size_t size, int direction) +{ + void *safe, *unsafe; + unsigned long flags; + struct safe_buffer *safe_buf; + + DBG("ixp425_unmap_single(ptr=%p, size=%d, dir=%x)\n", + (void *)dma_addr, size, direction); + + if ((safe_buf = find_safe_buffer(dma_addr, &unsafe))) { + if((direction == PCI_DMA_FROMDEVICE) || + (direction == PCI_DMA_BIDIRECTIONAL)) { + DBG("copyback unsafe %p, safe %p, size %d\n", unsafe, safe_buf->safe, size); + consistent_sync(safe_buf->safe, size, direction); + memcpy(unsafe, safe_buf->safe, size); + } + + free_safe_buffer(safe_buf); + } else { + /* + * Assume this is normal memory. We have a possible + * OOPs here if someone sends us a bad dma_addr_t. + */ + unsafe = bus_to_virt(dma_addr); + consistent_sync(unsafe, size, direction); + } +} + +void ixp425_sync_single(dma_addr_t dma_addr, size_t size, int direction) +{ + void *safe, *unsafe; + unsigned long flags; + struct safe_buffer *safe_buf; + + DBG("ixp425_sync_single(dma_addr=%p, size=%d, dir=%x)\n", + (void *)dma_addr, size, direction); + + if((safe_buf = find_safe_buffer(dma_addr, &unsafe))) { + DBG("copyback unsafe %p, safe %p, size %d\n", unsafe, safe_buf->safe, size); + switch(direction) { + case PCI_DMA_TODEVICE: + memcpy(safe_buf->safe, unsafe, size); + consistent_sync(safe_buf->safe, size, direction); + break; + case PCI_DMA_FROMDEVICE: + consistent_sync(safe_buf->safe, size, direction); + memcpy(unsafe, safe_buf->safe, size); + break; + } + } else { + /* assume this is normal memory */ + unsafe = bus_to_virt(dma_addr); + consistent_sync(unsafe, size, direction); + } +} + + +EXPORT_SYMBOL(ixp425_map_single); +EXPORT_SYMBOL(ixp425_unmap_single); +EXPORT_SYMBOL(ixp425_sync_single); + + diff -Nru a/arch/arm/mach-ixp425/prpmc1100-pci.c b/arch/arm/mach-ixp425/prpmc1100-pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-ixp425/prpmc1100-pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,93 @@ +/* + * arch/arm/mach-ixp425/prpmc1100-pci.c + * + * PrPMC1100 PCI initialization + * + * Copyright (C) 2003 MontaVista Sofwtare, Inc. + * Based on IXDP425 code originally (C) Intel Corporation + * + * Author: Deepak Saxena + * + * PrPMC1100 PCI init code. GPIO usage is similar to that on + * IXDP425, but the IRQ routing is completely different and + * depends on what carrier you are using. This code is written + * to work on the Motorola PrPMC800 ATX carrier board. + * + * 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 + + +/* PCI controller pin mappings */ +#define INTA_PIN IXP425_GPIO_PIN_11 +#define INTB_PIN IXP425_GPIO_PIN_10 +#define INTC_PIN IXP425_GPIO_PIN_9 +#define INTD_PIN IXP425_GPIO_PIN_8 + +#define IXP425_PCI_RESET_GPIO IXP425_GPIO_PIN_13 +#define IXP425_PCI_CLK_PIN IXP425_GPIO_CLK_0 +#define IXP425_PCI_CLK_ENABLE IXP425_GPIO_CLK0_ENABLE +#define IXP425_PCI_CLK_TC_LSH IXP425_GPIO_CLK0TC_LSH +#define IXP425_PCI_CLK_DC_LSH IXP425_GPIO_CLK0DC_LSH + +void __init prpmc1100_pci_init(void *sysdata) +{ + gpio_line_config(INTA_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTB_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTC_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + gpio_line_config(INTD_PIN, IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(INTA_PIN); + gpio_line_isr_clear(INTB_PIN); + gpio_line_isr_clear(INTC_PIN); + gpio_line_isr_clear(INTD_PIN); + + ixp425_pci_init(sysdata); +} + + +/* + * Interrupt mapping + */ +#define INTA IRQ_PRPMC1100_PCI_INTA +#define INTB IRQ_PRPMC1100_PCI_INTB +#define INTC IRQ_PRPMC1100_PCI_INTC +#define INTD IRQ_PRPMC1100_PCI_INTD + +static int __init prpmc1100_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + const long min_idsel = 10, max_idsel = 16, irqs_per_slot = 4; + + static int pci_irq_table[][4] = + { + {INTD, INTA, INTB, INTC}, /* IDSEL 16 - PMC A1 */ + {INTD, INTA, INTB, INTC}, /* IDSEL 17 - PRPMC-A-B */ + {INTA, INTB, INTC, INTD}, /* IDSEL 18 - PMC A1-B */ + {0, 0, 0, 0}, /* IDSEL 19 - Unused */ + {INTA, INTB, INTC, INTD}, /* IDSEL 20 - P2P Bridge */ + {INTC, INTD, INTA, INTB}, /* IDSEL 21 - PMC A2 */ + {INTD, INTA, INTB, INTC}, /* IDSEL 22 - PMC A2-B */ + }; + + + return PCI_IRQ_TABLE_LOOKUP; +} + +struct hw_pci prpmc1100_pci __initdata = { + init: prpmc1100_pci_init, + swizzle: common_swizzle, + map_irq: prpmc1100_map_irq, +}; + diff -Nru a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile --- a/arch/arm/mm/Makefile Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/Makefile Thu Dec 4 16:24:25 2003 @@ -42,6 +42,7 @@ p-$(CONFIG_CPU_ARM1026) += proc-arm1026.o p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o +p-$(CONFIG_CPU_XSCALE) += proc-xscale.o xscale-lock.o # Integrator follows "new style" # Soon, others will do too, and we can get rid of this diff -Nru a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c --- a/arch/arm/mm/alignment.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/alignment.c Thu Dec 4 16:24:25 2003 @@ -138,6 +138,18 @@ #define TYPE_LDST 2 #define TYPE_DONE 3 +#ifdef __ARMEB__ +#define BE 1 +#define FIRST_BYTE_16 "mov %1, %1, ror #8\n" +#define FIRST_BYTE_32 "mov %1, %1, ror #24\n" +#define NEXT_BYTE "ror #24" +#else +#define BE 0 +#define FIRST_BYTE_16 +#define FIRST_BYTE_32 +#define NEXT_BYTE "lsr #8" +#endif + #define __get8_unaligned_check(ins,val,addr,err) \ __asm__( \ "1: "ins" %1, [%2], #1\n" \ @@ -157,9 +169,10 @@ #define __get16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ - __get8_unaligned_check(ins,val,a,err); \ __get8_unaligned_check(ins,v,a,err); \ - val |= v << 8; \ + val = v << ((BE) ? 8 : 0); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << ((BE) ? 0 : 8); \ if (err) \ goto fault; \ } while (0) @@ -173,13 +186,14 @@ #define __get32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ - __get8_unaligned_check(ins,val,a,err); \ __get8_unaligned_check(ins,v,a,err); \ - val |= v << 8; \ + val = v << ((BE) ? 24 : 0); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << ((BE) ? 16 : 8); \ __get8_unaligned_check(ins,v,a,err); \ - val |= v << 16; \ + val |= v << ((BE) ? 8 : 16); \ __get8_unaligned_check(ins,v,a,err); \ - val |= v << 24; \ + val |= v << ((BE) ? 0 : 24); \ if (err) \ goto fault; \ } while (0) @@ -193,9 +207,9 @@ #define __put16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ - __asm__( \ + __asm__( FIRST_BYTE_16 \ "1: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ + " mov %1, %1, "NEXT_BYTE"\n" \ "2: "ins" %1, [%2]\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ @@ -223,13 +237,13 @@ #define __put32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ - __asm__( \ + __asm__( FIRST_BYTE_32 \ "1: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ + " mov %1, %1, "NEXT_BYTE"\n" \ "2: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ + " mov %1, %1, "NEXT_BYTE"\n" \ "3: "ins" %1, [%2], #1\n" \ - " mov %1, %1, lsr #8\n" \ + " mov %1, %1, "NEXT_BYTE"\n" \ "4: "ins" %1, [%2]\n" \ "5:\n" \ " .section .fixup,\"ax\"\n" \ diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c --- a/arch/arm/mm/consistent.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/consistent.c Thu Dec 4 16:24:25 2003 @@ -103,8 +103,11 @@ #if defined(CONFIG_PCI) || defined(CONFIG_SA1111) if ((hwdev) == NULL || dev_is_sa1111(hwdev) || (hwdev)->dma_mask != 0xffffffff) -#endif gfp |= GFP_DMA; +#endif +#ifdef CONFIG_ARCH_IXP425 + gfp |= GFP_DMA; +#endif return consistent_alloc(gfp, size, handle); } diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c --- a/arch/arm/mm/fault-armv.c Thu Dec 4 16:24:26 2003 +++ b/arch/arm/mm/fault-armv.c Thu Dec 4 16:24:26 2003 @@ -84,6 +84,11 @@ { const struct fsr_info *inf = fsr_info + (fsr & 15); +#ifdef CONFIG_KGDB + if(kgdb_fault_expected) + kgdb_handle_bus_error(); +#endif + if (!inf->fn(addr, fsr, regs)) return; @@ -91,6 +96,12 @@ inf->name, fsr, addr); force_sig(inf->sig, current); show_pte(current->mm, addr); + +#ifdef CONFIG_KGDB + if(!user_mode(regs)) + do_kgdb(regs, inf->sig); +#endif + die_if_kernel("Oops", regs, 0); } diff -Nru a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c --- a/arch/arm/mm/fault-common.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/fault-common.c Thu Dec 4 16:24:25 2003 @@ -20,6 +20,7 @@ #include #include #include +#include #include "fault.h" @@ -143,7 +144,12 @@ "paging request", addr); show_pte(mm, addr); + +#ifdef CONFIG_KGDB + do_kgdb(regs, SIGKILL); +#endif die("Oops", regs, fsr); + do_exit(SIGKILL); } @@ -195,6 +201,12 @@ struct vm_area_struct *vma; int fault, mask; +#if defined(CONFIG_KGDB) + /* REVISIT: This one may not be required? */ + if (kgdb_fault_expected) + kgdb_handle_bus_error(); +#endif + vma = find_vma(mm, addr); fault = -2; /* bad map area */ if (!vma) @@ -260,6 +272,11 @@ struct task_struct *tsk; struct mm_struct *mm; int fault; + +#if defined(CONFIG_KGDB) + if (kgdb_fault_expected) + kgdb_handle_bus_error(); +#endif tsk = current; mm = tsk->mm; diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c --- a/arch/arm/mm/init.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/init.c Thu Dec 4 16:24:25 2003 @@ -497,11 +497,13 @@ /* * allocate the zero page. Note that we count on this going ok. */ + printk("alloc_bootmem_low\n"); zero_page = alloc_bootmem_low_pages(PAGE_SIZE); /* * initialise the page tables. */ + printk("memtable_init\n"); memtable_init(mi); if (mdesc->map_io) mdesc->map_io(); diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c --- a/arch/arm/mm/mm-armv.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/mm/mm-armv.c Thu Dec 4 16:24:25 2003 @@ -204,7 +204,6 @@ /* * Clear any PGD mapping. On a two-level page table system, - * the clearance is done by the middle-level functions (pmd) * rather than the top-level (pgd) functions. */ static inline void clear_mapping(unsigned long virt) @@ -221,7 +220,7 @@ static void __init create_mapping(struct map_desc *md) { unsigned long virt, length; - int prot_sect, prot_pte; + unsigned int prot_sect, prot_pte; long off; if (md->prot_read && md->prot_write && @@ -324,7 +323,6 @@ p->prot_write = 1; p->cacheable = 1; p->bufferable = 1; - p ++; } @@ -337,7 +335,6 @@ p->prot_write = 0; p->cacheable = 1; p->bufferable = 1; - p ++; #endif @@ -350,7 +347,6 @@ p->prot_write = 0; p->cacheable = 1; p->bufferable = 0; - p ++; #endif @@ -399,8 +395,9 @@ { int i; - for (i = 0; io_desc[i].last == 0; i++) + for (i = 0; io_desc[i].last == 0; i++) { create_mapping(io_desc + i); + } } static inline void free_memmap(int node, unsigned long start, unsigned long end) diff -Nru a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S --- a/arch/arm/mm/proc-sa110.S Thu Dec 4 16:24:26 2003 +++ b/arch/arm/mm/proc-sa110.S Thu Dec 4 16:24:26 2003 @@ -573,6 +573,8 @@ .asciz "StrongARM-1100" cpu_sa1110_name: .asciz "StrongARM-1110" +cpu_ixp1200_name: + .asciz "IXP12xx" .align .section ".text.init", #alloc, #execinstr @@ -699,6 +701,11 @@ .long cpu_sa1110_name .size cpu_sa1110_info, . - cpu_sa1110_info +cpu_ixp1200_info: + .long 0 + .long cpu_ixp1200_name + .size cpu_ixp_1200_info, . - cpu_ixp1200_info + .type cpu_arch_name, #object cpu_arch_name: .asciz "armv4" @@ -750,3 +757,16 @@ .long cpu_sa1110_info .long sa1100_processor_functions .size __sa1110_proc_info, . - __sa1110_proc_info + + .type __ixp1200_proc_info,#object +__ixp1200_proc_info: + .long 0x6901c120 + .long 0xfffffff0 + .long 0x00000c0e + b __sa110_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT + .long cpu_ixp1200_info + .long sa110_processor_functions + .size __ixp1200_proc_info, . - __ixp1200_proc_info diff -Nru a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mm/proc-xscale.S Thu Dec 4 16:24:26 2003 @@ -0,0 +1,1163 @@ +/* + * linux/arch/arm/mm/proc-xscale.S + * + * Author: Nicolas Pitre + * Created: November 2000 + * Copyright: (C) 2000, 2001 MontaVista Software Inc. + * + * 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. + * + * MMU functions for the Intel XScale CPUs + * + * 2001 Aug 21: + * some contributions by Brett Gaines + * Copyright 2001 by Intel Corp. + * + * 2001 Sep 08: + * Completely revisited, many important fixes + * Nicolas Pitre + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Some knobs for cache allocation policy. + * Allocate on write may or may not be beneficial depending on the memory + * usage pattern of your main application. Write through cache is definitely + * a performance loss in most cases, but might be used for special purposes. + */ +#ifdef CONFIG_XSCALE_XBIT +#define PMD_CACHE_WRITE_ALLOCATE 1 +#define PTE_CACHE_WRITE_ALLOCATE 1 +#else +#define PMD_CACHE_WRITE_ALLOCATE 0 +#define PTE_CACHE_WRITE_ALLOCATE 0 +#endif + +#define CACHE_WRITE_THROUGH 0 + +/* + * Ther are errata that says that dirty status bits in the cache may get + * corrupted. The workaround significantly affects performances, and the bug + * _might_ just not be that visible or critical to you, so it is configurable. + * Let's hope a future core revision will tell us this was only a bad dream. + * But in the mean time the risk and tradeoff is yours to decide.... + */ +#ifdef CONFIG_XSCALE_CACHE_ERRATA +#undef CACHE_WRITE_THROUGH +#define CACHE_WRITE_THROUGH 1 +#endif + +/* + * This is the maximum size of an area which will be flushed. If the area + * is larger than this, then we flush the whole cache + */ +#define MAX_AREA_SIZE 32768 + +/* + * the cache line size of the I and D cache + */ +#define CACHELINESIZE 32 + +/* + * the size of the data cache + */ +#define CACHESIZE 32768 + +/* + * and the page size + */ +#define PAGESIZE 4096 + +/* + * Virtual address used to allocate the cache when flushed + * + * This must be an address range which is _never_ used. It should + * apparently have a mapping in the corresponding page table for + * compatibility with future CPUs that _could_ require it. For instance we + * don't care. + * + * This must be aligned on a 2*CACHESIZE boundary. The code selects one of + * the 2 areas in alternance each time the clean_d_cache macro is used. + * Without this the XScale core exhibits cache eviction problems and no one + * knows why. + * + * Reminder: the vector table is located at 0xffff0000-0xffff0fff. + */ +#define CLEAN_ADDR 0xfffe0000 + +/* + * This macro is used to wait for a CP15 write and is needed + * when we have to ensure that the last operation to the co-pro + * was completed before continuing with operation. + */ + .macro cpwait, rd + mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 + mov \rd, \rd @ wait for completion + sub pc, pc, #4 @ flush instruction pipeline + .endm + + .macro cpwait_ret, lr, rd + mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 + sub pc, \lr, \rd, LSR #32 @ wait for completion and + @ flush instruction pipeline + .endm + +#if !CACHE_WRITE_THROUGH + +/* + * This macro cleans the entire dcache using line allocate. + * The main loop has been unrolled to reduce loop overhead. + * rd and rs are two scratch registers. + */ + .macro clean_d_cache, rd, rs + ldr \rs, =clean_addr + ldr \rd, [\rs] + eor \rd, \rd, #CACHESIZE + str \rd, [\rs] + add \rs, \rd, #CACHESIZE +1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + teq \rd, \rs + bne 1b + .endm + + .macro clean_d_line, rd + mcr p15, 0, \rd, c7, c10, 1 + .endm + + .data +clean_addr: .word CLEAN_ADDR + +#else + +/* + * If cache is write-through, there is no need to clean it. + * Simply invalidating will do. + */ + + .macro clean_d_cache, rd, rs + mcr p15, 0, \rd, c7, c6, 0 + .endm + + /* let's try to skip this needless operations at least within loops */ + .macro clean_d_line, rd + .endm + +#endif + + .text + +/* + * cpu_xscale_data_abort() + * + * obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + * + * r2 = address of aborted instruction + * r3 = cpsr + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + * r4 = corrupted + */ + .align 5 +ENTRY(cpu_xscale_data_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r3, [r2] @ read aborted instruction + bic r1, r1, #1 << 11 @ clear bits 11 and 10 of FSR + tst r3, #1 << 20 @ C = bit 20 + orreq r1, r1, #1 << 11 + mov pc, lr + +/* + * cpu_xscale_check_bugs() + */ +ENTRY(cpu_xscale_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +#ifndef CONFIG_XSCALE_CACHE_ERRATA +/* + * cpu_xscale_proc_init() + * + * Nothing too exciting at the moment + */ +ENTRY(cpu_xscale_proc_init) + mov pc, lr +#else +/* + * We enable the cache here, but we make sure all the status bits for dirty + * lines are cleared as well (see PXA250 erratum #120). + */ +ENTRY(cpu_xscale_proc_init) + @ enable data cache + ldr r0, cr_p + ldmia r0, {r1, r2} + orr r1, r1, #0x4 + orr r2, r2, #0x4 + stmia r0, {r1, r2} + mcr p15, 0, r1, c1, c0, 0 + cpwait r0 + + @ invalidate data cache + mcr p15, 0, r0, c7, c6, 0 + + @ fill main cache with write-through lines + bic r0, pc, #0x1f + add r1, r0, #CACHESIZE +1: ldr r2, [r0], #32 + cmp r0, r1 + bne 1b + + @ enable test feature to force all fills to the mini-cache + mov r1, #0x8 + mcr p15, 0, r1, c15, c15, 3 + + @ fill mini-cache with write-through lines (2kbytes, 64 lines) + add r1, r0, #2048 +2: ldr r2, [r0], #32 + cmp r0, r1 + bne 2b + + @ disable test feature to force all fills to the mini-cache + mov r1, #0x0 + mcr p15, 0, r1, c15, c15, 3 + + @ invalidate data cache again + mcr p15, 0, r1, c7, c6, 0 + mov pc, lr + +cr_p: .long SYMBOL_NAME(cr_alignment) +#endif + +/* + * cpu_xscale_proc_fin() + */ +ENTRY(cpu_xscale_proc_fin) + str lr, [sp, #-4]! + mov r0, #F_BIT|I_BIT|SVC_MODE + msr cpsr_c, r0 + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1800 @ ...IZ........... + bic r0, r0, #0x0006 @ .............CA. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + bl cpu_xscale_cache_clean_invalidate_all @ clean caches + ldr pc, [sp], #4 + +/* + * cpu_xscale_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_xscale_reset) + mov r1, #F_BIT|I_BIT|SVC_MODE + msr cpsr_c, r1 @ reset CPSR + mrc p15, 0, r1, c1, c0, 0 @ ctrl register + bic r1, r1, #0x0086 @ ........B....CA. + bic r1, r1, #0x3900 @ ...IZ..S........ + mcr p15, 0, r1, c1, c0, 0 @ ctrl register + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB + bic r1, r1, #0x0001 @ ...............M + mcr p15, 0, r1, c1, c0, 0 @ ctrl register + @ CAUTION: MMU turned off from this point. We count on the pipeline + @ already containing those two last instructions to survive. + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, r0 + +/* + * cpu_xscale_do_idle(type) + * + * Cause the processor to idle + * + * type: + * 0 = slow idle + * 1 = fast idle + * 2 = switch to slow processor clock + * 3 = switch to fast processor clock + * + * For now we do nothing but go to idle mode for every case + * + * XScale supports clock switching, but using idle mode support + * allows external hardware to react to system state changes. + */ + .align 5 + +ENTRY(cpu_xscale_do_idle) + mov r0, #1 + mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE + mov pc, lr + +/* ================================= CACHE ================================ */ + +/* + * cpu_xscale_cache_clean_invalidate_all (void) + * + * clean and invalidate all cache lines + * + * Note: + * 1. We should preserve r0 at all times. + * 2. Even if this function implies cache "invalidation" by its name, + * we don't need to actually use explicit invalidation operations + * since the goal is to discard all valid references from the cache + * and the cleaning of it already has that effect. + * 3. Because of 2 above and the fact that kernel space memory is always + * coherent across task switches there is no need to worry about + * inconsistencies due to interrupts, ence no irq disabling. + */ + .align 5 +ENTRY(cpu_xscale_cache_clean_invalidate_all) + mov r2, #1 +cpu_xscale_cache_clean_invalidate_all_r2: + clean_d_cache r0, r1 + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_xscale_cache_clean_invalidate_range) + bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bhi cpu_xscale_cache_clean_invalidate_all_r2 +1: clean_d_line r0 @ Clean D cache line + mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + teq r2, #0 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + moveq pc, lr + sub r0, r0, r3 +1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB + mov pc, lr + +/* + * cpu_xscale_flush_ram_page(page) + * + * clean all cache lines associated with this memory page + * + * page: page to clean + */ + .align 5 +ENTRY(cpu_xscale_flush_ram_page) +#if !CACHE_WRITE_THROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #2 * CACHELINESIZE + bne 1b +#endif + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_xscale_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that on XScale we must clean all + * entries also due to hardware errata (80200 A0 & A1 only). + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_xscale_dcache_invalidate_range) + mrc p15, 0, r2, c0, c0, 0 @ Read part no. + eor r2, r2, #0x69000000 + eor r2, r2, #0x00052000 @ 80200 XX part no. + bics r2, r2, #0x1 @ Clear LSB in revision field + moveq r2, #0 + beq cpu_xscale_cache_clean_invalidate_range @ An 80200 A0 or A1 + + tst r0, #CACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ Clean D cache line + tst r1, #CACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ Clean D cache line + bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line +1: mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mov pc, lr + +/* + * cpu_xscale_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_range) +#if !CACHE_WRITE_THROUGH + bic r0, r0, #CACHELINESIZE - 1 + sub r2, r1, r0 + cmp r2, #MAX_AREA_SIZE + movhi r2, #0 + bhi cpu_xscale_cache_clean_invalidate_all_r2 + +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b +#endif + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_clean_dcache_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * Note: + * 1. we don't need to flush the write buffer in this case. [really? -Nico] + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_page) +#if !CACHE_WRITE_THROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #4 * CACHELINESIZE + bne 1b +#endif + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_entry) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_xscale_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + * + * Note1: This is vaguely defined as supposed to bring the dcache and the + * icache in sync by the way this function is used. + * + * Note2: single I-cache line invalidation isn't used here since + * it also trashes the mini I-cache used by JTAG debuggers. + */ + .align 5 +ENTRY(cpu_xscale_icache_invalidate_range) + bic r0, r0, #CACHELINESIZE - 1 +1: clean_d_line r0 @ Clean D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_icache_invalidate_page(page) + * + * invalidate all Icache lines associated with this area of memory + * + * page: page to invalidate + */ + .align 5 +ENTRY(cpu_xscale_icache_invalidate_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #4 * CACHELINESIZE + bne 1b + mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB + mov pc, lr + +/* ================================ CACHE LOCKING============================ + * + * The XScale MicroArchitecture implements support for locking entries into + * the data and instruction cache. The following functions implement the core + * low level instructions needed to accomplish the locking. The developer's + * manual states that the code that performs the locking must be in non-cached + * memory. To accomplish this, the code in xscale-cache-lock.c copies the + * following functions from the cache into a non-cached memory region that + * is allocated through consistent_alloc(). + * + */ + .align 5 +/* + * xscale_icache_lock + * + * r0: starting address to lock + * r1: end address to lock + */ +ENTRY(xscale_icache_lock) + +iLockLoop: + bic r0, r0, #CACHELINESIZE - 1 + mcr p15, 0, r0, c9, c1, 0 @ lock into cache + cmp r0, r1 @ are we done? + add r0, r0, #CACHELINESIZE @ advance to next cache line + bls iLockLoop + mov pc, lr + +/* + * xscale_icache_unlock + */ +ENTRY(xscale_icache_unlock) + mcr p15, 0, r0, c9, c1, 1 @ Unlock icache + mov pc, lr + +/* + * xscale_dcache_lock + * + * r0: starting address to lock + * r1: end address to lock + */ +ENTRY(xscale_dcache_lock) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov r2, #1 + mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode + cpwait ip @ Wait for completion + + mrs r2, cpsr + orr r3, r2, #F_BIT | I_BIT +dLockLoop: + msr cpsr_c, r3 + mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty + mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line + msr cpsr_c, r2 + ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from + @ location [r0]. Post-increment + @ r3 to next cache line + cmp r0, r1 @ Are we done? + bls dLockLoop + + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov r2, #0 + mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode + cpwait_ret lr, ip + +/* + * xscale_dcache_unlock + */ +ENTRY(xscale_dcache_unlock) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c9, c2, 1 @ Unlock cache + mov pc, lr + +/* + * Needed to determine the length of the code that needs to be copied. + */ + .align 5 +ENTRY(xscale_cache_dummy) + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_xscale_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_all) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + cpwait_ret lr, ip + +/* + * cpu_xscale_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_range) + bic r0, r0, #(PAGESIZE - 1) & 0x00ff + bic r0, r0, #(PAGESIZE - 1) & 0xff00 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blo 1b + cpwait_ret lr, ip + +/* + * cpu_xscale_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_page) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry + cpwait_ret lr, ip + +/* ================================ TLB LOCKING============================== + * + * The XScale MicroArchitecture implements support for locking entries into + * the Instruction and Data TLBs. The following functions provide the + * low level support for supporting these under Linux. xscale-lock.c + * implements some higher level management code. Most of the following + * is taken straight out of the Developer's Manual. + */ + +/* + * Lock I-TLB entry + * + * r0: Virtual address to translate and lock + */ + .align 5 +ENTRY(xscale_itlb_lock) + mrs r2, cpsr + orr r3, r2, #F_BIT | I_BIT + msr cpsr_c, r3 @ Disable interrupts + mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry + mcr p15, 0, r0, c10, c4, 0 @ Translate and lock + msr cpsr_c, r2 @ Restore interrupts + cpwait_ret lr, ip + +/* + * Lock D-TLB entry + * + * r0: Virtual address to translate and lock + */ + .align 5 +ENTRY(xscale_dtlb_lock) + mrs r2, cpsr + orr r3, r2, #F_BIT | I_BIT + msr cpsr_c, r3 @ Disable interrupts + mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry + mcr p15, 0, r0, c10, c8, 0 @ Translate and lock + msr cpsr_c, r2 @ Restore interrupts + cpwait_ret lr, ip + +/* + * Unlock all I-TLB entries + */ + .align 5 +ENTRY(xscale_itlb_unlock) + mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB + mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB + cpwait_ret lr, ip + +/* + * Unlock all D-TLB entries + */ +ENTRY(xscale_dtlb_unlock) + mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL + mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB + cpwait_ret lr, ip + +/* =============================== PageTable ============================== */ + +/* + * cpu_xscale_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_xscale_set_pgd) + clean_d_cache r1, r2 + mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + cpwait_ret lr, ip + +/* + * cpu_xscale_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_xscale_set_pmd) +#if PMD_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH + and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + orreq r1, r1, #PMD_SECT_TEX(1) +#elif CACHE_WRITE_THROUGH + and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + biceq r1, r1, #PMD_SECT_BUFFERABLE +#endif +#if defined(CONFIG_ARCH_IXDP2400) || defined(CONFIG_ARCH_IXDP2401) + tst r1, #PMD_SECT_TEX(1) + andeq r2, r1, #PMD_TYPE_MASK | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE + cmpeq r2, #PMD_TYPE_SECT + orreq r1, r1, #PMD_SECT_TEX(1) + orreq r1, r1, #PMD_SECT_BUFFERABLE +#endif + + str r1, [r0] + mov ip, #0 + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_set_pte(ptep, pte) + * + * Set a PTE and flush it out + * + * Errata 40: must set memory to write-through for user read-only pages. + */ + .align 5 +ENTRY(cpu_xscale_set_pte) + str r1, [r0], #-1024 @ linux version + + bic r2, r1, #0xff0 + orr r2, r2, #PTE_TYPE_EXT @ extended page + + eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY + + tst r3, #L_PTE_USER | L_PTE_EXEC @ User or Exec? + orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w + + tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? + orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w + @ combined with user -> user r/w + + @ + @ Handle the X bit. We want to set this bit for the minicache + @ (U = E = B = W = 0, C = 1) or when write allocate is enabled, + @ and we have a writeable, cacheable region. If we ignore the + @ U and E bits, we can allow user space to use the minicache as + @ well. + @ + @ X = C & ~W & ~B + @ | C & W & B & write_allocate + @ + eor ip, r1, #L_PTE_CACHEABLE + tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE +#if PTE_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH + eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE + tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE +#endif + orreq r2, r2, #PTE_EXT_TEX(1) + +#if CACHE_WRITE_THROUGH + bic r2, r2, #L_PTE_BUFFERABLE +#else + @ + @ Errata 40: The B bit must be cleared for a user read-only + @ cacheable page. + @ + @ B = B & ~((U|E) & C & ~W) + @ + and ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE + teq ip, #L_PTE_USER | L_PTE_CACHEABLE + teqne ip, #L_PTE_EXEC | L_PTE_CACHEABLE + teqne ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE + biceq r2, r2, #PTE_BUFFERABLE +#endif + +#if defined(CONFIG_ARCH_IXDP2400) || defined(CONFIG_ARCH_IXDP2401) + and ip, r2, #PTE_TYPE_MASK | PTE_EXT_TEX(1) | L_PTE_CACHEABLE | L_PTE_BUFFERABLE + cmp ip, #PTE_TYPE_EXT + orreq r2, r2, #PTE_EXT_TEX(1) | L_PTE_BUFFERABLE +#endif + + tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? + movne r2, #0 @ no -> fault + + str r2, [r0] @ hardware version + + @ We try to map 64K page entries when possible. + @ We do that for kernel space only since the usage pattern from + @ the setting of VM area is quite simple. User space is not worth + @ the implied complexity because of ever randomly changing PTEs + @ (page aging, swapout, etc) requiring constant coherency checks. + @ Since PTEs are usually set in increasing order, we test the + @ possibility for a large page only when given the last PTE of a + @ 64K boundary. + tsteq r1, #L_PTE_USER + andeq r1, r0, #(15 << 2) + teqeq r1, #(15 << 2) + beq 1f + + mov r0, r0 + mov ip, #0 + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + + @ See if we have 16 identical PTEs but with consecutive base addresses + 1: bic r3, r2, #0x0000f000 + mov r1, #0x0000f000 + 2: eor r2, r2, r3 + teq r2, r1 + bne 4f + subs r1, r1, #0x00001000 + ldr r2, [r0, #-4]! + bne 2b + eors r2, r2, r3 + bne 4f + + @ Now create our LARGE PTE from the current EXT one. + bic r3, r3, #PTE_TYPE_MASK + orr r3, r3, #PTE_TYPE_LARGE + and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0 + orr r2, r2, r2, lsl #2 @ add LARGE_AP1 + orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2 + and r1, r3, #0x3c0 @ EXT_TEX + bic r3, r3, #0x3c0 + orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX + orr r2, r2, r3 @ add remaining bits + + @ then put it in the pagetable + mov r3, r2 + 3: strd r2, [r0], #8 + tst r0, #(15 << 2) + bne 3b + + @ Then sync the 2 corresponding cache lines + sub r0, r0, #(16 << 2) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + 4: orr r0, r0, #(15 << 2) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mov ip, #0 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + + .ltorg + +cpu_manu_name: + .asciz "Intel" + +cpu_80200_name: + .asciz "XScale-80200" + +cpu_80321_name: + .asciz "XScale-IOP80321" + +cpu_pxa250_name: + .asciz "XScale-PXA250" + +cpu_ixp425_name: + .asciz "XScale-IXP4xx/IXC11xx" + +cpu_ixp2400_name: + .asciz "XScale-IXP2400" + +cpu_ixp2800_name: + .asciz "XScale-IXP2800" + + .align + + .section ".text.init", #alloc, #execinstr + +__xscale_setup: + mov r0, #F_BIT|I_BIT|SVC_MODE + msr cpsr_c, r0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs + mcr p15, 0, r4, c2, c0, 0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0, 0 @ load domain access register + mov r0, #1 @ Allow access to CP0 + orr r0, r0, #1 << 13 @ and CP13 + orr r0, r0, #1 << 6 @ cp6 for IOP3xx + mcr p15, 0, r0, c15, c1, 0 +#if CACHE_WRITE_THROUGH + mov r0, #0x20 +#else + mov r0, #0x00 +#endif + mcr p15, 0, r0, c1, c1, 0 @ set auxiliary control reg + mrc p15, 0, r0, c1, c0, 0 @ get control register + bic r0, r0, #0x0200 @ ......R......... + bic r0, r0, #0x0002 @ ..............A. + orr r0, r0, #0x0005 @ .............C.M + orr r0, r0, #0x3900 @ ..VIZ..S........ +#ifdef CONFIG_XSCALE_CACHE_ERRATA + bic r0, r0, #0x0004 @ see cpu_xscale_proc_init +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + + .type xscale_processor_functions, #object +ENTRY(xscale_processor_functions) + .word cpu_xscale_data_abort + .word cpu_xscale_check_bugs + .word cpu_xscale_proc_init + .word cpu_xscale_proc_fin + .word cpu_xscale_reset + .word cpu_xscale_do_idle + + /* cache */ + .word cpu_xscale_cache_clean_invalidate_all + .word cpu_xscale_cache_clean_invalidate_range + .word cpu_xscale_flush_ram_page + + /* dcache */ + .word cpu_xscale_dcache_invalidate_range + .word cpu_xscale_dcache_clean_range + .word cpu_xscale_dcache_clean_page + .word cpu_xscale_dcache_clean_entry + + /* icache */ + .word cpu_xscale_icache_invalidate_range + .word cpu_xscale_icache_invalidate_page + + /* tlb */ + .word cpu_xscale_tlb_invalidate_all + .word cpu_xscale_tlb_invalidate_range + .word cpu_xscale_tlb_invalidate_page + + /* pgtable */ + .word cpu_xscale_set_pgd + .word cpu_xscale_set_pmd + .word cpu_xscale_set_pte + .size xscale_processor_functions, . - xscale_processor_functions + + .type cpu_80200_info, #object +cpu_80200_info: + .long cpu_manu_name + .long cpu_80200_name + .size cpu_80200_info, . - cpu_80200_info + + .type cpu_80321_info, #object +cpu_80321_info: + .long cpu_manu_name + .long cpu_80321_name + .size cpu_80321_info, . - cpu_80321_info + + .type cpu_pxa250_info, #object +cpu_pxa250_info: + .long cpu_manu_name + .long cpu_pxa250_name + .size cpu_pxa250_info, . - cpu_pxa250_info + +cpu_ixp425_info: + .long cpu_manu_name + .long cpu_ixp425_name + .size cpu_ixp425_info, . - cpu_ixp425_info + + .type cpu_ixp2400_info, #object +cpu_ixp2400_info: + .long cpu_manu_name + .long cpu_ixp2400_name + .size cpu_ixp2400_info, . - cpu_ixp2400_info + + .type cpu_ixp2800_info, #object +cpu_ixp2800_info: + .long cpu_manu_name + .long cpu_ixp2800_name + .size cpu_ixp2800_info, . - cpu_ixp2800_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __80200_proc_info,#object +__80200_proc_info: + .long 0x69052000 + .long 0xffffe3f0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_80200_info + .long xscale_processor_functions + .size __80200_proc_info, . - __80200_proc_info + + .type __80321_proc_info,#object +__80321_proc_info: + .long 0x69052420 + .long 0xfffff7e0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_80321_info + .long xscale_processor_functions + .size __80321_proc_info, . - __80321_proc_info + + .type __pxa250_proc_info,#object +__pxa250_proc_info: + .long 0x69052100 + .long 0xfffff7f0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa250_info + .long xscale_processor_functions + .size __pxa250_proc_info, . - __pxa250_proc_info + + .type __ixp425_proc_info, #object +__ixp425_proc_info: +#if 0 + .long 0x69054000 + .long 0xfffffe00 +#endif + .long 0x690541c0 + .long 0xffffffc0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp425_info + .long xscale_processor_functions + .size __ixp425_proc_info, . - __ixp425_proc_info + + .type __ixp2400_proc_info,#object +__ixp2400_proc_info: + .long 0x69054190 + .long 0xfffffff0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2400_info + .long xscale_processor_functions + .size __ixp2400_proc_info, . - __ixp2400_proc_info +# + .type __ixp2800_proc_info,#object +__ixp2800_proc_info: + .long 0x690541a0 + .long 0xfffffff0 +#if CACHE_WRITE_THROUGH + .long 0x00000c0a +#else + .long 0x00000c0e +#endif + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp2800_info + .long xscale_processor_functions + .size __ixp2800_proc_info, . - __ixp2800_proc_info + diff -Nru a/arch/arm/mm/xscale-lock.c b/arch/arm/mm/xscale-lock.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mm/xscale-lock.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,472 @@ +/* + * xscale-lock.c + * + * This file implements the APIs that can be used by kernel developers + * to lock entries into the caches and TLBs on processors based on + * Intel's XScale * Microarchitecture. For information on using the APIs see + * Documentation/arm/XScale/cache-lock.txt and tlb_lock.txt. + * + * Author: Deepak Saxena + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 SOFTWARE IS PROVIDED ``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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern void* consistent_alloc(int, size_t, dma_addr_t); + +#undef DEBUG +#ifdef DEBUG +#define DBG_LEVEL 3 +#define DBG(n, args...) do { if (DBG_LEVEL>=(n)) printk(args); } while (0) +#else +#define DBG(n, args...) do { } while (0) +#endif + +/* + * Future XScale cores may have different cache sizes + */ +#define CACHE_SIZE 32 +#define CACHE_LOCK 28 +#define CACHE_LINES CACHE_LOCK * 1024 / L1_CACHE_BYTES + +#define TLB_ENTRIES 28 + + +/* + * Cache Locking Implementation + */ + +static dma_addr_t dma_handle; +static void *low_level_page = NULL; + +/* + * Internal structure used to track cache usage + */ +struct cache_entry +{ + void *addr; + int lines; + struct cache_entry *next; + struct cache_entry *prev; +}; + +static struct cache_capabilities cache = +{ + CACHE_LOCKABLE, + CACHE_SIZE, + CACHE_LOCK +}; + +static int cache_lock_init(void); + +static int cache_lines[2] = { CACHE_LINES, CACHE_LINES }; +static struct cache_entry *cache_data[2] = {NULL, NULL}; + +static int alloc_cache_entry(void *, int, u8); +static struct cache_entry* unlink_cache_entry(void *, u8); + +extern int xscale_icache_lock(void*, int); +extern int xscale_dcache_lock(void*, int); +extern int xscale_icache_unlock(void); +extern int xscale_dcache_unlock(void); +extern void xscale_cache_dummy(void); + +typedef int (*cache_lock_fn)(void *, int); +typedef int (*cache_unlock_fn)(void); + +static cache_lock_fn icache_lock_fn; +static cache_lock_fn dcache_lock_fn; +static cache_unlock_fn icache_unlock_fn; +static cache_unlock_fn dcache_unlock_fn; + +static cache_lock_fn lock_fns[2]; +static cache_unlock_fn unlock_fns[2]; + +/* + * Cache Lock API functions + */ + +int cache_query_capabilities(u8 cache_type, struct cache_capabilities *pcap) +{ + if(!pcap) + return -EINVAL; + + /* + * Both caches are same on current xscale + */ + memcpy(pcap, &cache, sizeof(struct cache_capabilities)); + + return 0; +} + +int cache_lock(void *addr, u32 len, u8 cache_type, const char *desc) +{ + u32 address = (u32)addr; + + DBG(1, "cache_lock entered\n"); + DBG(2, " Addr: %#10x\n", (u32)addr); + DBG(2, " Type: %s\n", cache_type == ICACHE ? "ICACHE" : "DCACHE"); + DBG(2, " Len: %#6x\n", len); + + + if(address & (L1_CACHE_BYTES - 1)) { + DBG(1, " Non-aligned lock request: %p\n", addr); + return -EINVAL; + } + + DBG(1, " calling alloc_cache_entry\n"); + return alloc_cache_entry(addr, len, cache_type); +} + +int cache_unlock(void *addr) +{ + struct cache_entry *entry; + u8 cache_type; + + DBG(1, "cache_unlock entered\n"); + + if((entry = unlink_cache_entry(addr, ICACHE))) + cache_type = ICACHE; + else if((entry = unlink_cache_entry(addr, DCACHE))) + cache_type = DCACHE; + else + { + DBG(1, " No entry!\n"); + return -ENOENT; + } + + DBG(2, " Addr: %#10x\n", (u32)addr); + DBG(2, " Type: %s\n", cache_type == ICACHE ? "ICACHE" : "DCACHE"); + DBG(2, " Len: %#6x\n", entry->lines); + + cache_lines[cache_type] += entry->lines; + kfree(entry); + + /* + * Unlock + * Invalidate + * Relock + */ + DBG(2, " Calling unlock_fn\n"); + unlock_fns[cache_type](); + DBG(2, " unlock_fn returned\n"); + cpu_cache_clean_invalidate_all(); + + + for(entry = cache_data[cache_type]; entry; entry = entry->next) + { + DBG(2, " Invalidating DCACHE\n"); + cpu_cache_clean_invalidate_all(); + DBG(2, " Cleaning DCACHE\n"); + + DBG(2, " Calling lock_fn\n"); + lock_fns[cache_type](entry->addr, + (u32)(entry->addr + entry->lines * L1_CACHE_BYTES)); + DBG(2, " lock_fn returned\n"); + } + + DBG(1, " cache_unlock exit\n"); + return 0; +} + +/* + * Cache Lock internals + */ + +static struct cache_entry* unlink_cache_entry(void *addr, u8 cache_type) +{ + struct cache_entry *p; + + p = cache_data[cache_type]; + + if(!p) return NULL; + + if(p->addr == addr) + { + cache_data[cache_type] = p->next; + if(p->next) + p->next->prev = NULL; + return p; + } + + for(p = cache_data[cache_type]; p; p = p->next) + { + if(p->addr == addr) + { + if(p->prev) + p->prev->next = p->next; + if(p->next) + p->next->prev = p->prev; + break; + } + } + + return p; +} + + +static int alloc_cache_entry(void *addr, int len, u8 cache_type) +{ + struct cache_entry *new = NULL; + u32 end = L1_CACHE_ALIGN((u32)addr + len); + int lines = 0; + + DBG(2, " addr: %#10x\n", (u32)addr); + DBG(2, " len: %#6x\n", len); + DBG(2, " type: %s\n", cache_type == ICACHE ? "ICACHE" : "DCACHE"); + + new = kmalloc(sizeof(struct cache_entry), GFP_ATOMIC); + DBG(1, "alloc_cache_entry entered\n"); + if(!new) + { + DBG(2, " Could not allocate cache_entry\n"); + return -ENOMEM; + } + + lines = ((u32)end - (u32)addr) / L1_CACHE_BYTES; + if(lines > cache_lines[cache_type]) + { + DBG(2, " No space left in cache\n"); + return -ENOSPC; + } + + new->addr = addr; + new->lines = lines; + new->next = NULL; + new->prev = NULL; + + if(cache_data[cache_type] == NULL) + { + cache_data[cache_type] = new; + } + else + { + new->next = cache_data[cache_type]; + cache_data[cache_type]->prev = new; + new->prev = NULL; + cache_data[cache_type] = new; + } + + cache_lines[cache_type] -= lines; + + DBG(2, " Invalidating/cleaning caches\n"); + cpu_cache_clean_invalidate_all(); + DBG(2, " Invalidate/clean complete\n"); + + DBG(2, " Calling lock_fn @ %#10x\n", (u32)lock_fns[cache_type]); + DBG(3, " start: %#10x end: %#10x\n", (u32)addr, (u32)end); + lock_fns[cache_type](addr, end); + DBG(2, " lock_fn returned\n"); + DBG(1, "alloc_cache_entry exit\n"); + + return 0; +} + + +/* + * This function basically sets up the cache locking code so + * it meets the requirements in section 4.3.4 of the 80200 + * manual. + * + * 1) The routine used to lock cache can't be cacheble + * 2) Code used to do locking not reside closer than 128 bytes + * to a cache/non-cache boundary. + * + * Since the compiler has no understanding of such things, we + * allocate uncacheble memory by calling consistent_alloc and + * copy the relavent low level code to the new memory and than + * create pointers into this memory. Ick. + * + */ +static int __init cache_lock_init(void) +{ + u32 len; + + DBG(1, "XScale cache_lock_init called\n"); + len = (u32)xscale_cache_dummy - (u32)xscale_icache_lock + 256; + + /* + * This is an ugly way to get a non-cached page + */ + DBG(1, " Calling consistent alloc\n"); + low_level_page = consistent_alloc(GFP_KERNEL, len, (u32)&dma_handle); + DBG(1, " low_level_page initialized\n"); + + if(!low_level_page) + { + printk(KERN_ERR + " Could not allocate memory for cache locking\n"); + printk(KERN_ERR " Cache locking disabled\n"); + + return -1; + } + + memcpy(low_level_page + 128, xscale_icache_lock, len - 256); + + DBG(1, " low_level_page @ %#10x\n", (u32)low_level_page); + icache_lock_fn = (cache_lock_fn)(low_level_page + 128); + dcache_lock_fn = + (cache_lock_fn)(low_level_page + 128 + + ((u32)xscale_dcache_lock - (u32)xscale_icache_lock)); + + DBG(1, " icache_lock_fn @ %#10x\n", (u32)icache_lock_fn); + DBG(1, " dcache_lock_fn @ %#10x\n", (u32)dcache_lock_fn); + lock_fns[ICACHE] = icache_lock_fn; + lock_fns[DCACHE] = dcache_lock_fn; + + icache_unlock_fn = (cache_unlock_fn)(low_level_page + 128 + + ((u32)xscale_icache_unlock - (u32)xscale_icache_lock)); + dcache_unlock_fn = (cache_unlock_fn)(low_level_page + 128 + + ((u32)xscale_dcache_unlock - (u32)xscale_icache_lock)); + + DBG(1, " icache_unlock_fn @ %#10x\n", (u32)icache_unlock_fn); + DBG(1, " dcache_unlock_fn @ %#10x\n", (u32)dcache_unlock_fn); + unlock_fns[ICACHE] = icache_unlock_fn; + unlock_fns[DCACHE] = dcache_unlock_fn; + + return 0; +} + + +/* + * TLB Locking Implementation + */ + +static u32 tlb_entries[TLB_ENTRIES][TLB_ENTRIES]; +static u32 tlb_count[2] = {TLB_ENTRIES, TLB_ENTRIES}; + +extern void xscale_itlb_lock(u32); +extern void xscale_dtlb_lock(u32); + +extern void xscale_itlb_unlock(void); +extern void xscale_dtlb_unlock(void); + +typedef void (*tlb_lock)(u32); +typedef void (*tlb_unlock)(void); + +static tlb_lock tlb_lock_fn[2] = + {xscale_itlb_lock, xscale_dtlb_lock}; + +static tlb_unlock tlb_unlock_fn[2] = + {xscale_itlb_unlock, xscale_dtlb_unlock}; + +int xscale_tlb_lock(u8 tlb_type, u32 addr) +{ + int i = 0; + + if(tlb_type != ITLB && tlb_type != DTLB) + return -EIO; + + if(!tlb_count[tlb_type]) + return -ENOSPC; + + if(addr & 0xff) + return -EINVAL; + + tlb_lock_fn[tlb_type](addr); + + for(i = 0; i < TLB_ENTRIES; i++) + { + if(tlb_entries[tlb_type][i] == 0xDEADBEEF) + { + tlb_entries[tlb_type][i] = addr; + break; + } + } + + tlb_count[tlb_type]--; + + return 0; +} + +int xscale_tlb_unlock(u8 tlb_type, u32 addr) +{ + int i = 0; + + if(tlb_type != ITLB && tlb_type != DTLB) + return -EIO; + + for(i = 0; i < TLB_ENTRIES; i++) + { + if(tlb_entries[tlb_type][i] == addr) + { + tlb_entries[tlb_type][i] = 0xDEADBEEF; + break; + } + } + + if(i == TLB_ENTRIES) + return -ENOENT; + + /* + * There's no unlock 1 entry command on XScale. So we unlock + * the whole tlb and than lock each entry in again. + */ + tlb_unlock_fn[tlb_type](); + + for(i = 0; i < TLB_ENTRIES; i++) + { + if(tlb_entries[tlb_type][i] != 0xDEADBEEF) + tlb_lock_fn[tlb_type](addr); + } + + return 0; +} + + +static void __init tlb_lock_init(void) +{ + int i = 0; + + DBG(1, "Initializing TLB locking\n"); + for(i = 0; i < TLB_ENTRIES; i++) + tlb_entries[ITLB][i] = tlb_entries[DTLB][i] = 0xDEADBEEF; + DBG(1, "TLB locking initialized\n"); +} + + +/* + * Initialization code + */ +void __init xscale_locking_init(void) +{ + printk(KERN_INFO "XScale Cache/TLB Locking Copyright(c) 2001 MontaVista Software, Inc.\n"); + + if(cache_lock_init()) + return; + + tlb_lock_init(); +} diff -Nru a/arch/arm/tools/getconstants.c b/arch/arm/tools/getconstants.c --- a/arch/arm/tools/getconstants.c Thu Dec 4 16:24:25 2003 +++ b/arch/arm/tools/getconstants.c Thu Dec 4 16:24:25 2003 @@ -25,6 +25,7 @@ #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) +#define BOFF_TSK(n) ((unsigned long)&(((struct task_struct *)0)->n))+1 #define DEFN(name,off) asm("\n#define "name" %0" :: "I" (off)) @@ -34,6 +35,7 @@ DEFN("TSK_ADDR_LIMIT", OFF_TSK(addr_limit)); DEFN("TSK_NEED_RESCHED", OFF_TSK(need_resched)); DEFN("TSK_PTRACE", OFF_TSK(ptrace)); + DEFN("TSK_USED_MATH", OFF_TSK(used_math)); DEFN("TSS_SAVE", OFF_TSK(thread.save)); diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types --- a/arch/arm/tools/mach-types Thu Dec 4 16:24:25 2003 +++ b/arch/arm/tools/mach-types Thu Dec 4 16:24:25 2003 @@ -250,8 +250,8 @@ pdb ARCH_PDB PDB 239 blue_2g SA1100_BLUE_2G BLUE_2G 240 bluearch SA1100_BLUEARCH BLUEARCH 241 -ixdp2400 ARCH_IXMB2400 IXMB2400 242 -ixdp2800 ARCH_IXMB2800 IXMB2800 243 +ixdp2400 ARCH_IXDP2400 IXDP2400 242 +ixdp2800 ARCH_IXDP2800 IXDP2800 243 explorer SA1100_EXPLORER EXPLORER 244 ixdp425 ARCH_IXDP425 IXDP425 245 chimp ARCH_CHIMP CHIMP 246 diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in --- a/drivers/char/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/char/Config.in Thu Dec 4 16:24:25 2003 @@ -160,10 +160,16 @@ bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE fi +tristate 'Support for IXP2000 as PCI slave' CONFIG_IXP2000_SLAVE + source drivers/i2c/Config.in if [ "$CONFIG_I2C" != "n" ]; then dep_tristate ' DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C + dep_tristate ' PCF8549C-2 I2C based /dev/nvram support' CONFIG_PCF8549C_NVRAM $CONFIG_I2C + if [ "$CONFIG_ARCH_IQ31244" = "y" ]; then + dep_tristate ' ST M41ST85W Real Time Clock' CONFIG_M41ST85W $CONFIG_I2C + fi fi source drivers/l3/Config.in diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/char/Makefile Thu Dec 4 16:24:25 2003 @@ -24,7 +24,8 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ - au1000_gpio.o hp_psaux.o nvram.o scx200.o + au1000_gpio.o hp_psaux.o nvram.o scx200.o \ + pcf8594c-nvram.o ixp2000.o mod-subdirs := joystick ftape drm drm-4.0 pcmcia @@ -267,9 +268,11 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o +obj-$(CONFIG_M41ST85W) += m41st85w.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif +obj-$(CONFIG_PCF8549C_NVRAM) += pcf8594c-nvram.o obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o @@ -331,6 +334,7 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_OMAHA_WATCHDOG) += omaha_wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_IXP2000_SLAVE) += ixp2000.o obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o # I2C char devices @@ -340,6 +344,8 @@ ifeq ($(CONFIG_MWAVE),y) obj-y += mwave/mwave.o endif + +obj-$(CONFIG_IXP2000_SLAVE) += ixp2000.o ifeq ($(CONFIG_ARCH_ACORN),y) mod-subdirs += ../acorn/char diff -Nru a/drivers/char/ixp2000.c b/drivers/char/ixp2000.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/ixp2000.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,564 @@ +/* + * drivers/char/ixp2000.c + * + * Author: Naeem Afzal + * Copyright: (C) 2002 Intel Corp. + * Copyright (C), 2003 MontaVista Software, Inc. + * + * Maintained by: Deepak Saxena + * + * 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. + * + * Slave IXP2000 NPU driver, Configure PCI interface to download images + * over PCI BUS + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "ixp2000.h" + +// #define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + +/* + * If the master CPU is an IXP2000, we need to do our "special" + * ioremap which fiddles with the PCI address extension. + * This is a requirement for the IXASDK. sigh... + */ +#ifdef CONFIG_ARCH_IXP2000 + + +#define PHY_PCI_MEM 0xe0000000 +#undef ioremap +#undef iounmap + +unsigned long pci_window_address = 0; + +/* + * ixp_ioremap...just returns the real PCI bus address + */ +static inline u32 ixp_ioremap(unsigned long address, unsigned long size) +{ + /* + * Subtract Linux PCI offset + */ + address -= 0xe0000000; + + return address; +} + +#define ioremap ixp_ioremap +#define iounmap + +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel + +static inline u8 readb(unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + u8 value; + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + value = *(volatile u8*)((u32)pci_window_address + (addr & ~0xe0000000)); + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); + + return value; +} + +static inline u16 readw(unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + u16 value; + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + value = *(volatile u16*)((u32)pci_window_address + (addr & ~0xe0000000)); + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); + + return value; +} + +static inline u32 readl(unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + u32 value; + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + value = *(volatile u32*)((u32)pci_window_address + (addr & ~0xe0000000)); + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); + + return value; +} + + +static inline void writeb(u8 value, unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + volatile u8* tmp = (u8*)((u32)pci_window_address + (addr & ~0xe0000000)); + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + *tmp = value; + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); +} + +static inline void writew(u16 value, unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + volatile u16* tmp = (u16*)((u32)pci_window_address + (addr & ~0xe0000000)); + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + *tmp = value; + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); +} + +static inline void writel(u32 value, unsigned long addr) +{ + unsigned long flags; + unsigned long addr_extension; + volatile u32* tmp = (u32*)((u32)pci_window_address + (addr & ~0xe0000000)); + + local_irq_save(flags); + addr_extension = *IXP2000_PCI_ADDR_EXT; + + *IXP2000_PCI_ADDR_EXT = (addr & 0xe0000000) >> 16; + + *tmp = value; + + *IXP2000_PCI_ADDR_EXT = addr_extension; + + local_irq_restore(flags); +} +#endif + +static int ixp2000_pci_init (struct pci_dev *, const struct pci_device_id *); +static ssize_t ixp2000_read (struct file *,char *, size_t,loff_t *); +static ssize_t ixp2000_write (struct file *,const char *, size_t,loff_t *); +int ixp2000_open (struct inode *, struct file *); +static int ixp2000_release(struct inode *, struct file *); +static loff_t ixp2000_llseek (struct file *, loff_t, int); +static int ixp2000_ioctl(struct inode *, struct file *, unsigned int, unsigned long); + +static int ixp2000_major = 251; +static int num_slave_devices = 0; + +struct ixp_info *ixp_devices; + +static struct file_operations ixp2000_fops = { + //module: THIS_MODULE, + open: ixp2000_open, + write: ixp2000_write, + ioctl: ixp2000_ioctl, + llseek: ixp2000_llseek, + release: ixp2000_release, +}; + +int ixp2000_open (struct inode *inode, struct file *filp) +{ + struct ixp_info *tmp = ixp_devices; + + int num = MINOR(inode->i_rdev); + + /* check the device number */ + if (num >= num_slave_devices) return -ENODEV; + while (num) { + if (tmp->next) + tmp = tmp->next; + else + return -ENODEV; + num--; + } + filp->private_data = tmp; + + MOD_INC_USE_COUNT; + return 0; +} + +static int ixp2000_release(struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} +ssize_t ixp2000_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + //struct ixp_info *ixp = filp->private_data; + return count; + +} +loff_t ixp2000_llseek (struct file *filp, loff_t off, int whence) +{ + long newpos; + struct ixp_info *ixp = filp->private_data; + + switch(whence) { + case 0: /* SEEK_SET */ + newpos = off; + break; + + case 1: /* SEEK_CUR */ + newpos = filp->f_pos + off; + break; + + case 2: /* SEEK_END */ + newpos = ixp->sdram_size + off; + break; + + default: /* can't happen */ + return -EINVAL; + } + if (newpos<0 || (newpos >= ixp->sdram_size)) return -EINVAL; + + filp->f_pos = newpos; + DBG("seek position :0x%x\n",newpos); + + return newpos; +} + +void query_ixp(struct ixp_info *ixp) +{ + /* + * TODO: FIX THIS TO READ FROM DEVICE + */ + + unsigned int ixp_names[] = {2800, 2850, 2400}; + + unsigned long product_id = le32_to_cpu(readl((ixp->csr_ioaddr + 0x04a00))); + + ixp->ixp_type = (product_id >> 8) & 0xff; + ixp->ixp_rev = (product_id >> 4) & 0xf; + ixp->flags = 0x0; + + printk(" IXP%d NPU, revision %d\n", ixp_names[ixp->ixp_type], ixp->ixp_rev); +} + +int ixp2000_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int val; + struct ixp_info *ixp = filp->private_data; + + switch(cmd) { + case IXP_IOC_QUERY_INFO: + if (copy_to_user((void *)arg, ixp, sizeof(struct ixp_info))) { + return -EFAULT; + } + break; + case IXP_IOC_RELEASE_RST: /* Set: arg points to the value */ + DBG("Relesing Slave NPU from RESET... "); + + val = le32_to_cpu(readl(ixp->csr_ioaddr + IXP_RESET0_FRM_PCI)); + val &= ~XSCALE_RESET_BIT; + writel(cpu_to_le32(val),ixp->csr_ioaddr + IXP_RESET0_FRM_PCI); + udelay(1); + + ixp->flags |= IXP_FLAG_NPU_UP; + break; + default: + return -EINVAL; + } + return 0; +} + +static void ixp2000_slave_remove (struct pci_dev *pdev) +{ + pci_disable_device(pdev); +} + +static struct pci_device_id ixp2000_slave_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2000, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; + +static struct pci_driver ixp2000_slave_driver = { + name: "IXP2000 Slave Driver", + id_table: ixp2000_slave_pci_tbl, + probe: ixp2000_pci_init, + remove: ixp2000_slave_remove, +}; + +static int __devinit ixp2000_pci_init (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int val; + struct ixp_info *newnode; + unsigned long flags; + unsigned long strap_options; + + num_slave_devices++; + + if (pci_enable_device(pdev)) + goto err_out_disable; + + if(num_slave_devices == 1) + printk("IXP2000 found at bus:%d slot:%d\n" , + pdev->bus->number, PCI_SLOT(pdev->devfn)); + else + printk("IXP2000 NPU (#%02d) found at bus:%d slot:%d\n" , + num_slave_devices - 1, pdev->bus->number, + PCI_SLOT(pdev->devfn)); + + if (!(newnode = kmalloc(sizeof(struct ixp_info), GFP_KERNEL))) { + printk(KERN_ERR "ixp2400: can't alloc ixp_info.\n"); + return -ENOMEM ; + } + + memset(newnode, 0, sizeof(struct ixp_info)); + + if (num_slave_devices == 1 ) + ixp_devices = newnode; + else { + struct ixp_info *tmp = ixp_devices; + while ( tmp->next) { + tmp = tmp->next; + } + tmp->next = newnode; + } + + newnode->csr_bar = pci_resource_start(pdev, 0); + newnode->sram_bar = pci_resource_start(pdev, 1); + newnode->sdram_bar = pci_resource_start(pdev, 2); + + newnode->sram_size = pci_resource_len(pdev, 1); + newnode->sdram_size = pci_resource_len(pdev, 2); + + strcpy(newnode->name,"IXP2400"); + + newnode->csr_ioaddr = (unsigned long)ioremap(newnode->csr_bar, 0x100000); + +#ifndef CONFIG_ARCH_IXP2000 + if (!newnode->csr_ioaddr) { + printk (KERN_ERR "Cannot ioremap CSR MMIO region %lx @ %lx\n", (unsigned long)0x100000, newnode->csr_bar); + + goto err_out; + } +#endif + + newnode->sram_ioaddr = (unsigned long)ioremap(newnode->sram_bar, newnode->sram_size); +#ifndef CONFIG_ARCH_IXP2000 + if (!newnode->sram_ioaddr) { + printk (KERN_ERR "Cannot remap SRAM MMIO region %lx @ %lx\n", + newnode->sram_size, newnode->sram_bar); + goto err_out_iounmap_csr; + } +#endif + + newnode->sdram_ioaddr = (unsigned long)ioremap(newnode->sdram_bar, newnode->sdram_size); +#ifndef CONFIG_ARCH_IXP2000 + if (!newnode->sdram_ioaddr) { + printk (KERN_ERR "Cannot remap SDRAM MMIO region %lx @ %lx\n", + newnode->sdram_size, newnode->sdram_bar); + goto err_out_iounmap_sram; + } +#endif + + /* populate more ixp_info structure */ + query_ixp(newnode); + + printk(" %#010x bytes SRAM, %#010x bytes SDRAM\n", + (u32)newnode->sram_size, (u32)newnode->sdram_size); + + DBG("IXP2400 ioremaped CSR:%lx len %lx SRAM:%lx len %x SDRAM:%lx len %lx\n" + ,newnode->csr_ioaddr, (int)0x100000 + ,newnode->sram_ioaddr, newnode->sram_size + ,newnode->sdram_ioaddr, newnode->sdram_size); + + strap_options = le32_to_cpu(readl(newnode->csr_ioaddr + STRAP_OPTIONS_FRM_PCI)); + + DBG("STRAP_OPTIONS = %#010x\n", strap_options); + + DBG("Check for Strap options for Flash on Slave NPU\n"); + if (strap_options & CFG_BOOT_ROM){ + newnode->flags &= ~IXP_FLAG_NO_FLASH; + newnode->flags |= IXP_FLAG_NPU_UP; + } else { /* No flash */ + newnode->flags |= IXP_FLAG_NO_FLASH; + + printk(" Device has no bootrom - reseting chip\n"); + + DBG("Reset NPU\n"); + val = le32_to_cpu(readl(newnode->csr_ioaddr + IXP_RESET0_FRM_PCI)); + val |= XSCALE_RESET_BIT; + writel(cpu_to_le32(val),newnode->csr_ioaddr + IXP_RESET0_FRM_PCI); + udelay(100); + + /* disable Flash alias on SDRAM */ + DBG("disable flash alias\n"); + val = le32_to_cpu(readl(newnode->csr_ioaddr + MISC_CONTROL_FRM_PCI)); + writel(cpu_to_le32(val|FLASH_ALIAS_DISABLE),newnode->csr_ioaddr+MISC_CONTROL_FRM_PCI); + udelay(10); + } + + return 0; + +err_out_iounmap_sram: + iounmap ((void *)newnode->sram_ioaddr); +err_out_iounmap_csr: + iounmap ((void *)newnode->csr_ioaddr); + +err_out: + kfree(newnode); +err_out_disable: + pci_disable_device(pdev); + return -ENODEV; +} + +ssize_t ixp2000_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + loff_t off = *f_pos; + unsigned char *tmpwritebuf; + unsigned char *from; + size_t i = count; + struct ixp_info *ixp = filp->private_data; + + off = *f_pos; + + DBG(" ixp2000_write: offset to write to: 0x%x\n",(int)off); + + if (*f_pos > ixp->sdram_size || (*f_pos + count) > ixp->sdram_size) + return -ENOSPC; + + tmpwritebuf = kmalloc(count,GFP_KERNEL); + + if (!tmpwritebuf) { + printk("No Memory available\n"); + return -ENOMEM; + } + + if (copy_from_user (tmpwritebuf, buf, count)) { + kfree(tmpwritebuf); + return -EFAULT; + } + *f_pos += count; + + from = tmpwritebuf; + while (i) { + unsigned long to = ixp->sdram_ioaddr+off; + i--; + writeb(*from, to); + from++; + off++; + } + + kfree(tmpwritebuf); + + return count; + +} + +static int __init ixp2000_slave_module_init(void) +{ + int result = devfs_register_chrdev(ixp2000_major, "ixpctl", &ixp2000_fops); + + if (result < 0) { + printk("ixpctl: unable to get major %d\n", ixp2000_major); + return result; + } + +#ifdef CONFIG_ARCH_IXP2000 + pci_window_address = __ioremap(PHY_PCI_MEM, 0x20000000, 0); + printk("pci_window_address = %#010x\n", pci_window_address); + if(!pci_window_address) { + printk("ixpctl: unable to __ioremap PCI memory region\n"); + devfs_unregister_chrdev(ixp2000_major, "ixpctl"); + return -EIO; + } +#endif + + return pci_module_init(&ixp2000_slave_driver); +} + +static void __exit ixp2000_slave_module_cleanup(void) +{ + devfs_unregister_chrdev(ixp2000_major, "ixpctl"); + + printk("Unregistered device\n"); + +#ifdef CONFIG_ARCH_IXP2000 + __iounmap(pci_window_address); + printk("iounmapped window\n"); +#endif + + pci_unregister_driver(&ixp2000_slave_driver); + + printk("unregistered driver\n"); +} + +module_init(ixp2000_slave_module_init); +module_exit(ixp2000_slave_module_cleanup); + +MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(pci_window_address); + + diff -Nru a/drivers/char/ixp2000.h b/drivers/char/ixp2000.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/ixp2000.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,154 @@ +/* + * inclue/asm-arm/arch-ixp2000/slave.h + * + * Register and other defines for IXMB2400 for slave NPU board + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 _SLAVE_H +#define _SLAVE_H + +#define MISC_CONTROL_OFF 0x04 +#define IXP_RESET0_OFF 0x0C +#define CCR_OFF 0x14 +#define STRAP_OPTIONS_OFF 0x18 + +/* slave's csr as seen from master PCI*/ +#define GLOBAL_CONTROL_BASE_FRM_PCI 0x04A00 +#define IXP_RESET0_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + IXP_RESET0_OFF) +#define CCR_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + CCR_OFF) +#define STRAP_OPTIONS_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + STRAP_OPTIONS_OFF) +#define MISC_CONTROL_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + MISC_CONTROL_OFF) + +#define SLOW_PORT_CSR_BASE_FRM_PCI 0x80000 +#define SCRATCH_BASE_FRM_PCI 0xF0000 + +#define DDR_RX_DLL_VAL 0x11 +#define DDR_RX_DESKEW_VAL 0x11 +#define DDR_RDDLYSEL_RECEN_VAL 0x11 + +#define SRAM_CH1_BASE_FRM_PCI 0xF9800 +#define SRAM_CH0_BASE_FRM_PCI 0xF9C00 +#define SRAM_CH_BASE_FRM_PCI 0xF9000 + +#define DU_CONTROL_OFF 0x0 +#define DU_ECC_TEST_OFF 0x18 +#define DU_INIT_OFF 0x20 +#define DU_CONTROL2_OFF 0x28 +#define DDR_RCOMP_IO_CONFIG_OFF 0x3c0 +#define DDR_RDDLYSEL_RECEN_OFF 0x3c8 +#define DDR_RX_DLL_OFF 0x650 +#define DDR_RX_DESKEW_OFF 0x688 + +#define CR0_FRCSMRCOMP_OFF 0x100 +#define CR0_DSTRENGTHSEL_OFF 0x130 +#define CR0_DDQRCOMP_OFF 0x148 +#define CR0_DCTLRCOMP_OFF 0x190 +#define CR0_DRCVRCOMP_OFF 0x1D8 +#define CR0_DCKERCOMP_OFF 0x228 +#define CR0_DCSRCOMP_OFF 0x2B0 +#define CR0_DCKRCOMP_OFF 0x338 +#define CR0_DX8X16CKECSCKSEL_OFF 0x220 +#define CR0_RCOMPPRD_OFF 0x108 +#define CR0_DIGFIL_OFF 0x118 + +#define CR0_SLEWPROGRAMMED_OFF 0x128 +#define CR0_OVRRIDEH_OFF 0x138 +#define CR0_OVRRIDEV_OFF 0x140 +#define CR0_JT_CONFIG_OFF 0x3C0 + +#define CR0_FRCSMRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_FRCSMRCOMP_OFF) +#define CR0_DSTRENGTHSEL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DSTRENGTHSEL_OFF) +#define CR0_DDQRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DDQRCOMP_OFF) +#define CR0_DCTLRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCTLRCOMP_OFF) +#define CR0_DRCVRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DRCVRCOMP_OFF) +#define CR0_DCKERCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCKERCOMP_OFF) +#define CR0_DCSRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCSRCOMP_OFF) +#define CR0_DCKRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCKRCOMP_OFF) +#define CR0_DX8X16CKECSCKSEL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DX8X16CKECSCKSEL_OFF) +#define CR0_RCOMPPRD_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_RCOMPPRD_OFF) +#define CR0_DIGFIL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DIGFIL_OFF) + +#define CR0_SLEWPROGRAMMED_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_SLEWPROGRAMMED_OFF) +#define CR0_OVRRIDEH_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_OVRRIDEH_OFF) +#define CR0_OVRRIDEV_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_OVRRIDEV_OFF) +#define CR0_JT_CONFIG_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_JT_CONFIG_OFF) + +#define DRAM_CH0_BASE_FRM_PCI 0xFD800 + +#define DU_CONTROL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_CONTROL_OFF) +#define DU_ECC_TEST_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_ECC_TEST_OFF) +#define DU_INIT_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_INIT_OFF) +#define DU_CONTROL2_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_CONTROL2_OFF) +#define DDR_RCOMP_IO_CONFIG_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RCOMP_IO_CONFIG_OFF) +#define DDR_RDDLYSEL_RECEN_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RDDLYSEL_RECEN_OFF) +#define DDR_RX_DLL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RX_DLL_OFF) +#define DDR_RX_DESKEW_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RX_DESKEW_OFF) + +#define PCI_OUT_INT_MASK_OFF 0x34 +#define MAILBOX_1_OFF 0x54 +#define PCI_CONTROL_OFF 0x13C +#define PCI_ADDR_EXT_OFF 0x140 +#define XSCALE_INT_STATUS_OFF 0x158 +#define XSCALE_INT_ENABLE_OFF 0x15C + +#define PCI_CSR_BASE_FRM_PCI 0xFE000 + +#define PCI_OUT_INT_MASK_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_OUT_INT_MASK_OFF) +#define PCI_CONTROL_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_CONTROL_OFF) +#define PCI_ADDR_EXT_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_ADDR_EXT_OFF) + +#define SLAVE_PCI_CMD_STAT_VAL (PCI_COMMAND_INVALIDATE \ + | PCI_COMMAND_MEMORY \ + | PCI_COMMAND_IO) + +#define CFG_PCI_BOOT_HOST (1 << 2) +#define PCI_OUT_INT_MASK_VAL (1<<1) +#define XSCALE_RESET_BIT 0x00000001 + +#define FLASH_WRITE_ENABLE (1 << 9) +#define FLASH_ALIAS_DISABLE (1 << 8) + +#define IXP_TYPE_2800 0 +#define IXP_TYPE_2850 1 +#define IXP_TYPE_2400 2 + +#define IXP_IOC_QUERY_INFO 0x1 +#define IXP_IOC_RELEASE_RST 0x2 + +#define IXP_FLAG_ROM_BOOT (1<<0x0) +#define IXP_FLAG_PCI_HOST (1<<0x1) +#define IXP_FLAG_PCI_ARB (1<<0x2) +#define IXP_FLAG_NPU_UP (1<<0x3) /* Slave NPU is running after reset */ +#define IXP_FLAG_NO_FLASH (1<<0x4) /* Slave NPU does not have flash*/ + +#define CFG_BOOT_ROM (1 << 1) + +struct ixp_info { + char name[32]; + unsigned short ixp_type; + unsigned short ixp_rev; + + unsigned long sdram_size; + unsigned long sram_size; + + unsigned long flags; + + unsigned long csr_bar; + unsigned long sram_bar; + unsigned long sdram_bar; + + unsigned long csr_ioaddr; + unsigned long sram_ioaddr; + unsigned long sdram_ioaddr; + struct ixp_info *next; +}; + +#endif diff -Nru a/drivers/char/m41st85w.c b/drivers/char/m41st85w.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/m41st85w.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,664 @@ +/* + * m41st85w.c + * + * Device driver for ST's Real Time Controller M41ST85W. + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * Copyright (C) 2003 Intel Corp. + * + * 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 driver is adapted from the DS1307 driver + * Kernel time sync borrowed from RMK's acorn RTC driver + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "m41st85w.h" + +#define DEBUG 0 + +#if DEBUG +static unsigned int rtc_debug = DEBUG; +#define DPRINT printk +#else + #define rtc_debug 0 /* gcc will remove all the debug code for us */ + #define DPRINT +#endif + +static unsigned short slave_address = M41ST85W_I2C_SLAVE_ADDR; + +struct i2c_driver m41st85w_driver; +struct i2c_client *m41st85w_i2c_client = 0; +extern int (*set_rtc)(void); + +static unsigned short ignore[] = { I2C_CLIENT_END}; +static unsigned short normal_addr[] = { M41ST85W_I2C_SLAVE_ADDR, I2C_CLIENT_END}; + +static struct i2c_client_address_data addr_data = { + normal_i2c: normal_addr, + normal_i2c_range: ignore, + probe: ignore, + probe_range: ignore, + ignore: ignore, + ignore_range: ignore, + force: ignore, +}; + +static int m41st85w_rtc_ioctl( struct inode *, struct file *, unsigned int, unsigned long); +static int m41st85w_rtc_open(struct inode *inode, struct file *file); +static int m41st85w_rtc_release(struct inode *inode, struct file *file); + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + ioctl: m41st85w_rtc_ioctl, + open: m41st85w_rtc_open, + release: m41st85w_rtc_release, +}; + +static struct miscdevice m41st85w_rtc_miscdev = { + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int m41st85w_probe(struct i2c_adapter *adap); +static int m41st85w_detach(struct i2c_client *client); +static int m41st85w_command(struct i2c_client *client, unsigned int cmd, void *arg); + +struct i2c_driver m41st85w_driver = { + name: "m41st85w", + id: I2C_DRIVERID_M41ST85W, + flags: I2C_DF_NOTIFY, + attach_adapter: m41st85w_probe, + detach_client: m41st85w_detach, + command: m41st85w_command +}; + +static spinlock_t m41st85w_rtc_lock = SPIN_LOCK_UNLOCKED; + +#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */ + +static int +m41st85w_readram( char *buf, int len) +{ + unsigned long flags; + unsigned char ad[1] = { 0}; + int ret; + struct i2c_msg msgs[2] = { + { m41st85w_i2c_client->addr , 0, 1, ad}, + { m41st85w_i2c_client->addr , I2C_M_RD, len, buf}}; + + spin_lock_irqsave(&m41st85w_rtc_lock, flags); + ret = i2c_transfer(m41st85w_i2c_client->adapter, msgs, 2); + spin_unlock_irqrestore(&m41st85w_rtc_lock,flags); + + return ret; +} + +static void +m41st85w_dumpram( void) +{ + unsigned char buf[M41ST85W_RAM_SIZE]; + int ret; + + ret = m41st85w_readram( buf, M41ST85W_RAM_SIZE); + + if(ret > 0) + { + int i; + for(i=0; iaddr , 0, 1, ad}, + { m41st85w_i2c_client->addr , I2C_M_RD, 1, buf} + }; + unsigned char ctrl_info[2]; + int ret; + + if(enable) + { + ctrl_info[0] = SQW_ENABLE; + ctrl_info[1] = RATE_32768HZ; + } + else + { + ctrl_info[0] = SQW_DISABLE; + ctrl_info[1] = RATE_0HZ; + } + m41st85w_command(m41st85w_i2c_client, M41ST85W_SETCTRL, &ctrl_info); + + /* read addr 1 (Clock-Halt bit and second counter */ + buf[0] = 1; + ret = i2c_transfer(m41st85w_i2c_client->adapter, msgs, 2); + + if(enable) + { + buf2[1] = buf2[1] & ~CLOCK_HALT; /* clear Clock-Halt bit */ + buf[1] = buf[1] & ~CLOCK_STOP; + } + else + { + buf2[1] = buf2[1] | CLOCK_HALT; /* set Clock-Halt bit */ + buf[1] = buf[1] | CLOCK_STOP; + } + + /* addr 12, halt bit */ + buf2[0] = 12; + ret = i2c_master_send(m41st85w_i2c_client, (char *)buf2, 2); + + ret = i2c_master_send(m41st85w_i2c_client, (char *)buf, 2); +} + +static int +m41st85w_attach(struct i2c_adapter *adap, int addr, unsigned short flags,int kind) +{ + struct i2c_client *c; + unsigned char buf[1], ad[1] = { 10}; + struct i2c_msg msgs[2] = { + { addr , 0, 1, ad}, + { addr , I2C_M_RD, 1, buf} + }; + int ret; + + c = (struct i2c_client *)kmalloc(sizeof(*c), GFP_KERNEL); + if(!c) + return -ENOMEM; + + strcpy(c->name, "m41st85w"); + c->id = m41st85w_driver.id; + c->flags = 0; + c->addr = addr; + c->adapter = adap; + c->driver = &m41st85w_driver; + c->data = NULL; + + ret = i2c_transfer(c->adapter, msgs, 2); + + if(ret >= 0) + { + DAT(c) = buf[0]; + } + else + printk ("%s: i2c_transfer() returned %d.\n", __func__, ret); + + m41st85w_i2c_client = c; + m41st85w_enable_clock( 1); + + return i2c_attach_client(c); +} + +static int +m41st85w_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, m41st85w_attach); +} + +static int +m41st85w_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + m41st85w_enable_clock( 0); + + return 0; +} + +static void +m41st85w_convert_to_time( struct rtc_time *dt, char *buf) +{ + dt->tm_sec = BCD_TO_BIN(buf[0]); + dt->tm_min = BCD_TO_BIN(buf[1]); + + /* 24 hour mode only */ + dt->tm_hour = HOURS_24(buf[2]); + + dt->tm_mday = BCD_TO_BIN(buf[4]); + /* dt->tm_mon is zero-based */ + dt->tm_mon = BCD_TO_BIN(buf[5]) - 1; + /* year is 1900 + dt->tm_year */ + dt->tm_year = BCD_TO_BIN(buf[6]) + 100; + + if(rtc_debug > 2) + { + printk("m41st85w_get_datetime: year = %d\n", dt->tm_year); + printk("m41st85w_get_datetime: mon = %d\n", dt->tm_mon); + printk("m41st85w_get_datetime: mday = %d\n", dt->tm_mday); + printk("m41st85w_get_datetime: hour = %d\n", dt->tm_hour); + printk("m41st85w_get_datetime: min = %d\n", dt->tm_min); + printk("m41st85w_get_datetime: sec = %d\n", dt->tm_sec); + } +} + +static int +m41st85w_get_datetime(struct i2c_client *client, struct rtc_time *dt) +{ + unsigned char buf[7], addr[1] = { 1}; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr}, + { client->addr, I2C_M_RD, 7, buf} + }; + int ret = -EIO; + + memset(buf, 0, sizeof(buf)); + + ret = i2c_transfer(client->adapter, msgs, 2); + + if(ret >= 0) + { + m41st85w_convert_to_time( dt, buf); + ret = 0; + } + else + printk("m41st85w_get_datetime(), i2c_transfer() returned %d\n",ret); + + return ret; +} + +static int +m41st85w_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo) +{ + unsigned char buf[8]; + int ret, len = 4; + + if(rtc_debug > 2) + { + printk("m41st85w_set_datetime: tm_year = %d\n", dt->tm_year); + printk("m41st85w_set_datetime: tm_mon = %d\n", dt->tm_mon); + printk("m41st85w_set_datetime: tm_mday = %d\n", dt->tm_mday); + printk("m41st85w_set_datetime: tm_hour = %d\n", dt->tm_hour); + printk("m41st85w_set_datetime: tm_min = %d\n", dt->tm_min); + printk("m41st85w_set_datetime: tm_sec = %d\n", dt->tm_sec); + } + + buf[0] = 1; /* register address on m41st85w */ + buf[1] = (BIN_TO_BCD(dt->tm_sec)); + buf[2] = (BIN_TO_BCD(dt->tm_min)); + buf[3] = (BIN_TO_BCD(dt->tm_hour)); + + if(datetoo) + { + len = 8; + /* we skip buf[4] as we don't use day-of-week. */ + buf[5] = (BIN_TO_BCD(dt->tm_mday)); + buf[6] = (BIN_TO_BCD(dt->tm_mon + 1)); + /* The year only ranges from 0-99, we are being passed an offset from 1900, + * and the chip calulates leap years based on 2000, thus we adjust by 100. + */ + buf[7] = (BIN_TO_BCD(dt->tm_year - 100)); + } + ret = i2c_master_send(client, (char *)buf, len); + if(ret >= 0) + ret = 0; + else + printk("m41st85w_set_datetime(), i2c_master_send() returned %d\n",ret); + + + return ret; +} + +static int +m41st85w_get_ctrl(struct i2c_client *client, unsigned char *ctrl) +{ + *ctrl = DAT(client); + + return 0; +} + +static int +m41st85w_set_ctrl(struct i2c_client *client, unsigned char *cinfo) +{ + unsigned char buf[2]; + int ret; + + /* need to set square wave first */ + buf[0] = 13; + buf[1] = cinfo[1]; + ret = i2c_master_send(client, (char *)buf, 2); + if(ret<0) + { + return ret; + } + + buf[0] = 10; + buf[1] = cinfo[0]; + /* save the control reg info in the client data field so that get_ctrl + * function doesn't have to do an I2C transfer to get it. + */ + // Need to save frequency also + DAT(client) = buf[1]; + + ret = i2c_master_send(client, (char *)buf, 2); + + return ret; +} + +static int +m41st85w_read_mem(struct i2c_client *client, struct rtc_mem *mem) +{ + unsigned char addr[1]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr}, + { client->addr, I2C_M_RD, mem->nr, mem->data} + }; + + if((mem->loc < M41ST85W_RAM_ADDR_START) || + ((mem->loc + mem->nr -1) > M41ST85W_RAM_ADDR_END)) + return -EINVAL; + + addr[0] = mem->loc; + + return i2c_transfer(client->adapter, msgs, 2) >= 0 ? 0 : -EIO; +} + +static int +m41st85w_write_mem(struct i2c_client *client, struct rtc_mem *mem) +{ + unsigned char addr[1]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr}, + { client->addr, 0, mem->nr, mem->data} + }; + + if((mem->loc < M41ST85W_RAM_ADDR_START) || + ((mem->loc + mem->nr -1) > M41ST85W_RAM_ADDR_END)) + return -EINVAL; + + addr[0] = mem->loc; + + return i2c_transfer(client->adapter, msgs, 2) >= 0 ? 0 : -EIO; +} + +static int +m41st85w_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case M41ST85W_GETDATETIME: + return m41st85w_get_datetime(client, arg); + + case M41ST85W_SETTIME: + return m41st85w_set_datetime(client, arg, 0); + + case M41ST85W_SETDATETIME: + return m41st85w_set_datetime(client, arg, 1); + + case M41ST85W_GETCTRL: + return m41st85w_get_ctrl(client, arg); + + case M41ST85W_SETCTRL: + return m41st85w_set_ctrl(client, arg); + + case M41ST85W_MEM_READ: + return m41st85w_read_mem(client, arg); + + case M41ST85W_MEM_WRITE: + return m41st85w_write_mem(client, arg); + + default: + return -EINVAL; + } +} + +static int +m41st85w_rtc_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +m41st85w_rtc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +m41st85w_rtc_ioctl( struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + struct rtc_time wtime; + int status = 0; + + switch(cmd) + { + default: + case RTC_UIE_ON: + case RTC_UIE_OFF: + case RTC_PIE_ON: + case RTC_PIE_OFF: + case RTC_AIE_ON: + case RTC_AIE_OFF: + case RTC_ALM_SET: + case RTC_ALM_READ: + case RTC_IRQP_READ: + case RTC_IRQP_SET: + case RTC_EPOCH_SET: + case RTC_WKALM_SET: + case RTC_WKALM_RD: + status = -EINVAL; + break; + case RTC_EPOCH_READ: + return put_user (1970, (unsigned long *)arg); + case RTC_RD_TIME: + spin_lock_irqsave(&m41st85w_rtc_lock, flags); + m41st85w_command( m41st85w_i2c_client, M41ST85W_GETDATETIME, &wtime); + spin_unlock_irqrestore(&m41st85w_rtc_lock,flags); + + if(copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time))) + status = -EFAULT; + break; + + case RTC_SET_TIME: + if(!capable(CAP_SYS_TIME)) + { + status = -EACCES; + break; + } + + if(copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time))) + { + status = -EFAULT; + break; + } + + spin_lock_irqsave(&m41st85w_rtc_lock, flags); + m41st85w_command( m41st85w_i2c_client, M41ST85W_SETDATETIME, &wtime); + spin_unlock_irqrestore(&m41st85w_rtc_lock,flags); + break; + } + + return status; +} + +static char * +m41st85w_mon2str(unsigned int mon) +{ + char *mon2str[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + if(mon > 11) return "error"; + else return mon2str[ mon]; +} + +static int m41st85w_rtc_proc_output(char *buf) +{ +#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no") + unsigned char ram[M41ST85W_RAM_SIZE]; + int ret; + + char *p = buf; + + ret = m41st85w_readram(ram, M41ST85W_RAM_SIZE); + if(ret > 0) + { + int i; + struct rtc_time dt; + char text[9]; + + p += sprintf(p, "M41ST85W (64x8 Serial Real Time Clock)\n"); + + m41st85w_convert_to_time( &dt, ram); + p += sprintf(p, "Date/Time : %02d-%s-%04d %02d:%02d:%02d\n", + dt.tm_mday, m41st85w_mon2str(dt.tm_mon), dt.tm_year + 1900, + dt.tm_hour, dt.tm_min, dt.tm_sec); + + p += sprintf(p, "Clock halted : %s\n", CHECK(ram[0],0x80)); + p += sprintf(p, "24h mode : %s\n", CHECK(ram[2],0x40)); + p += sprintf(p, "Square wave enabled : %s\n", CHECK(ram[7],0x10)); + p += sprintf(p, "Freq : "); + + switch(ram[19] & 0x03) + { + case RATE_1HZ: + p += sprintf(p, "1Hz\n"); + break; + case RATE_4096HZ: + p += sprintf(p, "4.096kHz\n"); + break; + case RATE_8192HZ: + p += sprintf(p, "8.192kHz\n"); + break; + case RATE_32768HZ: + default: + p += sprintf(p, "32.768kHz\n"); + break; + + } + + p += sprintf(p, "RAM dump:\n"); + text[8]='\0'; + for(i=0; i126)) ram[i]='.'; + text[i%8] = ram[i]; + if((i%8) == 7) p += sprintf(p, "%s\n",text); + } + p += sprintf(p, "\n"); + } + else + { + p += sprintf(p, "Failed to read RTC memory!\n"); + } + + return p - buf; +} + +static int m41st85w_rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = m41st85w_rtc_proc_output (page); + if(len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if(len>count) len = count; + if(len<0) len = 0; + return len; +} + +static int m41st85w_k_set_rtc_time(void) +{ + struct rtc_time new_rtctm, old_rtctm; + unsigned long nowtime = xtime.tv_sec; + + if (m41st85w_command(m41st85w_i2c_client, M41ST85W_GETDATETIME, &old_rtctm)) + return 0; + + new_rtctm.tm_sec = nowtime % 60; nowtime /= 60; + new_rtctm.tm_min = nowtime % 60; nowtime /= 60; + new_rtctm.tm_hour = nowtime % 24; + + /* + * avoid writing when we're going to change the day + * of the month. We will retry in the next minute. + * This basically means that if the RTC must not drift + * by more than 1 minute in 11 minutes. + * + * [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00, + * rtc gets set to 1/1/2000 00:01:00 ] + */ + if ((old_rtctm.tm_hour == 23 && old_rtctm.tm_min == 59) || + (new_rtctm.tm_hour == 23 && new_rtctm.tm_min == 59)) + return 1; + + return m41st85w_command(m41st85w_i2c_client, M41ST85W_SETTIME, &new_rtctm); +} + + +static __init int m41st85w_init(void) +{ + int retval=0; + + normal_addr[0] = slave_address; + + retval = i2c_add_driver(&m41st85w_driver); + + if(retval==0) + { + misc_register (&m41st85w_rtc_miscdev); + create_proc_read_entry (PROC_M41ST85W_NAME, 0, 0, m41st85w_rtc_read_proc, NULL); + printk("I2C: M41ST85W RTC driver successfully loaded\n"); + + if(rtc_debug) m41st85w_dumpram(); + } + + { + struct rtc_time rtctm; + + retval = m41st85w_command(m41st85w_i2c_client, M41ST85W_GETDATETIME, + (void *)&rtctm); + + xtime.tv_usec = 0; + + xtime.tv_sec = mktime(1900+rtctm.tm_year, rtctm.tm_mon+1, rtctm.tm_mday, + rtctm.tm_hour, rtctm.tm_min, rtctm.tm_sec); + set_rtc = m41st85w_k_set_rtc_time; + } + + return retval; +} + +static __exit void m41st85w_exit(void) +{ + remove_proc_entry (PROC_M41ST85W_NAME, NULL); + misc_deregister(&m41st85w_rtc_miscdev); + i2c_del_driver(&m41st85w_driver); +} + +module_init(m41st85w_init); +module_exit(m41st85w_exit); + +MODULE_PARM (slave_address, "i"); +MODULE_PARM_DESC (slave_address, "I2C slave address for M41ST85W RTC."); + +MODULE_AUTHOR ("Intel Corp."); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/m41st85w.h b/drivers/char/m41st85w.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/m41st85w.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,69 @@ +/* + * m41st85w.h + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * Copyright (C) 2003 Intel Corp. + * + * 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 driver is adapted from the DS1307 driver + * + */ +#ifndef M41ST85W_H +#define M41ST85W_H + +#define M41ST85W_I2C_SLAVE_ADDR 0x68 + +#define M41ST85W_RAM_ADDR_START 0x00 +#define M41ST85W_RAM_ADDR_END 0x13 +#define M41ST85W_RAM_SIZE 0x14 + +#define PROC_M41ST85W_NAME "driver/m41st85w" + +struct rtc_mem { + unsigned int loc; + unsigned int nr; + unsigned char *data; +}; + +#define M41ST85W_GETDATETIME 0 +#define M41ST85W_SETTIME 1 +#define M41ST85W_SETDATETIME 2 +#define M41ST85W_GETCTRL 3 +#define M41ST85W_SETCTRL 4 +#define M41ST85W_MEM_READ 5 +#define M41ST85W_MEM_WRITE 6 + +#define SQW_ENABLE 0x40 /* Square Wave Enable */ +#define SQW_DISABLE 0x00 /* Square Wave disable */ + +#define RATE_32768HZ 0x10 /* Rate Select 32.768KHz */ +#define RATE_8192HZ 0x20 /* Rate Select 8.192KHz */ +#define RATE_4096HZ 0x30 /* Rate Select 4.096KHz */ +#define RATE_2048HZ 0x40 /* Rate Select 2.048Khz */ +#define RATE_1024HZ 0x50 /* Rate Select 1.024Khz */ +#define RATE_512HZ 0x60 /* Rate Select 0.512Khz */ +#define RATE_256HZ 0x70 /* Rate Select 0.256Khz */ +#define RATE_128HZ 0x80 /* Rate Select 0.128Khz */ +#define RATE_64HZ 0x90 /* Rate Select 0.064Khz */ +#define RATE_32HZ 0xa0 /* Rate Select 0.032Khz */ +#define RATE_16HZ 0xb0 /* Rate Select 0.016Khz */ +#define RATE_8HZ 0xc0 /* Rate Select 0.008Khz */ +#define RATE_4HZ 0xd0 /* Rate Select 0.004Khz */ +#define RATE_2HZ 0xe0 /* Rate Select 0.0001Khz */ +#define RATE_1HZ 0xf0 /* Rate Select 1Hz */ +#define RATE_0HZ 0x00 /* Rate Select None */ + +#define CLOCK_HALT 0x80 /* Clock Halt */ + +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) + +#define TWELVE_HOUR_MODE(n) (((n)>>6)&1) +#define HOURS_AP(n) (((n)>>5)&1) +#define HOURS_12(n) BCD_TO_BIN((n)&0x1F) +#define HOURS_24(n) BCD_TO_BIN((n)&0x3F) + +#endif diff -Nru a/drivers/char/pcf8594c-nvram.c b/drivers/char/pcf8594c-nvram.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/pcf8594c-nvram.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,411 @@ +/* + * drivers/char/pcf8594c-nvram.c + * + * I2C based NVRAM driver for the PCF8594C-2 EEPROM on the IXDP425 + * development platform. + * + * Original Author: Teodor Mihai + * Maintainer: Deepak Saxena + * + * The NVRAM is used to store MAC addresses for the onboard NPEs and + * other HW specific info on the IXDP425, so we want a much nicer/cleaner + * way to access the data then having to use the /proc interface from + * lm-sensors. This driver can easilly be adapted to other platforms + * by changing the I2C bus address we connect to. Note though that it + * is not meant to be used as a general purpose I2C EEPROM driver. + * + * + * Copyright (C) 2002-2003 INTEL CORPORATION + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define DBG printk +#else +#define DBG if (0) printk +#endif /* DEBUG */ + +#define PCF8594_EEPROM_ADDR (0x50) +#define PCF8594_EEPROM_SIZE (256) /* 256byte EEPROM */ + +#define PCF8594_EEPROM_MAX_WRITE (8) /* 8 bytes page mode */ +#define PCF8594_EEPROM_WRITE_DELAY (100)/* E/W time delay = 100ms */ + +/* forward declarations */ +static int pcf8594_attach_adapter(struct i2c_adapter *adapter); +static int pcf8594_detach_client(struct i2c_client *client); +static void pcf8594_inc_use(struct i2c_client *client); +static void pcf8594_dec_use(struct i2c_client *client); + +static struct i2c_driver pcf8594_driver = { + name: "PCF8594-2 EEPROM Driver", + id: I2C_DRIVERID_EXP0, + flags: I2C_DF_NOTIFY, + attach_adapter: pcf8594_attach_adapter, + detach_client: pcf8594_detach_client, + command: NULL, + inc_use: pcf8594_inc_use, + dec_use: pcf8594_dec_use +}; + +static struct i2c_client *pcf8594_client; + +/* Global lock to r/w acces to the device */ +static spinlock_t nvram_lock; + +/* mode [O_EXCL/FMODE_WRITE] for /dev/nvram */ +static int open_mode; + +static int pcf8594_write_transfer(int addr, u8 *buf, u32 num, u8 offset) +{ + struct i2c_msg msg[2]; + + if (pcf8594_client) { + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = &offset; + + msg[1].addr = addr; + msg[1].flags = 0 | I2C_M_NOSTART; + msg[1].len = num; + msg[1].buf = buf; + + return i2c_transfer(pcf8594_client->adapter, msg, 2); + } + else { + return -ENODEV; + } +} + +static int pcf8594_read_transfer(int addr, u8 *buf, u32 num, u8 offset) +{ + struct i2c_msg msg[2]; + + if (pcf8594_client) { + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = &offset; + + msg[1].addr = addr; + msg[1].flags = I2C_M_RD; + msg[1].len = num; + msg[1].buf = buf; + + return i2c_transfer(pcf8594_client->adapter, msg, 2); + } + else { + return -ENODEV; + } +} + +/* + * Kernel exported APIs. We provide a set of APIs to the kernel itself + * as there are drivers for IXP425 systems that require reading data + * out of the EEPROM. + */ + +/** + * pcf8594_eeprom_read - Read data from PCF8594C-2 EEPROM device + * @buf: Pointer to source buffer + * @num: Number of bytes to read + * @offset: Offset into EEPROM device at which to start reading + */ +int pcf8594_eeprom_read(u8 *buf, u32 num, u8 offset) +{ + if ((num + offset) > PCF8594_EEPROM_SIZE || buf == NULL) return (-1); + + return pcf8594_read_transfer(PCF8594_EEPROM_ADDR, buf, num, offset); +} + + +/** + * pcf8594_eeprom_write - Write data to PCF8594C-2 EEPROM + * @buf: Pointer to destination buffer + * @num: Number of bytes to write + * @offset: Offset at which to start writing + */ +int pcf8594_eeprom_write(u8 *buf, u32 num, u8 offset) +{ + int temp_count = 0; + int current_number = num; + + if ((num + offset) > PCF8594_EEPROM_SIZE || buf == NULL) + return (-1); + + while (current_number > 0) { + temp_count = PCF8594_EEPROM_MAX_WRITE > current_number ? current_number : PCF8594_EEPROM_MAX_WRITE; + + pcf8594_write_transfer(PCF8594_EEPROM_ADDR, buf, temp_count, offset); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((PCF8594_EEPROM_WRITE_DELAY * HZ) / 1000); + + current_number -= temp_count; + buf += temp_count; + offset += temp_count; + } + + return(num); +} + + +static int pcf8594_attach_adapter(struct i2c_adapter *adapter) +{ + DBG("pcf8594c-nvram: attaching to adapter %s\n", adapter->name); + + pcf8594_client = kmalloc(sizeof(*pcf8594_client), GFP_KERNEL); + + if (!pcf8594_client) { + return -ENOMEM; + } + + strcpy(pcf8594_client->name, "PCF8594C-2 NVRAM Driver"); + pcf8594_client->id = pcf8594_driver.id; + pcf8594_client->flags = I2C_CLIENT_ALLOW_USE; + pcf8594_client->addr = PCF8594_EEPROM_ADDR; + pcf8594_client->adapter = adapter; + pcf8594_client->driver = &pcf8594_driver; + pcf8594_client->data = NULL; + pcf8594_client->usage_count = 0; + + DBG("pcf8594c-nvram.0: client created, inserting\n"); + + return i2c_attach_client(pcf8594_client); +} + +static int pcf8594_detach_client(struct i2c_client *client) { + + int result = i2c_detach_client(client); + + if (result == 0) { + kfree(client); + + return 0; + } + else { + return result; + } + +} + +static void pcf8594_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +static void pcf8594_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} + +static long long pcf8594c_nvram_llseek(struct file *file, loff_t offset, int from) +{ + if (!pcf8594_client) return -ENODEV; + + switch (from) { + case 0: + break; + case 1: + offset += file->f_pos; + break; + case 2: + offset += PCF8594_EEPROM_SIZE; + break; + default: + return -EINVAL; + } + + if (offset < 0 || offset >= PCF8594_EEPROM_SIZE) + return -EINVAL; + + return file->f_pos = offset; +} + +static ssize_t pcf8594c_nvram_read(struct file *file, + char *buf, size_t count, loff_t *offset) +{ + char buffer[PCF8594_EEPROM_SIZE]; + + if (!pcf8594_client) return -ENODEV; + + if (*offset < 0 || *offset >= PCF8594_EEPROM_SIZE) + return 0; + + if (*offset + count >= PCF8594_EEPROM_SIZE) + count = PCF8594_EEPROM_SIZE - *offset; + + DBG("nvram: file_read into buffer 0x%08x, offset %d, len %d\n", (int) buf, (int) *offset, count); + + pcf8594_eeprom_read(buffer, count, *offset); + + if (copy_to_user(buf, buffer, count)) + return -EFAULT; + + *offset += count; + + DBG("nvram: read %d bytes\n", count); + + return count; +} + +static ssize_t pcf8594c_nvram_write(struct file *file, + const char *buf, size_t count, loff_t *offset) +{ + char buffer[PCF8594_EEPROM_SIZE]; + + if (!pcf8594_client) return -ENODEV; + + if (*offset < 0 || *offset >= PCF8594_EEPROM_SIZE) + return 0; + + if (*offset + count >= PCF8594_EEPROM_SIZE) + count = PCF8594_EEPROM_SIZE - *offset; + + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + + DBG("nvram: file_write from buffer 0x%08x, offset %d, len %d\n", (int) buf, (int) *offset, count); + + pcf8594_eeprom_write(buffer, count, *offset); + + *offset += count; + + DBG("nvram: wrote %d bytes\n", count); + + return count; +} + +static int pcf8594c_nvram_open( struct inode *inode, struct file *file ) +{ + int res = -EBUSY; + + if (!pcf8594_client) return -ENODEV; + + spin_lock(nvram_lock); + + if ((MOD_IN_USE && (file->f_flags & O_EXCL)) || + (open_mode & O_EXCL)) { + goto exit; + } + + if (file->f_flags & O_EXCL) + open_mode |= O_EXCL; + + pcf8594_inc_use(pcf8594_client); + + res = 0; + +exit: + spin_unlock(nvram_lock); + + return res; +} + +static int pcf8594c_nvram_release(struct inode *inode, struct file *file) +{ + if (!pcf8594_client) return -ENODEV; + + spin_lock_irq(nvram_lock); + + pcf8594_dec_use(pcf8594_client); + + if (file->f_flags & O_EXCL) + open_mode &= ~O_EXCL; + + spin_unlock_irq(nvram_lock); + + return 0; +} + +/* + * Since we're not a real PC-style "NVRAM", we just return -EINVAL + * on all IOCTL calls. + */ +static int pcf8594c_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return -EINVAL; +} + +static struct file_operations dev_fops = { + owner: THIS_MODULE, + + read: pcf8594c_nvram_read, + write: pcf8594c_nvram_write, + + open: pcf8594c_nvram_open, + release: pcf8594c_nvram_release, + + llseek: pcf8594c_nvram_llseek, + + ioctl: pcf8594c_nvram_ioctl +}; + +static struct miscdevice pcf8594c_nvram_dev = { + NVRAM_MINOR, + "PCF8594C2 I2C NVRAM", + &dev_fops +}; + + +static int __init pcf8594c_nvram_init(void) +{ + int ret; + + if ((ret = i2c_add_driver(&pcf8594_driver)) == 0) { + ret = misc_register(&pcf8594c_nvram_dev); + + if (ret) { + printk(KERN_ERR "misc_register failed for PCF8594C2 NVRAM device\n"); + return ret; + } + + printk(KERN_INFO "Loaded PCF8594C2 I2C EEPROM NVRAM driver\n"); + return 0; + } else { + printk(KERN_ERR "failed to register PCF8594C2 I2C EEPROM driver\n"); + + return ret; + } +} + +static void __exit pcf8594c_nvram_exit (void) +{ + i2c_del_driver(&pcf8594_driver); + misc_deregister(&pcf8594c_nvram_dev); +} + +module_init(pcf8594c_nvram_init); +module_exit(pcf8594c_nvram_exit); + +EXPORT_SYMBOL(pcf8594_eeprom_read); +EXPORT_SYMBOL(pcf8594_eeprom_write); + +MODULE_DESCRIPTION("PCF8594C-2 EEPROM /dev/nvram driver"); +MODULE_AUTHOR("Teodor Mihai "); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/char/serial.c b/drivers/char/serial.c --- a/drivers/char/serial.c Thu Dec 4 16:24:26 2003 +++ b/drivers/char/serial.c Thu Dec 4 16:24:26 2003 @@ -57,11 +57,8 @@ * 10/00: add in optional software flow control for serial console. * Kanoj Sarcar (Modified by Theodore Ts'o) * - * 02/02: Fix for AMD Elan bug in transmit irq routine, by - * Christer Weinigel , - * Robert Schwebel , - * Juergen Beisert , - * Theodore Ts'o + * 9/02: Add support for IXP425 uart chip. Intel Corporation. + * */ static char *serial_version = "5.05c"; @@ -311,6 +308,7 @@ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "XScale UART", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, { 0, 0} }; @@ -326,12 +324,11 @@ MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif /* CONFIG_SERIAL_RSA */ -struct serial_state rs_table[RS_TABLE_SIZE] = { +static struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) -int serial_nr_ports = NR_PORTS; #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) #define NR_PCI_BOARDS 8 @@ -423,7 +420,11 @@ #endif case SERIAL_IO_MEM: return readb((unsigned long) info->iomem_base + - (offset<iomem_reg_shift)); + ((offset)<iomem_reg_shift)); +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + return gsc_readb(info->iomem_base + offset); +#endif default: return inb(info->port + offset); } @@ -441,8 +442,13 @@ #endif case SERIAL_IO_MEM: writeb(value, (unsigned long) info->iomem_base + - (offset<iomem_reg_shift)); + ((offset)<iomem_reg_shift)); + break; +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + gsc_writeb(value, info->iomem_base + offset); break; +#endif default: outb(value, info->port+offset); } @@ -699,6 +705,7 @@ } count = info->xmit_fifo_size; + do { serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]); info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); @@ -798,7 +805,7 @@ */ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - int status, iir; + int status; struct async_struct * info; int pass_counter = 0; struct async_struct *end_mark = 0; @@ -823,7 +830,7 @@ do { if (!info->tty || - ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -883,7 +890,7 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status, iir; + int status; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT @@ -905,7 +912,6 @@ first_multi = inb(multi->port_monitor); #endif - iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -914,21 +920,18 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if ((status & UART_LSR_THRE) || - /* For buggy ELAN processors */ - ((iir & UART_IIR_ID) == UART_IIR_THRI)) + if (status & UART_LSR_THRE) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if SERIAL_DEBUG_INTR +#if 0 printk("rs_single loop break.\n"); #endif break; } - iir = serial_in(info, UART_IIR); #ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", iir); + printk("IIR = %x...", serial_in(info, UART_IIR)); #endif - } while ((iir & UART_IIR_NO_INT) == 0); + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor) @@ -1406,6 +1409,8 @@ * Finally, enable interrupts */ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + if (state->type == PORT_XSCALE) + info->IER |= UART_IER_UUE | UART_IER_RTOIE; serial_outp(info, UART_IER, info->IER); /* enable interrupts */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1538,7 +1543,7 @@ #endif info->MCR &= ~UART_MCR_OUT2; info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ - + /* disable break condition */ serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); @@ -1546,6 +1551,7 @@ info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); serial_outp(info, UART_MCR, info->MCR); + /* disable FIFO's */ serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | @@ -1852,6 +1858,7 @@ save_flags(flags); cli(); info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); + restore_flags(flags); } @@ -2141,7 +2148,6 @@ if (new_serial.type) { for (i = 0 ; i < NR_PORTS; i++) if ((state != &rs_table[i]) && - (rs_table[i].io_type == SERIAL_IO_PORT) && (rs_table[i].port == new_port) && rs_table[i].type) return -EADDRINUSE; @@ -2204,7 +2210,7 @@ check_and_exit: - if ((!state->port && !state->iomem_base) || !state->type) + if (!state->port || !state->type) return 0; if (info->flags & ASYNC_INITIALIZED) { if (((old_state.flags & ASYNC_SPD_MASK) != @@ -3256,17 +3262,14 @@ int ret; unsigned long flags; - /* - * Return zero characters for ports not claimed by driver. - */ - if (state->type == PORT_UNKNOWN) { - return 0; /* ignore unused ports */ - } - ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", state->line, uart_config[state->type].name, - (state->port ? state->port : (long)state->iomem_base), - state->irq); + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } /* * Figure out the current RS-232 lines @@ -3924,25 +3927,6 @@ } - /* HP's Diva chip puts the 4th/5th serial port further out, and - * some serial ports are supposed to be hidden on certain models. - */ - if (dev->vendor == PCI_VENDOR_ID_HP && - dev->device == PCI_DEVICE_ID_HP_SAS) { - switch (dev->subsystem_device) { - case 0x104B: /* Maestro */ - if (idx == 3) idx++; - break; - case 0x1282: /* Everest / Longs Peak */ - if (idx > 0) idx++; - if (idx > 2) idx++; - break; - } - if (idx > 2) { - offset = 0x18; - } - } - port = pci_resource_start(dev, base_idx) + offset; if ((board->flags & SPCI_FL_BASE_TABLE) == 0) @@ -4112,14 +4096,12 @@ * interface chip and different configuration methods: * - 10x cards have control registers in IO and/or memory space; * - 20x cards have control registers in standard PCI configuration space. - * - * SIIG initialization functions exported for use by parport_serial.c module. */ #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) -int __devinit +static int __devinit pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u16 data, *p; @@ -4144,12 +4126,11 @@ iounmap(p); return 0; } -EXPORT_SYMBOL(pci_siig10x_fn); #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) -int __devinit +static int __devinit pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u8 data; @@ -4168,7 +4149,6 @@ } return 0; } -EXPORT_SYMBOL(pci_siig20x_fn); /* Added for EKF Intel i960 serial boards */ static int __devinit @@ -4250,40 +4230,6 @@ return 0; } -/* - * HP's Remote Management Console. The Diva chip came in several - * different versions. N-class, L2000 and A500 have two Diva chips, each - * with 3 UARTs (the third UART on the second chip is unused). Superdome - * and Keystone have one Diva chip with 3 UARTs. Some later machines have - * one Diva chip, but it has been expanded to 5 UARTs. - */ -static int __devinit -pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable) -{ - if (!enable) - return 0; - - switch (dev->subsystem_device) { - case 0x1049: /* Prelude Diva 1 */ - case 0x1223: /* Superdome */ - case 0x1226: /* Keystone */ - case 0x1282: /* Everest / Longs Peak */ - board->num_ports = 3; - break; - case 0x104A: /* Prelude Diva 2 */ - board->num_ports = 2; - break; - case 0x104B: /* Maestro */ - board->num_ports = 4; - break; - case 0x1227: /* Powerbar */ - board->num_ports = 1; - break; - } - - return 0; -} - static int __devinit pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) { @@ -4313,7 +4259,6 @@ pbn_b0_bt_2_115200, pbn_b0_bt_1_460800, pbn_b0_bt_2_460800, - pbn_b0_bt_2_921600, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4328,7 +4273,6 @@ pbn_b1_4_1382400, pbn_b1_8_1382400, - pbn_b2_1_115200, pbn_b2_8_115200, pbn_b2_4_460800, pbn_b2_8_460800, @@ -4349,7 +4293,6 @@ pbn_timedia, pbn_intel_i960, pbn_sgi_ioc3, - pbn_hp_diva, #ifdef CONFIG_DDB5074 pbn_nec_nile4, #endif @@ -4394,7 +4337,6 @@ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4409,7 +4351,6 @@ { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */ { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */ - { SPCI_FL_BASE2, 1, 115200 }, /* pbn_b2_1_115200 */ { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */ { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */ { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */ @@ -4440,7 +4381,6 @@ 8<<2, 2, pci_inteli960ni_fn, 0x10000}, { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */ 1, 458333, 0, 0, 0, 0x20178 }, - { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0}, /* pbn_hp_diva */ #ifdef CONFIG_DDB5074 /* * NEC Vrc-5074 (Nile 4) builtin UART. @@ -4740,7 +4680,7 @@ pbn_b0_4_115200 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, + pbn_b0_2_115200 }, /* Digitan DS560-558, from jimd@esoft.com */ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, @@ -4787,6 +4727,15 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_2 }, @@ -4796,6 +4745,15 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig10x_4 }, @@ -4814,6 +4772,24 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_2 }, @@ -4823,6 +4799,15 @@ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_siig20x_4 }, @@ -4902,14 +4887,6 @@ 0xFF00, 0, 0, 0, pbn_sgi_ioc3 }, - /* HP Diva card */ - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_hp_diva }, - { PCI_VENDOR_ID_HP, 0x1290, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_115200 }, - #ifdef CONFIG_DDB5074 /* * NEC Vrc-5074 (Nile 4) builtin UART. @@ -5501,7 +5478,6 @@ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; state->line = i; - state->type = PORT_UNKNOWN; state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; @@ -5515,14 +5491,18 @@ state->irq = irq_cannonicalize(state->irq); if (state->hub6) state->io_type = SERIAL_IO_HUB6; - if (state->port && check_region(state->port,8)) + if (state->port && check_region(state->port,8)) { + state->type = PORT_UNKNOWN; continue; + } #ifdef CONFIG_MCA if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus) continue; #endif - if (state->flags & ASYNC_BOOT_AUTOCONF) + if (state->flags & ASYNC_BOOT_AUTOCONF) { + state->type = PORT_UNKNOWN; autoconfig(state); + } } for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { if (state->type == PORT_UNKNOWN) @@ -5532,7 +5512,7 @@ && (state->port != 0 || state->iomem_base != 0)) state->irq = detect_uart_irq(state); if (state->io_type == SERIAL_IO_MEM) { - printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n", + printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n", state->line + SERIAL_DEV_OFFSET, (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", state->iomem_base, state->irq, @@ -5707,7 +5687,7 @@ if (state->info && state->info->tty) tty_hangup(state->info->tty); state->type = PORT_UNKNOWN; - printk(KERN_INFO "ttyS%02d unloaded\n", state->line); + printk(KERN_INFO "tty%02d unloaded\n", state->line); /* These will be hidden, because they are devices that will no longer * be available to the system. (ie, PCMCIA modems, once ejected) */ @@ -5841,7 +5821,9 @@ * First save the IER then disable the interrupts */ ier = serial_in(info, UART_IER); - serial_out(info, UART_IER, 0x00); + serial_out(info, UART_IER, 0); + if (info->state->type == PORT_XSCALE) + serial_out(info, UART_IER, UART_IER_UUE); /* * Now, do each character @@ -5993,6 +5975,8 @@ serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ serial_out(info, UART_LCR, cval); /* reset DLAB */ serial_out(info, UART_IER, 0); + if (info->state->type == PORT_XSCALE) + serial_out(info, UART_IER, UART_IER_UUE); serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); /* diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c --- a/drivers/char/sysrq.c Thu Dec 4 16:24:25 2003 +++ b/drivers/char/sysrq.c Thu Dec 4 16:24:25 2003 @@ -98,6 +98,24 @@ }; +#ifdef CONFIG_KGDB + +#include + +static void +sysrq_handle_kgdb(int key, struct pt_regs *regs, struct kbd_struct *unused0, + struct tty_struct *unused1) +{ + breakpoint(); +} + +static struct sysrq_key_op sysrq_kgdb_op = { + handler: sysrq_handle_kgdb, + help_msg: "Debug Break", + action_msg: "Breaking into KGDB" +}; +#endif + /* SYNC SYSRQ HANDLERS BLOCK */ @@ -316,7 +334,6 @@ help_msg: "kIll", action_msg: "Kill All Tasks", }; - /* END SIGNAL SYSRQ HANDLERS BLOCK */ @@ -342,7 +359,11 @@ /* d */ NULL, /* e */ &sysrq_term_op, /* f */ NULL, +#ifndef CONFIG_KGDB /* g */ NULL, +#else +/* g */ &sysrq_kgdb_op, +#endif /* h */ NULL, /* i */ &sysrq_kill_op, /* j */ NULL, diff -Nru a/drivers/i2c/Config.in b/drivers/i2c/Config.in --- a/drivers/i2c/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/i2c/Config.in Thu Dec 4 16:24:25 2003 @@ -27,6 +27,12 @@ dep_tristate ' Frodo I2C adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT dep_tristate ' SA1100 I2C GPIO adapter' CONFIG_I2C_BIT_SA1100_GPIO $CONFIG_I2C_ALGOBIT fi + if [ "$CONFIG_ARCH_IXP2000" = "y" ]; then + dep_tristate ' IXP2000 style GPIO I2C adapter' CONFIG_I2C_IXP2000 $CONFIG_I2C_ALGOBIT + fi + if [ "$CONFIG_ARCH_IXP425" = "y" ]; then + dep_tristate ' IXP425 GPIO-based I2C adapter' CONFIG_I2C_IXP425 $CONFIG_I2C_ALGOBIT + fi fi dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C @@ -59,6 +65,10 @@ if [ "$CONFIG_ARCH_AT91RM9200" = "y" ] ; then dep_tristate 'Atmel AT91RM9200 I2C Two-Wire interface (TWI)' CONFIG_I2C_AT91 $CONFIG_I2C + fi + + if [ "$CONFIG_ARCH_IOP3XX" = "y" ] ; then + dep_tristate 'Intel XScale IOP3xx on-chip I2C interface' CONFIG_I2C_IOP3XX $CONFIG_I2C fi # This is needed for automatic patch generation: sensors code starts here diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile --- a/drivers/i2c/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/i2c/Makefile Thu Dec 4 16:24:25 2003 @@ -5,7 +5,7 @@ O_TARGET := i2c.o export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ - i2c-algo-ite.o i2c-proc.o + i2c-algo-ite.o i2c-proc.o # Init order: core, chardev, bit adapters, pcf adapters @@ -20,6 +20,8 @@ obj-$(CONFIG_I2C_GUIDE) += i2c-guide.o obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o obj-$(CONFIG_I2C_OMAHA) += i2c-omaha.o +obj-$(CONFIG_I2C_IXP2000) += i2c-adap-ixp2000.o +obj-$(CONFIG_I2C_IXP425) += i2c-adap-ixp425.o # PCF adapters obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o @@ -30,7 +32,7 @@ obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o - +obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -Nru a/drivers/i2c/i2c-adap-ixdp2400.c b/drivers/i2c/i2c-adap-ixdp2400.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-adap-ixdp2400.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,183 @@ +/* + * drivers/i2c/i2c-ixdp2400.c + * + * I2C adapter for IXP2000 systems with IXDP2400 style I2C bus + * + * Author: Deepak Saxena + * Based on code by: Naeem M. Afzal + * + * Copyright 2003 MontaVista Software Inc. + * + * 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. + * + * I2C adapter driver for IXDP2400 reference platform. This could + * be a generic IXP2000 driver, but the IXDP2400 uses the HW GPIO + * in a very board specific manner to create an I2C bus. If you copy + * the exact same setup, you can use this driver for your board. + * + * GPIO2 is pulled high and connected to both I2C lines. + * + * GPIO6 and GPIO7 are used for SDA and SCL respectively and + * are both set to 0. + * + * To drive a line high on the bus, that that GPIO is set to an output. + * This causes the GPIO pin to float and so the bus sees a logic 1. + * + * To drive a line low on the bus, that GPIO is set to an input + * and we pull down the line. + * + * (This is my understanding of it. I'm not a HW person and don't have + * the schematics in front of me, but this seems to make sense from + * the original Intel driver). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * In case other boards use the same setup, this will make it + * easier to support multiple boards without tons of + * #ifdef's or machine_is_xxx() calls. Just fill in the ixdp2400_gpio + * with the appropriate GPIO information. + */ +static struct ixdp2400_data { + unsigned short sda_gpio; + unsigned short scl_gpio; +} ixdp2400_gpio; + +static void ixdp2400_bit_setscl(void *data, int val) +{ + struct ixdp2400_data *gpio = (struct ixdp2400_data*)data; + int i = 5000; + + if(val) { + gpio_line_config(gpio->scl_gpio, GPIO_IN); + while(!gpio_line_get(gpio->scl_gpio) && i--); + } else { + gpio_line_config(gpio->scl_gpio, GPIO_OUT); + } +} + +static void ixdp2400_bit_setsda(void *data, int val) +{ + struct ixdp2400_data *gpio = (struct ixdp2400_data*)data; + + if(val) { + gpio_line_config(gpio->sda_gpio, GPIO_IN); + } else { + gpio_line_config(gpio->sda_gpio, GPIO_OUT); + } + +// printk("SDA %d PDPR = %#010x\n", val, *IXP2000_GPIO_PDPR); +} + +static int ixdp2400_bit_getscl(void *data) +{ + struct ixdp2400_data *gpio = (struct ixdp2400_data*)data; + int ret; + + ret = gpio_line_get(gpio->scl_gpio); + + return ret; +} + +static int ixdp2400_bit_getsda(void *data) +{ + struct ixdp2400_data *gpio = (struct ixdp2400_data*)data; + int ret; + + ret = gpio_line_get(gpio->sda_gpio); + + return ret; +} + +void ixdp2400_i2c_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void ixdp2400_i2c_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +/* + * If you board provides multiple I2C channels, just + * make copies of this and change the gpio information. + */ +static struct i2c_algo_bit_data ixdp2400_bit_data = { + .data = &ixdp2400_gpio, + .setsda = ixdp2400_bit_setsda, + .setscl = ixdp2400_bit_setscl, + .getsda = ixdp2400_bit_getsda, + .getscl = ixdp2400_bit_getscl, + .udelay = 6, + .mdelay = 6, + .timeout = 100 +}; + +static struct i2c_adapter ixdp2400_i2c_adapter = { + .name = "IXDP2400-style GPIO I2C Adapter", + .id = I2C_HW_B_IXDP2400, + .algo = NULL, + .algo_data = &ixdp2400_bit_data, + .inc_use = ixdp2400_i2c_inc, + .dec_use = ixdp2400_i2c_dec +}; + +static int __init ixdp2400_i2c_init(void) +{ + if(machine_is_ixdp2400()) { + int i = 0; + + /* + * GPIO2 needs to be high for SDA to work on this board + */ + gpio_line_set(IXDP2400_GPIO_HIGH, 1); + gpio_line_config(IXDP2400_GPIO_HIGH, GPIO_OUT); + + ixdp2400_gpio.sda_gpio = IXDP2400_GPIO_SCL; + ixdp2400_gpio.scl_gpio = IXDP2400_GPIO_SDA; + + gpio_line_config(ixdp2400_gpio.sda_gpio, GPIO_OUT); + gpio_line_config(ixdp2400_gpio.scl_gpio, GPIO_OUT); + + gpio_line_set(ixdp2400_gpio.scl_gpio, 0); + gpio_line_set(ixdp2400_gpio.sda_gpio, 0); + + gpio_line_config(ixdp2400_gpio.scl_gpio, GPIO_IN); + + for(i = 0; i < 10; i++); + + gpio_line_config(ixdp2400_gpio.sda_gpio, GPIO_IN); + } + + if (i2c_bit_add_bus(&ixdp2400_i2c_adapter)) { + printk("i2c-ixdp2400: I2C adapter registration failed\n"); + return -EIO; + } else printk("i2c-ixdp2400: I2C bus initialized\n"); + + return 0; +} + +static void __exit ixdp2400_i2c_exit(void) +{ + i2c_bit_del_bus(&ixdp2400_i2c_adapter); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR ("Deepak Saxena "); +MODULE_DESCRIPTION("IXDP2400 I2C bus driver"); +MODULE_LICENSE("GPL"); + +module_init(ixdp2400_i2c_init); +module_exit(ixdp2400_i2c_exit); diff -Nru a/drivers/i2c/i2c-adap-ixp2000.c b/drivers/i2c/i2c-adap-ixp2000.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-adap-ixp2000.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,179 @@ +/* + * drivers/i2c/i2c-adap-ixp2000.c + * + * I2C adapter for IXP2000 systems using GPIOs for I2C bus + * + * Author: Deepak Saxena + * Based on code by: Naeem M. Afzal + * Made generic by: Jeff Daly + * + * Copyright (c) 2003 MontaVista Software Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * I2C adapter driver for IXP2000 platform. This should + * be a generic IXP2000 driver, if you use the HW GPIO in the same manner. + * Basically, SDA and SCL GPIOs have external pullups. Setting the respective + * GPIO to an input will make the signal a '1' via the pullup. Setting them + * to outputs will pull them down. + * + * The GPIOs are open drain signals and are used as configuration strap inputs + * during power-up so there's generally a buffer on the board that needs to be + * 'enabled' to drive the GPIOs. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Init code fills this in at run time with board-specific data. + */ +static struct ixp2000_data { + unsigned short sda_gpio; + unsigned short scl_gpio; +} ixp2000_gpio; + +static void ixp2000_bit_setscl(void *data, int val) +{ + struct ixp2000_data *gpio = (struct ixp2000_data*)data; + int i = 5000; + + if(val) { + gpio_line_config(gpio->scl_gpio, GPIO_IN); + while(!gpio_line_get(gpio->scl_gpio) && i--); + } else { + gpio_line_config(gpio->scl_gpio, GPIO_OUT); + } +} + +static void ixp2000_bit_setsda(void *data, int val) +{ + struct ixp2000_data *gpio = (struct ixp2000_data*)data; + + if(val) { + gpio_line_config(gpio->sda_gpio, GPIO_IN); + } else { + gpio_line_config(gpio->sda_gpio, GPIO_OUT); + } +} + +static int ixp2000_bit_getscl(void *data) +{ + struct ixp2000_data *gpio = (struct ixp2000_data*)data; + int ret; + + ret = gpio_line_get(gpio->scl_gpio); + + return ret; +} + +static int ixp2000_bit_getsda(void *data) +{ + struct ixp2000_data *gpio = (struct ixp2000_data*)data; + int ret; + + ret = gpio_line_get(gpio->sda_gpio); + + return ret; +} + +void ixp2000_i2c_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void ixp2000_i2c_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +/* + * If you board provides multiple I2C channels, just + * make copies of this and change the gpio information. + */ +static struct i2c_algo_bit_data ixp2000_bit_data = { + .data = &ixp2000_gpio, + .setsda = ixp2000_bit_setsda, + .setscl = ixp2000_bit_setscl, + .getsda = ixp2000_bit_getsda, + .getscl = ixp2000_bit_getscl, + .udelay = 6, + .mdelay = 6, + .timeout = 100 +}; + +static struct i2c_adapter ixp2000_i2c_adapter = { + .name = "IXP2000-style GPIO I2C Adapter", + .id = I2C_HW_B_IXP2000, + .algo = NULL, + .algo_data = &ixp2000_bit_data, + .inc_use = ixp2000_i2c_inc, + .dec_use = ixp2000_i2c_dec +}; + +static int __init ixp2000_i2c_init(void) +{ + int i = 0; + +#ifdef CONFIG_ARCH_IXDP2400 + if(machine_is_ixdp2400()) { + + gpio_line_set(IXDP2400_GPIO_I2C_ENABLE, 1); + gpio_line_config(IXDP2400_GPIO_I2C_ENABLE, GPIO_OUT); + + ixp2000_gpio.sda_gpio = IXDP2400_GPIO_SDA; + ixp2000_gpio.scl_gpio = IXDP2400_GPIO_SCL; + } +#endif +#ifdef CONFIG_ARCH_IXDP2800 + if(machine_is_ixdp2800()) { + + gpio_line_set(IXDP2800_GPIO_I2C_ENABLE, 1); + gpio_line_config(IXDP2800_GPIO_I2C_ENABLE, GPIO_OUT); + + ixp2000_gpio.sda_gpio = IXDP2800_GPIO_SDA; + ixp2000_gpio.scl_gpio = IXDP2800_GPIO_SCL; + } +#endif + + gpio_line_config(ixp2000_gpio.sda_gpio, GPIO_OUT); + gpio_line_config(ixp2000_gpio.scl_gpio, GPIO_OUT); + + gpio_line_set(ixp2000_gpio.scl_gpio, 0); + gpio_line_set(ixp2000_gpio.sda_gpio, 0); + + gpio_line_config(ixp2000_gpio.scl_gpio, GPIO_IN); + + for(i = 0; i < 10; i++); + + gpio_line_config(ixp2000_gpio.sda_gpio, GPIO_IN); + + if (i2c_bit_add_bus(&ixp2000_i2c_adapter)) { + printk("i2c-adap-ixp2000: I2C adapter registration failed\n"); + return -EIO; + } else printk("i2c-adap-ixp2000: I2C bus initialized\n"); + + return 0; +} + +static void __exit ixp2000_i2c_exit(void) +{ + i2c_bit_del_bus(&ixp2000_i2c_adapter); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR ("Deepak Saxena "); +MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); +MODULE_LICENSE("GPL"); + +module_init(ixp2000_i2c_init); +module_exit(ixp2000_i2c_exit); diff -Nru a/drivers/i2c/i2c-adap-ixp425.c b/drivers/i2c/i2c-adap-ixp425.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-adap-ixp425.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,146 @@ +/* + * drivers/i2c/i2c-adap-ixp425.c + * + * Driver for gpio-based i2c adapter on IXP425 systems. + * + * Author: Deepak Saxena + * + * Based on original Intel driver by Teodor Mihai + * + * TODO: fix GPIO interface so that _get just returns value instead + * of taking ptr + * + * Copyright 2003 MontaVista Software Inc. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct ixp425_i2c_data { + unsigned int sda_line; + unsigned int scl_line; +} gpio_data; + +static inline int ixp425_scl_line(void *data) +{ + return ((struct ixp425_i2c_data*)data)->scl_line; +} + +static inline int ixp425_sda_line(void *data) +{ + return ((struct ixp425_i2c_data*)data)->sda_line; +} + +static void ixdp425_bit_setscl(void *data, int val) +{ + gpio_line_set(ixp425_scl_line(data), 0); + gpio_line_config(ixp425_scl_line(data), + val ? IXP425_GPIO_IN : IXP425_GPIO_OUT ); +} + +static void ixdp425_bit_setsda(void *data, int val) +{ + gpio_line_set(ixp425_sda_line(data), 0); + gpio_line_config(ixp425_sda_line(data), + val ? IXP425_GPIO_IN : IXP425_GPIO_OUT ); +} + +static int ixdp425_bit_getscl(void *data) +{ + int scl; + + gpio_line_config(ixp425_scl_line(data), IXP425_GPIO_IN ); + gpio_line_get(ixp425_scl_line(data), &scl); + + return scl; +} + +static int ixdp425_bit_getsda(void *data) +{ + int sda; + + gpio_line_config(ixp425_sda_line(data), IXP425_GPIO_IN ); + gpio_line_get(ixp425_sda_line(data), &sda); + + return sda; +} + +static void ixp425_i2c_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void ixp425_i2c_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +struct i2c_algo_bit_data ixdp425_bit_data = { + .data = &gpio_data, + .setsda = ixdp425_bit_setsda, + .setscl = ixdp425_bit_setscl, + .getsda = ixdp425_bit_getsda, + .getscl = ixdp425_bit_getscl, + .udelay = 10, + .mdelay = 10, + .timeout = 100 +}; + +struct i2c_adapter ixp425_i2c_adapter = { + .name = "IXP425 I2C Adapter", + .id = I2C_HW_B_IXP425, + .algo_data = &ixdp425_bit_data, + .inc_use = ixp425_i2c_inc_use, + .dec_use = ixp425_i2c_dec_use, +}; + +int __init ixp425_i2c_init(void) +{ + int res; + + if(machine_is_ixdp425()) { + gpio_data.scl_line = IXP425_GPIO_PIN_6; + gpio_data.sda_line = IXP425_GPIO_PIN_7; + } else { + printk(KERN_WARNING + "Unknown IXP425 platform: No I2C support available\n"); + return -EIO; + } + + gpio_line_config(gpio_data.scl_line, IXP425_GPIO_IN); + gpio_line_config(gpio_data.sda_line, IXP425_GPIO_IN); + gpio_line_set(gpio_data.scl_line, 0); + gpio_line_set(gpio_data.sda_line, 0); + + if ((res = i2c_bit_add_bus(&ixp425_i2c_adapter) != 0)) { + printk(KERN_ERR "ERROR: Could not install IXP425 I2C adapter\n"); + return res; + } + + return 0; +} + +void __exit ixp425_i2c_exit(void) +{ + i2c_bit_del_bus(&ixp425_i2c_adapter); +} + +module_init(ixp425_i2c_init); +module_exit(ixp425_i2c_exit); + +MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP425 systems"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena"); + diff -Nru a/drivers/i2c/i2c-iop3xx.c b/drivers/i2c/i2c-iop3xx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-iop3xx.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,545 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd + * + + 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. + + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ +/* + With acknowledgements to i2c-algo-ibm_ocp.c by + Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com + + And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund: + + Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund + + And which acknowledged Kyösti Mälkki , + Frodo Looijaard , Martin Bailey + + ---------------------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include "i2c-iop3xx.h" + + +/* ----- global defines ----------------------------------------------- */ +#define PASSERT(x) do { if (!(x) ) \ + printk(KERN_CRIT "PASSERT %s in %s:%d\n", #x, __FILE__, __LINE__ );\ + } while (0) + + +/* ----- global variables --------------------------------------------- */ + + +static inline unsigned char iic_cook_addr(struct i2c_msg *msg) +{ + unsigned char addr; + + addr = (msg->addr << 1); + + if (msg->flags & I2C_M_RD) + addr |= 1; + + /* PGM: what is M_REV_DIR_ADDR - do we need it ?? */ + if (msg->flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + + return addr; +} + + +static inline void iop3xx_adap_reset(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + /* Follows devman 9.3 */ + *iop3xx_adap->biu->CR = IOP321_ICR_UNIT_RESET; + *iop3xx_adap->biu->SR = IOP321_ISR_CLEARBITS; + *iop3xx_adap->biu->CR = 0; +} + +static inline void iop3xx_adap_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + *iop3xx_adap->biu->SAR = MYSAR; +} + +static inline void iop3xx_adap_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + u32 cr = IOP321_ICR_GCD|IOP321_ICR_SCLEN|IOP321_ICR_UE; + + /* NB SR bits not same position as CR IE bits :-( */ + iop3xx_adap->biu->SR_enabled = + IOP321_ISR_ALD | IOP321_ISR_BERRD | + IOP321_ISR_RXFULL | IOP321_ISR_TXEMPTY; + + cr |= IOP321_ICR_ALDIE | IOP321_ICR_BERRIE | + IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE; + + *iop3xx_adap->biu->CR = cr; +} + +static void iop3xx_adap_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + unsigned cr = *iop3xx_adap->biu->CR; + + cr &= ~(IOP321_ICR_MSTART | IOP321_ICR_TBYTE | + IOP321_ICR_MSTOP | IOP321_ICR_SCLEN); + *iop3xx_adap->biu->CR = cr; +} + +static void iop3xx_adap_final_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + unsigned cr = *iop3xx_adap->biu->CR; + + cr &= ~(IOP321_ICR_ALDIE | IOP321_ICR_BERRIE | + IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE); + iop3xx_adap->biu->SR_enabled = 0; + *iop3xx_adap->biu->CR = cr; +} + +/* + * NB: the handler has to clear the source of the interrupt! + * Then it passes the SR flags of interest to BH via adap data + */ +static void iop3xx_i2c_handler(int this_irq, + void *dev_id, + struct pt_regs *regs) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id; + + u32 sr = *iop3xx_adap->biu->SR; + + if ((sr &= iop3xx_adap->biu->SR_enabled)) { + *iop3xx_adap->biu->SR = sr; + iop3xx_adap->biu->SR_received |= sr; + wake_up_interruptible(&iop3xx_adap->waitq); + } +} + +/* check all error conditions, clear them , report most important */ +static int iop3xx_adap_error(u32 sr) +{ + int rc = 0; + + if ((sr&IOP321_ISR_BERRD)) { + if ( !rc ) rc = -I2C_ERR_BERR; + } + if ((sr&IOP321_ISR_ALD)) { + if ( !rc ) rc = -I2C_ERR_ALD; + } + return rc; +} + +static inline u32 get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + unsigned long flags; + u32 sr; + + spin_lock_irqsave(&iop3xx_adap->lock, flags); + sr = iop3xx_adap->biu->SR_received; + iop3xx_adap->biu->SR_received = 0; + spin_unlock_irqrestore(&iop3xx_adap->lock, flags); + + return sr; +} + +/* + * sleep until interrupted, then recover and analyse the SR + * saved by handler + */ +typedef int (* compare_func)(unsigned test, unsigned mask); +/* returns 1 on correct comparison */ + +static int iop3xx_adap_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, + unsigned flags, unsigned* status, + compare_func compare) +{ + unsigned sr = 0; + int interrupted; + int done; + int rc = 0; + + do { + interrupted = wait_event_interruptible_timeout ( + iop3xx_adap->waitq, + (done = compare( sr = get_srstat(iop3xx_adap),flags )), + iop3xx_adap->timeout + ); + if ((rc = iop3xx_adap_error(sr)) < 0) { + *status = sr; + return rc; + }else if (!interrupted) { + *status = sr; + return -ETIMEDOUT; + } + } while(!done); + + *status = sr; + + return 0; +} + +/* + * Concrete compare_funcs + */ +static int all_bits_clear(unsigned test, unsigned mask) +{ + return (test & mask) == 0; +} +static int any_bits_set(unsigned test, unsigned mask) +{ + return (test & mask) != 0; +} + +static int iop3xx_adap_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) +{ + return iop3xx_adap_wait_event( + iop3xx_adap, + IOP321_ISR_TXEMPTY|IOP321_ISR_ALD|IOP321_ISR_BERRD, + status, any_bits_set); +} + +static int iop3xx_adap_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) +{ + return iop3xx_adap_wait_event( + iop3xx_adap, + IOP321_ISR_RXFULL|IOP321_ISR_ALD|IOP321_ISR_BERRD, + status, any_bits_set); +} + +static int iop3xx_adap_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) +{ + return iop3xx_adap_wait_event( + iop3xx_adap, IOP321_ISR_UNITBUSY, status, all_bits_clear); +} + +/* + * Description: This performs the IOP3xx initialization sequence + * Valid for IOP321. Maybe valid for IOP310?. + */ +static int iop3xx_adap_init (struct i2c_algo_iop3xx_data *iop3xx_adap) +{ + *IOP321_GPOD &= ~(iop3xx_adap->channel==0 ? + IOP321_GPOD_I2C0: + IOP321_GPOD_I2C1); + + iop3xx_adap_reset(iop3xx_adap); + iop3xx_adap_set_slave_addr(iop3xx_adap); + iop3xx_adap_enable(iop3xx_adap); + + return 0; +} + +static int iop3xx_adap_send_target_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, + struct i2c_msg* msg) +{ + unsigned cr = *iop3xx_adap->biu->CR; + int status; + int rc; + + *iop3xx_adap->biu->DBR = iic_cook_addr(msg); + + cr &= ~(IOP321_ICR_MSTOP | IOP321_ICR_NACK); + cr |= IOP321_ICR_MSTART | IOP321_ICR_TBYTE; + + *iop3xx_adap->biu->CR = cr; + rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status); + /* this assert fires every time, contrary to IOP manual + PASSERT((status&IOP321_ISR_UNITBUSY)!=0); + */ + PASSERT((status&IOP321_ISR_RXREAD)==0); + + return rc; +} + +static int iop3xx_adap_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, int stop) +{ + unsigned cr = *iop3xx_adap->biu->CR; + int status; + int rc = 0; + + *iop3xx_adap->biu->DBR = byte; + cr &= ~IOP321_ICR_MSTART; + if (stop) { + cr |= IOP321_ICR_MSTOP; + } else { + cr &= ~IOP321_ICR_MSTOP; + } + *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE; + rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status); + + return rc; +} + +static int iop3xx_adap_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, + char* byte, int stop) +{ + unsigned cr = *iop3xx_adap->biu->CR; + int status; + int rc = 0; + + cr &= ~IOP321_ICR_MSTART; + + if (stop) { + cr |= IOP321_ICR_MSTOP|IOP321_ICR_NACK; + } else { + cr &= ~(IOP321_ICR_MSTOP|IOP321_ICR_NACK); + } + *iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE; + + rc = iop3xx_adap_wait_rx_done(iop3xx_adap, &status); + + *byte = *iop3xx_adap->biu->DBR; + + + return rc; +} + +static int iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, + const char *buf, int count) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; + int ii; + int rc = 0; + int ret = 0; + + for (ii = 0; rc == 0 && ii != count; ++ii) { + rc = iop3xx_adap_write_byte(iop3xx_adap, buf[ii], ii==count-1); + } + return rc; +} + +static int iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, + char *buf, int count) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; + int ii; + int rc = 0; + int ret = 0; + + for (ii = 0; rc == 0 && ii != count; ++ii) { + rc = iop3xx_adap_read_byte(iop3xx_adap, &buf[ii], ii==count-1); + } + return rc; +} + +/* + * Description: This function implements combined transactions. Combined + * transactions consist of combinations of reading and writing blocks of data. + * FROM THE SAME ADDRESS + * Each transfer (i.e. a read or a write) is separated by a repeated start + * condition. + */ +static int iop3xx_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; + int rc; + + rc = iop3xx_adap_send_target_slave_addr(iop3xx_adap, pmsg); + if (rc < 0) { + return rc; + } + + if ((pmsg->flags&I2C_M_RD)) { + return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len); + } else { + return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len); + } +} + +/* + * master_xfer() - main read/write entry + */ +static int iop3xx_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; + int im = 0; + int ret = 0; + int status; + + iop3xx_adap_wait_idle(iop3xx_adap, &status); + iop3xx_adap_reset(iop3xx_adap); + iop3xx_adap_enable(iop3xx_adap); + + for (im = 0; ret == 0 && im != num; im++) { + ret = iop3xx_handle_msg(i2c_adap, &msgs[im]); + } + + iop3xx_adap_transaction_cleanup(iop3xx_adap); + + if(ret) + return ret; + + return im; +} + +static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +static u32 iic_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm iic_algo = { + .name = "IOP3xx I2C algorithm", + .id = I2C_ALGO_OCP_IOP3XX, + .master_xfer = iop3xx_master_xfer, + .algo_control = algo_control, + .functionality = iic_func, +}; + +/* + * registering functions to load algorithms at runtime + */ +static int i2c_iop3xx_add_bus(struct i2c_adapter *iic_adap) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data; + + if (!request_region( REGION_START(iop3xx_adap), + REGION_LENGTH(iop3xx_adap), + iic_adap->name)) { + return -ENODEV; + } + + init_waitqueue_head(&iop3xx_adap->waitq); + spin_lock_init(&iop3xx_adap->lock); + + if (request_irq( + iop3xx_adap->biu->irq, + iop3xx_i2c_handler, + /* SA_SAMPLE_RANDOM */ 0, + iic_adap->name, + iop3xx_adap)) { + return -ENODEV; + } + + /* register new iic_adapter to i2c module... */ + iic_adap->id |= iic_algo.id; + iic_adap->algo = &iic_algo; + + iic_adap->timeout = 100; /* default values, should */ + iic_adap->retries = 3; /* be replaced by defines */ + + iop3xx_adap_init(iic_adap->algo_data); + i2c_add_adapter(iic_adap); + return 0; +} + +static int i2c_iop3xx_del_bus(struct i2c_adapter *iic_adap) +{ + struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data; + + iop3xx_adap_final_cleanup(iop3xx_adap); + free_irq(iop3xx_adap->biu->irq, iop3xx_adap); + + release_region(REGION_START(iop3xx_adap), REGION_LENGTH(iop3xx_adap)); + + return i2c_del_adapter(iic_adap); +} + +#ifdef CONFIG_ARCH_IOP321 + +static struct iop3xx_biu biu0 = { + .CR = IOP321_I2C_ICR0, + .SR = IOP321_I2C_ISR0, + .SAR = IOP321_I2C_ISAR0, + .DBR = IOP321_I2C_IDBR0, + .BMR = IOP321_I2C_IBMR0, + .irq = IRQ_IOP321_I2C_0, +}; + +static struct iop3xx_biu biu1 = { + .CR = IOP321_I2C_ICR1, + .SR = IOP321_I2C_ISR1, + .SAR = IOP321_I2C_ISAR1, + .DBR = IOP321_I2C_IDBR1, + .BMR = IOP321_I2C_IBMR1, + .irq = IRQ_IOP321_I2C_1, +}; + +#define ADAPTER_NAME_ROOT "IOP321 i2c biu adapter " +#else +#error Please define the BIU struct iop3xx_biu for your processor arch +#endif + +static struct i2c_algo_iop3xx_data algo_iop3xx_data0 = { + .channel = 0, + .biu = &biu0, + .timeout = 1*HZ, +}; +static struct i2c_algo_iop3xx_data algo_iop3xx_data1 = { + .channel = 1, + .biu = &biu1, + .timeout = 1*HZ, +}; + +static struct i2c_adapter iop3xx_ops0 = { + .name = ADAPTER_NAME_ROOT "0", + .id = I2C_HW_IOP321, + .algo = NULL, + .algo_data = &algo_iop3xx_data0, +}; +static struct i2c_adapter iop3xx_ops1 = { + .name = ADAPTER_NAME_ROOT "1", + .id = I2C_HW_IOP321, + .algo = NULL, + .algo_data = &algo_iop3xx_data1, +}; + +static int __init i2c_iop3xx_init (void) +{ + return i2c_iop3xx_add_bus(&iop3xx_ops0) || + i2c_iop3xx_add_bus(&iop3xx_ops1); +} + +static void __exit i2c_iop3xx_exit (void) +{ + i2c_iop3xx_del_bus(&iop3xx_ops0); + i2c_iop3xx_del_bus(&iop3xx_ops1); +} + +module_init (i2c_iop3xx_init); +module_exit (i2c_iop3xx_exit); + +MODULE_AUTHOR("D-TACQ Solutions Ltd "); +MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(i2c_debug,"i"); + +MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol"); + diff -Nru a/drivers/i2c/i2c-iop3xx.h b/drivers/i2c/i2c-iop3xx.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-iop3xx.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,118 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd + * + + 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. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- */ + + +#ifndef I2C_IOP3XX_H +#define I2C_IOP3XX_H 1 + +/* + * iop321 hardware bit definitions + */ +#define IOP321_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */ +#define IOP321_ICR_UNIT_RESET 0x4000 /* 1=RESET */ +#define IOP321_ICR_SADIE 0x2000 /* 1=Slave Detect Interrupt Enable */ +#define IOP321_ICR_ALDIE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */ +#define IOP321_ICR_SSDIE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */ +#define IOP321_ICR_BERRIE 0x0400 /* 1=Bus Error Interrupt Enable */ +#define IOP321_ICR_RXFULLIE 0x0200 /* 1=Receive Full Interrupt Enable */ +#define IOP321_ICR_TXEMPTYIE 0x0100 /* 1=Transmit Empty Interrupt Enable */ +#define IOP321_ICR_GCD 0x0080 /* 1=General Call Disable */ +/* + * IOP321_ICR_GCD: 1 disables response as slave. "This bit must be set + * when sending a master mode general call message from the I2C unit" + */ +#define IOP321_ICR_UE 0x0040 /* 1=Unit Enable */ +/* + * "NOTE: To avoid I2C bus integrity problems, + * the user needs to ensure that the GPIO Output Data Register - + * GPOD bits associated with an I2C port are cleared prior to setting + * the enable bit for that I2C serial port. + * The user prepares to enable I2C port 0 and + * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively. + */ +#define IOP321_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */ +#define IOP321_ICR_MABORT 0x0010 /* 1=Send a STOP with no data + * NB TBYTE must be clear */ +#define IOP321_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */ +#define IOP321_ICR_NACK 0x0004 /* 1=reply with NACK */ +#define IOP321_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */ +#define IOP321_ICR_MSTART 0x0001 /* 1=initiate a START */ + + +#define IOP321_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */ +#define IOP321_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */ +#define IOP321_ISR_GCAD 0x0100 /* 1=General Call Address Detected */ +#define IOP321_ISR_RXFULL 0x0080 /* 1=Receive Full */ +#define IOP321_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */ +#define IOP321_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */ +#define IOP321_ISR_SSD 0x0010 /* 1=Slave STOP Detected */ +#define IOP321_ISR_BBUSY 0x0008 /* 1=Bus BUSY */ +#define IOP321_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */ +#define IOP321_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */ +#define IOP321_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */ + +#define IOP321_ISR_CLEARBITS 0x07f0 + +#define IOP321_ISAR_SAMASK 0x007f + +#define IOP321_IDBR_MASK 0x00ff + +#define IOP321_IBMR_SCL 0x0002 +#define IOP321_IBMR_SDA 0x0001 + +#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */ +#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */ + +#define MYSAR 0x02 /* SWAG a suitable slave address */ + +#define I2C_ERR 321 +#define I2C_ERR_BERR (I2C_ERR+0) +#define I2C_ERR_ALD (I2C_ERR+1) + + +struct iop3xx_biu { /* Bus Interface Unit - the hardware */ +/* physical hardware defs - regs*/ + u32 *CR; + u32 *SR; + u32 *SAR; + u32 *DBR; + u32 *BMR; +/* irq bit vector */ + u32 irq; +/* stored flags */ + u32 SR_enabled, SR_received; +}; + +struct i2c_algo_iop3xx_data { + int channel; + + wait_queue_head_t waitq; + spinlock_t lock; + int timeout; + struct iop3xx_biu* biu; +}; + +#define REGION_START(adap) ((u32)((adap)->biu->CR)) +#define REGION_END(adap) ((u32)((adap)->biu->BMR+1)) +#define REGION_LENGTH(adap) (REGION_END(adap)-REGION_START(adap)) + +#define IRQ_STATUS_MASK(adap) (1<biu->irq) + +#endif /* I2C_IOP3XX_H */ diff -Nru a/drivers/mtd/Config.in b/drivers/mtd/Config.in --- a/drivers/mtd/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/Config.in Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ -# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $ +# $Id: Config.in,v 1.75 2003/05/23 11:38:29 dwmw2 Exp $ mainmenu_option next_comment comment 'Memory Technology Devices (MTD)' @@ -30,6 +30,7 @@ if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW fi + dep_tristate ' INFTL (Inverse NAND Flash Translation Layer) support' CONFIG_INFTL $CONFIG_MTD source drivers/mtd/chips/Config.in diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile --- a/drivers/mtd/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/Makefile Thu Dec 4 16:24:26 2003 @@ -1,30 +1,7 @@ # # Makefile for the memory technology device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -# -# $Id: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $ - - -obj-y += chips/chipslink.o maps/mapslink.o \ - devices/devlink.o nand/nandlink.o -obj-m := -obj-n := -obj- := - -O_TARGET := mtdlink.o - -export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o -list-multi := nftl.o - -mod-subdirs := -subdir-y := chips maps devices nand -subdir-m := $(subdir-y) +# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $ # *** BIG UGLY NOTE *** # @@ -52,15 +29,44 @@ # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o -obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o -obj-$(CONFIG_FTL) += ftl.o -obj-$(CONFIG_NFTL) += nftl.o +obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o +obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o +obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o +obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o +obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o + +nftl-objs := nftlcore.o nftlmount.o +inftl-objs := inftlcore.o inftlmount.o -nftl-objs := nftlcore.o nftlmount.o +ifeq ($(PATCHLEVEL),4) + +export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o \ + mtdconcat.o mtd_blkdevs-24.o + +mtd_blkdevs-objs := mtd_blkdevs-24.o + +obj-y += chips/chipslink.o maps/mapslink.o \ + devices/devlink.o nand/nandlink.o + +O_TARGET := mtdlink.o + +list-multi := nftl.o inftl.o mtd_blkdevs.o + +mod-subdirs := +subdir-y := chips maps devices nand +subdir-m := $(subdir-y) include $(TOPDIR)/Rules.make nftl.o: $(nftl-objs) $(LD) -r -o $@ $(nftl-objs) +inftl.o: $(inftl-objs) + $(LD) -r -o $@ $(inftl-objs) + +mtd_blkdevs.o: $(mtd_blkdevs-objs) + $(LD) -r -o $@ $(mtd_blkdevs-objs) + +else +obj-y += chips/ maps/ devices/ nand/ +endif diff -Nru a/drivers/mtd/afs.c b/drivers/mtd/afs.c --- a/drivers/mtd/afs.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/afs.c Thu Dec 4 16:24:25 2003 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $ + $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $ ======================================================================*/ @@ -76,17 +76,19 @@ return ret; } + ret = 1; + /* * Does it contain the magic number? */ if (fs.signature != 0xa0ffff9f) - ret = 1; + ret = 0; /* * Don't touch the SIB. */ if (fs.type == 2) - ret = 1; + ret = 0; *iis_start = fs.image_info_base & mask; *img_start = fs.image_start & mask; @@ -96,14 +98,14 @@ * be located after the footer structure. */ if (*iis_start >= ptr) - ret = 1; + ret = 0; /* * Check the start of this image. The image * data can not be located after this block. */ if (*img_start > off) - ret = 1; + ret = 0; return ret; } @@ -125,7 +127,9 @@ return ret; } -int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts) +static int parse_afs_partitions(struct mtd_info *mtd, + struct mtd_partition **pparts, + unsigned long origin) { struct mtd_partition *parts; u_int mask, off, idx, sz; @@ -150,7 +154,7 @@ ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) break; - if (ret == 1) + if (ret == 0) continue; ret = afs_read_iis(mtd, &iis, iis_ptr); @@ -183,7 +187,7 @@ ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); if (ret < 0) break; - if (ret == 1) + if (ret == 0) continue; /* Read the image info block */ @@ -227,7 +231,25 @@ return idx ? idx : ret; } -EXPORT_SYMBOL(parse_afs_partitions); +static struct mtd_part_parser afs_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_afs_partitions, + .name = "afs", +}; + +static int __init afs_parser_init(void) +{ + return register_mtd_parser(&afs_parser); +} + +static void __exit afs_parser_exit(void) +{ + deregister_mtd_parser(&afs_parser); +} + +module_init(afs_parser_init); +module_exit(afs_parser_exit); + MODULE_AUTHOR("ARM Ltd"); MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); diff -Nru a/drivers/mtd/chips/Config.in b/drivers/mtd/chips/Config.in --- a/drivers/mtd/chips/Config.in Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/chips/Config.in Thu Dec 4 16:24:26 2003 @@ -1,6 +1,6 @@ # drivers/mtd/chips/Config.in -# $Id: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $ +# $Id: Config.in,v 1.17 2003/09/25 14:40:34 thayne Exp $ mainmenu_option next_comment @@ -11,13 +11,12 @@ if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then define_bool CONFIG_MTD_GEN_PROBE y +elif [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then + define_bool CONFIG_MTD_GEN_PROBE m else - if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then - define_bool CONFIG_MTD_GEN_PROBE m - else - define_bool CONFIG_MTD_GEN_PROBE n - fi + define_bool CONFIG_MTD_GEN_PROBE n fi + if [ "$CONFIG_MTD_GEN_PROBE" = "y" -o "$CONFIG_MTD_GEN_PROBE" = "m" ]; then bool ' Flash chip driver advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then @@ -44,7 +43,26 @@ fi dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE +if [ "$CONFIG_MTD_CFI_AMDSTD" = "y" -o "$CONFIG_MTD_CFI_AMDSTD" = "m" ]; then + bool ' Retry failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY n + if [ "$CONFIG_MTD_CFI_AMDSTD_RETRY" = "y" ]; then + int ' Max retries of failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0 + fi +fi + dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE + +if [ "$CONFIG_MTD_CFI_INTELEXT" = "y" \ + -o "$CONFIG_MTD_CFI_AMDSTD" = "y" \ + -o "$CONFIG_MTD_CFI_STAA" = "y" ]; then + define_bool CONFIG_MTD_CFI_UTIL y +elif [ "$CONFIG_MTD_CFI_INTELEXT" = "m" \ + -o "$CONFIG_MTD_CFI_AMDSTD" = "m" \ + -o "$CONFIG_MTD_CFI_STAA" = "m" ]; then + define_bool CONFIG_MTD_CFI_UTIL m +else + define_bool CONFIG_MTD_CFI_UTIL n +fi dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD diff -Nru a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile --- a/drivers/mtd/chips/Makefile Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/chips/Makefile Thu Dec 4 16:24:26 2003 @@ -1,11 +1,12 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ +# $Id: Makefile.common,v 1.3 2003/09/25 14:40:34 thayne Exp $ +ifeq ($(PATCHLEVEL),4) O_TARGET := chipslink.o - -export-objs := chipreg.o gen_probe.o +export-objs := chipreg.o gen_probe.o cfi_util.o +endif # *** BIG UGLY NOTE *** # @@ -17,6 +18,7 @@ obj-$(CONFIG_MTD) += chipreg.o obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o obj-$(CONFIG_MTD_CFI) += cfi_probe.o +obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o @@ -28,4 +30,4 @@ obj-$(CONFIG_MTD_SHARP) += sharp.o obj-$(CONFIG_MTD_ABSENT) += map_absent.o -include $(TOPDIR)/Rules.make +-include $(TOPDIR)/Rules.make diff -Nru a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c --- a/drivers/mtd/chips/amd_flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/amd_flash.c Thu Dec 4 16:24:25 2003 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -125,10 +126,10 @@ static struct mtd_chip_driver amd_flash_chipdrv = { - probe: amd_flash_probe, - destroy: amd_flash_destroy, - name: "amd_flash", - module: THIS_MODULE + .probe = amd_flash_probe, + .destroy = amd_flash_destroy, + .name = "amd_flash", + .module = THIS_MODULE }; @@ -140,11 +141,11 @@ static inline __u32 wide_read(struct map_info *map, __u32 addr) { if (map->buswidth == 1) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (map->buswidth == 2) { - return map->read16(map, addr); + return map_read16(map, addr); } else if (map->buswidth == 4) { - return map->read32(map, addr); + return map_read32(map, addr); } return 0; @@ -153,11 +154,11 @@ static inline void wide_write(struct map_info *map, __u32 val, __u32 addr) { if (map->buswidth == 1) { - map->write8(map, val, addr); + map_write8(map, val, addr); } else if (map->buswidth == 2) { - map->write16(map, val, addr); + map_write16(map, val, addr); } else if (map->buswidth == 4) { - map->write32(map, val, addr); + map_write32(map, val, addr); } } @@ -424,231 +425,228 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) { - /* Keep this table on the stack so that it gets deallocated after the - * probe is done. - */ - const struct amd_flash_info table[] = { + static const struct amd_flash_info table[] = { { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV160DT, - name: "AMD AM29LV160DT", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DT, + .name = "AMD AM29LV160DT", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV160DB, - name: "AMD AM29LV160DB", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DB, + .name = "AMD AM29LV160DB", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVT160, - name: "Toshiba TC58FVT160", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT160, + .name = "Toshiba TC58FVT160", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV160TE, - name: "Fujitsu MBM29LV160TE", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160TE, + .name = "Fujitsu MBM29LV160TE", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVB160, - name: "Toshiba TC58FVB160", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB160, + .name = "Toshiba TC58FVB160", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV160BE, - name: "Fujitsu MBM29LV160BE", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160BE, + .name = "Fujitsu MBM29LV160BE", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BB, - name: "AMD AM29LV800BB", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F800BB, - name: "AMD AM29F800BB", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BB, + .name = "AMD AM29F800BB", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BT, - name: "AMD AM29LV800BT", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, - { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BT, + .name = "AMD AM29LV800BT", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F800BT, - name: "AMD AM29F800BT", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, - { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BT, + .name = "AMD AM29F800BT", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BB, - name: "AMD AM29LV800BB", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, - { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV800BB, - name: "Fujitsu MBM29LV800BB", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800BB, + .name = "Fujitsu MBM29LV800BB", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W800T, - name: "ST M29W800T", - size: 0x00100000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, - { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W800T, + .name = "ST M29W800T", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W160DT, - name: "ST M29W160DT", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W160DT, + .name = "ST M29W160DT", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W160DB, - name: "ST M29W160DB", - size: 0x00200000, - numeraseregions: 4, - regions: { - { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, - { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, - { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W160DB, + .name = "ST M29W160DB", + .size = 0x00200000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29BDS323D, - name: "AMD AM29BDS323D", - size: 0x00400000, - numeraseregions: 3, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 48 }, - { offset: 0x300000, erasesize: 0x10000, numblocks: 15 }, - { offset: 0x3f0000, erasesize: 0x02000, numblocks: 8 }, + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29BDS323D, + .name = "AMD AM29BDS323D", + .size = 0x00400000, + .numeraseregions = 3, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, + { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29BDS643D, - name: "AMD AM29BDS643D", - size: 0x00800000, - numeraseregions: 3, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 96 }, - { offset: 0x600000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 }, + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29BDS643D, + .name = "AMD AM29BDS643D", + .size = 0x00800000, + .numeraseregions = 3, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, + { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, } }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49xV16x, - name: "Atmel AT49xV16x", - size: 0x00200000, - numeraseregions: 2, - regions: { - { offset: 0x000000, erasesize: 0x02000, numblocks: 8 }, - { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16x, + .name = "Atmel AT49xV16x", + .size = 0x00200000, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49xV16xT, - name: "Atmel AT49xV16xT", - size: 0x00200000, - numeraseregions: 2, - regions: { - { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, - { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 } + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16xT, + .name = "Atmel AT49xV16xT", + .size = 0x00200000, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } } } }; @@ -822,7 +820,7 @@ chip->state = FL_READY; - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); wake_up(&chip->wq); spin_unlock_bh(chip->mutex); @@ -984,7 +982,7 @@ u_char tmp_buf[4]; __u32 datum; - map->copy_from(map, tmp_buf, + map_copy_from(map, tmp_buf, bus_ofs + private->chips[chipnum].start, map->buswidth); while (len && i < map->buswidth) @@ -1057,7 +1055,7 @@ u_char tmp_buf[2]; __u32 datum; - map->copy_from(map, tmp_buf, + map_copy_from(map, tmp_buf, ofs + private->chips[chipnum].start, map->buswidth); while (len--) { @@ -1178,7 +1176,7 @@ __u8 verify; for (address = adr; address < (adr + size); address++) { - if ((verify = map->read8(map, address)) != 0xFF) { + if ((verify = map_read8(map, address)) != 0xFF) { error = 1; break; } diff -Nru a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c --- a/drivers/mtd/chips/cfi_cmdset_0001.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/cfi_cmdset_0001.c Thu Dec 4 16:24:25 2003 @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.114 2003/03/18 12:28:40 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.132 2003/11/04 19:34:22 thayne Exp $ * * * 10/10/2000 Nicolas Pitre @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,10 +30,14 @@ #include #include #include -#include +#include #include +#include + +/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */ -// debugging, turns off buffer write mode #define FORCE_WORD_WRITE +// debugging, turns off buffer write mode if set to 1 +#define FORCE_WORD_WRITE 0 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -52,16 +57,21 @@ static struct mtd_info *cfi_intelext_setup (struct map_info *); -static int do_point (struct mtd_info *mtd, loff_t from, size_t len, +static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); -static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, +static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len); + +/* + * *********** SETUP AND PROBE BITS *********** + */ + static struct mtd_chip_driver cfi_intelext_chipdrv = { - probe: NULL, /* Not usable directly */ - destroy: cfi_intelext_destroy, - name: "cfi_cmdset_0001", - module: THIS_MODULE + .probe = NULL, /* Not usable directly */ + .destroy = cfi_intelext_destroy, + .name = "cfi_cmdset_0001", + .module = THIS_MODULE }; /* #define DEBUG_LOCK_BITS */ @@ -102,13 +112,63 @@ } printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", - extp->VccOptimal >> 8, extp->VccOptimal & 0xf); + extp->VccOptimal >> 4, extp->VccOptimal & 0xf); if (extp->VppOptimal) printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", - extp->VppOptimal >> 8, extp->VppOptimal & 0xf); + extp->VppOptimal >> 4, extp->VppOptimal & 0xf); } #endif +#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE +/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ +static void fixup_intel_strataflash(struct map_info *map, void* param) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + + printk(KERN_WARNING "cfi_cmdset_0001: Suspend " + "erase on write disabled.\n"); + extp->SuspendCmdSupport &= ~1; +} +#endif + +static void fixup_st_m28w320ct(struct map_info *map, void* param) +{ + struct cfi_private *cfi = map->fldrv_priv; + + cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ + cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ +} + +static void fixup_st_m28w320cb(struct map_info *map, void* param) +{ + struct cfi_private *cfi = map->fldrv_priv; + + /* Note this is done after the region info is endian swapped */ + cfi->cfiq->EraseRegionInfo[1] = + (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; +}; + +static struct cfi_fixup fixup_table[] = { +#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE + { + CFI_MFR_ANY, CFI_ID_ANY, + fixup_intel_strataflash, NULL + }, +#endif + { + 0x0020, /* STMicroelectronics */ + 0x00ba, /* M28W320CT */ + fixup_st_m28w320ct, NULL + }, { + 0x0020, /* STMicroelectronics */ + 0x00bb, /* M28W320CB */ + fixup_st_m28w320cb, NULL + }, { + 0, 0, NULL, NULL + } +}; + /* This routine is made available to other mtd code via * inter_module_register. It must only be accessed through * inter_module_get which will bump the use count of this module. The @@ -120,7 +180,6 @@ { struct cfi_private *cfi = map->fldrv_priv; int i; - __u32 base = cfi->chips[0].start; if (cfi->cfi_mode == CFI_MODE_CFI) { /* @@ -130,40 +189,20 @@ */ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; struct cfi_pri_intelext *extp; - int ofs_factor = cfi->interleave * cfi->device_type; - //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr); - if (!adr) + extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp"); + if (!extp) return NULL; - - /* Switch it into Query Mode */ - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - - extp = kmalloc(sizeof(*extp), GFP_KERNEL); - if (!extp) { - printk(KERN_ERR "Failed to allocate memory\n"); - return NULL; - } - - /* Read in the Extended Query Table */ - for (i=0; iMajorVersion != '1' || - (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { - printk(KERN_WARNING " Unknown IntelExt Extended Query " - "version %c.%c.\n", extp->MajorVersion, - extp->MinorVersion); - kfree(extp); - return NULL; - } /* Do some byteswapping if necessary */ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); + + /* Install our own private info structure */ + cfi->cmdset_priv = extp; + + cfi_fixup(map, fixup_table); #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ @@ -171,18 +210,8 @@ #endif if(extp->SuspendCmdSupport & 1) { -//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ - printk(KERN_WARNING "cfi_cmdset_0001: Suspend " - "erase on write disabled.\n"); - extp->SuspendCmdSupport &= ~1; -#else printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); -#endif } - /* Install our own private info structure */ - cfi->cmdset_priv = extp; } for (i=0; i< cfi->numchips; i++) { @@ -194,8 +223,6 @@ map->fldrv = &cfi_intelext_chipdrv; - /* Make sure it's in read mode */ - cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); return cfi_intelext_setup(map); } @@ -261,20 +288,16 @@ mtd->erase = cfi_intelext_erase_varsize; mtd->read = cfi_intelext_read; - if(map->point && map->unpoint){ - mtd->point = do_point; - mtd->unpoint = do_unpoint; + if (map_is_linear(map)) { + mtd->point = cfi_intelext_point; + mtd->unpoint = cfi_intelext_unpoint; } -#ifndef FORCE_WORD_WRITE - if ( cfi->cfiq->BufWriteTimeoutTyp ) { - printk("Using buffer write method\n" ); + if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { + printk(KERN_INFO "Using buffer write method\n" ); mtd->write = cfi_intelext_write_buffers; } else { -#else - { -#endif - printk("Using word write method\n" ); + printk(KERN_INFO "Using word write method\n" ); mtd->write = cfi_intelext_write_words; } mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; @@ -286,8 +309,8 @@ mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; map->fldrv = &cfi_intelext_chipdrv; - MOD_INC_USE_COUNT; mtd->name = map->name; + __module_get(THIS_MODULE); return mtd; setup_err: @@ -301,78 +324,170 @@ return NULL; } -static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) +/* + * *********** CHIP ACCESS FUNCTIONS *********** + */ + +static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { - cfi_word status, status_OK; - unsigned long timeo; DECLARE_WAITQUEUE(wait, current); - unsigned long cmd_addr; struct cfi_private *cfi = map->fldrv_priv; + cfi_word status, status_OK = CMD(0x80); + unsigned long timeo; + struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv; - adr += chip->start; - - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); - - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - + resettime: timeo = jiffies + HZ; retry: - spin_lock(chip->mutex); - - /* Check that the chip's ready to talk to us. - * If it's in FL_ERASING state, suspend it and make it talk now. - */ switch (chip->state) { - case FL_READY: - case FL_POINT: - break; + case FL_STATUS: + for (;;) { + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + if (time_after(jiffies, timeo)) { + printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", + (long long)status); + spin_unlock(chip->mutex); + return -EIO; + } + spin_unlock(chip->mutex); + cfi_udelay(1); + spin_lock(chip->mutex); + /* Someone else might have been playing with it. */ + goto retry; + } + + case FL_READY: case FL_CFI_QUERY: case FL_JEDEC_QUERY: - cfi_write(map, CMD(0x70), cmd_addr); - chip->state = FL_STATUS; + return 0; + + case FL_ERASING: + if (!(cfip->FeatureSupport & 2) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) + goto sleep; + + + /* Erase suspend */ + cfi_write(map, CMD(0xB0), adr); + + /* If the flash has finished erasing, then 'erase suspend' + * appears to make some (28F320) flash devices switch to + * 'read' mode. Make sure that we switch to 'read status' + * mode so we get the right data. --rmk + */ + cfi_write(map, CMD(0x70), adr); + chip->oldstate = FL_ERASING; + chip->state = FL_ERASE_SUSPENDING; + chip->erase_suspended = 1; + for (;;) { + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + if (time_after(jiffies, timeo)) { + /* Urgh. Resume and pretend we weren't here. */ + cfi_write(map, CMD(0xd0), adr); + /* Make sure we're in 'read status' mode if it had finished */ + cfi_write(map, CMD(0x70), adr); + chip->state = FL_ERASING; + chip->oldstate = FL_READY; + printk(KERN_ERR "Chip not ready after erase " + "suspended: status = 0x%x\n", status); + return -EIO; + } - case FL_STATUS: - status = cfi_read(map, cmd_addr); - if ((status & status_OK) == status_OK) { - cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; - break; - } - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { spin_unlock(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status); - return -EIO; + cfi_udelay(1); + spin_lock(chip->mutex); + /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. + So we can just loop here. */ } + chip->state = FL_STATUS; + return 0; - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; + case FL_POINT: + /* Only if there's no operation suspended... */ + if (mode == FL_READY && chip->oldstate == FL_READY) + return 0; default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ + sleep: set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + spin_lock(chip->mutex); + goto resettime; } +} - chip->state = FL_POINT; - chip->ref_point_counter++; +static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + + switch(chip->oldstate) { + case FL_ERASING: + chip->state = chip->oldstate; + /* What if one interleaved chip has finished and the + other hasn't? The old code would leave the finished + one in READY mode. That's bad, and caused -EROFS + errors to be returned from do_erase_oneblock because + that's the only bit it checked for at the time. + As the state machine appears to explicitly allow + sending the 0x70 (Read Status) command to an erasing + chip and expecting it to be ignored, that's what we + do. */ + cfi_write(map, CMD(0xd0), adr); + cfi_write(map, CMD(0x70), adr); + chip->oldstate = FL_READY; + chip->state = FL_ERASING; + break; + + case FL_READY: + case FL_STATUS: + /* We should really make set_vpp() count, rather than doing this */ + DISABLE_VPP(map); + break; + default: + printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); + } + wake_up(&chip->wq); +} + +static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) +{ + unsigned long cmd_addr; + struct cfi_private *cfi = map->fldrv_priv; + int ret = 0; + + adr += chip->start; + + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); + + spin_lock(chip->mutex); + + ret = get_chip(map, chip, cmd_addr, FL_POINT); + + if (!ret) { + if (chip->state != FL_POINT && chip->state != FL_READY) + cfi_write(map, CMD(0xff), cmd_addr); + + chip->state = FL_POINT; + chip->ref_point_counter++; + } spin_unlock(chip->mutex); - return 0; + + return ret; } -static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) + +static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -380,19 +495,17 @@ int chipnum; int ret = 0; - if (from + len > mtd->size) + if (!map->virt || (from + len > mtd->size)) return -EINVAL; - *mtdbuf = map->point(map, from, len); - if(*mtdbuf == NULL) - return -EINVAL; /* can not point this region */ + *mtdbuf = (void *)map->virt + from; *retlen = 0; /* Now lock the chip(s) to POINT state */ /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); - ofs = from - (chipnum << cfi->chipshift); + ofs = from - (chipnum << cfi->chipshift); while (len) { unsigned long thislen; @@ -418,14 +531,13 @@ return 0; } -static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long ofs; int chipnum; - map->unpoint(map, addr, from, len); /* Now unlock the chip(s) POINT state */ /* ofs: offset within the first chip that the first read should start */ @@ -446,13 +558,14 @@ thislen = len; spin_lock(chip->mutex); - if(chip->state == FL_POINT){ + if (chip->state == FL_POINT) { chip->ref_point_counter--; if(chip->ref_point_counter == 0) chip->state = FL_READY; } else - printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ - wake_up(&chip->wq); + printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ + + put_chip(map, chip, chip->start); spin_unlock(chip->mutex); len -= thislen; @@ -463,136 +576,32 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) { - cfi_word status, status_OK; - unsigned long timeo; - DECLARE_WAITQUEUE(wait, current); - int suspended = 0; unsigned long cmd_addr; struct cfi_private *cfi = map->fldrv_priv; + int ret; adr += chip->start; /* Ensure cmd read/writes are aligned. */ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - - timeo = jiffies + HZ; - retry: spin_lock(chip->mutex); + ret = get_chip(map, chip, cmd_addr, FL_READY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } - /* Check that the chip's ready to talk to us. - * If it's in FL_ERASING state, suspend it and make it talk now. - */ - switch (chip->state) { - case FL_ERASING: - if (!cfi->cmdset_priv || - !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) - goto sleep; /* We don't support erase suspend */ - - cfi_write (map, CMD(0xb0), cmd_addr); - /* If the flash has finished erasing, then 'erase suspend' - * appears to make some (28F320) flash devices switch to - * 'read' mode. Make sure that we switch to 'read status' - * mode so we get the right data. --rmk - */ - cfi_write(map, CMD(0x70), cmd_addr); - chip->oldstate = FL_ERASING; - chip->state = FL_ERASE_SUSPENDING; - // printk("Erase suspending at 0x%lx\n", cmd_addr); - for (;;) { - status = cfi_read(map, cmd_addr); - if ((status & status_OK) == status_OK) - break; - - if (time_after(jiffies, timeo)) { - /* Urgh */ - cfi_write(map, CMD(0xd0), cmd_addr); - /* make sure we're in 'read status' mode */ - cfi_write(map, CMD(0x70), cmd_addr); - chip->state = FL_ERASING; - spin_unlock(chip->mutex); - printk(KERN_ERR "Chip not ready after erase " - "suspended: status = 0x%llx\n", (__u64)status); - return -EIO; - } - - spin_unlock(chip->mutex); - cfi_udelay(1); - spin_lock(chip->mutex); - } - - suspended = 1; + if (chip->state != FL_POINT && chip->state != FL_READY) { cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; - break; - -#if 0 - case FL_WRITING: - /* Not quite yet */ -#endif - - case FL_READY: - case FL_POINT: - break; - - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - cfi_write(map, CMD(0x70), cmd_addr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, cmd_addr); - if ((status & status_OK) == status_OK) { - cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; - break; - } - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; - default: - sleep: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + chip->state = FL_READY; } - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); - if (suspended) { - chip->state = chip->oldstate; - /* What if one interleaved chip has finished and the - other hasn't? The old code would leave the finished - one in READY mode. That's bad, and caused -EROFS - errors to be returned from do_erase_oneblock because - that's the only bit it checked for at the time. - As the state machine appears to explicitly allow - sending the 0x70 (Read Status) command to an erasing - chip and expecting it to be ignored, that's what we - do. */ - cfi_write(map, CMD(0xd0), cmd_addr); - cfi_write(map, CMD(0x70), cmd_addr); - } + put_chip(map, chip, cmd_addr); - wake_up(&chip->wq); spin_unlock(chip->mutex); return 0; } @@ -640,70 +649,52 @@ { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int ofs_factor = cfi->interleave * cfi->device_type; - int count=len; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; struct flchip *chip; - int chip_num,offst; - unsigned long timeo; - DECLARE_WAITQUEUE(wait, current); + int ofs_factor = cfi->interleave * cfi->device_type; + int count = len; + int chip_num, offst; + int ret; - chip=0; + chip_num = ((unsigned int)from/reg_sz); + offst = from - (reg_sz*chip_num)+base_offst; + + while (count) { /* Calculate which chip & protection register offset we need */ - chip_num=((unsigned int)from/reg_sz); - offst=from-(reg_sz*chip_num)+base_offst; - while(count){ - - if(chip_num>=cfi->numchips) + if (chip_num >= cfi->numchips) goto out; - /* Make sure that the chip is in the right state */ - - timeo = jiffies + HZ; - chip=&cfi->chips[chip_num]; - retry: - spin_lock(chip->mutex); - - switch (chip->state) { - case FL_READY: - case FL_STATUS: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - break; + chip = &cfi->chips[chip_num]; - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); + if (ret) { spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + return (len-count)?:ret; } - - /* Now read the data required from this flash */ - - cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL); - while(count && ((offst-base_offst)read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); + + if (chip->state != FL_JEDEC_QUERY) { + cfi_write(map, CMD(0x90), chip->start); + chip->state = FL_JEDEC_QUERY; + } + + while (count && ((offst-base_offst) < reg_sz)) { + *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); buf++; offst++; count--; } - - chip->state=FL_CFI_QUERY; + + put_chip(map, chip, chip->start); spin_unlock(chip->mutex); + /* Move on to the next chip */ chip_num++; - offst=base_offst; - + offst = base_offst; } out: - wake_up(&chip->wq); return len-count; } @@ -749,103 +740,20 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum) { struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; cfi_word status, status_OK; unsigned long timeo; - DECLARE_WAITQUEUE(wait, current); - int z, suspended=0, ret=0; + int z, ret=0; adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; - retry: spin_lock(chip->mutex); - - /* Check that the chip's ready to talk to us. - * Later, we can actually think about interrupting it - * if it's in FL_ERASING state. - * Not just yet, though. - */ - switch (chip->state) { - case FL_READY: - break; - - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in read\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ + ret = get_chip(map, chip, adr, FL_WRITING); + if (ret) { spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; - - case FL_ERASING: - if (!extp || - !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1))) - goto sleep; /* We don't support erase suspend */ - - cfi_write (map, CMD(0xb0), adr); - - /* If the flash has finished erasing, then 'erase suspend' - * appears to make some (28F320) flash devices switch to - * 'read' mode. Make sure that we switch to 'read status' - * mode so we get the right data. --rmk - */ - cfi_write(map, CMD(0x70), adr); - chip->oldstate = FL_ERASING; - chip->state = FL_ERASE_SUSPENDING; - for (;;) { - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - if (time_after(jiffies, timeo)) { - /* Urgh */ - cfi_write(map, CMD(0xd0), adr); - /* make sure we're in 'read status' mode */ - cfi_write(map, CMD(0x70), adr); - chip->state = FL_ERASING; - spin_unlock(chip->mutex); - printk(KERN_ERR "Chip not ready after erase " - "suspended: status = 0x%x\n", status); - return -EIO; - } - - spin_unlock(chip->mutex); - cfi_udelay(1); - spin_lock(chip->mutex); - } - suspended = 1; - chip->state = FL_STATUS; - break; - - default: - sleep: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + return ret; } ENABLE_VPP(map); @@ -862,6 +770,8 @@ for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock(chip->mutex); @@ -879,7 +789,6 @@ /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; - DISABLE_VPP(map); printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); ret = -EIO; goto out; @@ -908,27 +817,11 @@ /* put back into read status register mode */ cfi_write(map, CMD(0x70), adr); ret = -EROFS; - goto out; } out: - if (suspended) { - chip->state = chip->oldstate; - /* What if one interleaved chip has finished and the - other hasn't? The old code would leave the finished - one in READY mode. That's bad, and caused -EROFS - errors to be returned from do_erase_oneblock because - that's the only bit it checked for at the time. - As the state machine appears to explicitly allow - sending the 0x70 (Read Status) command to an erasing - chip and expecting it to be ignored, that's what we - do. */ - cfi_write(map, CMD(0xd0), adr); - cfi_write(map, CMD(0x70), adr); - } else - DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */ - - wake_up(&chip->wq); + put_chip(map, chip, adr); spin_unlock(chip->mutex); + return ret; } @@ -1059,11 +952,9 @@ unsigned long adr, const u_char *buf, int len) { struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; cfi_word status, status_OK; unsigned long cmd_adr, timeo; - DECLARE_WAITQUEUE(wait, current); - int wbufsize, z, suspended=0, ret=0; + int wbufsize, z, ret=0, bytes, words; wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; adr += chip->start; @@ -1072,91 +963,18 @@ /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; - retry: spin_lock(chip->mutex); + ret = get_chip(map, chip, cmd_adr, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } - /* Check that the chip's ready to talk to us. - * Later, we can actually think about interrupting it - * if it's in FL_ERASING state. - * Not just yet, though. - */ - switch (chip->state) { - case FL_READY: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: + if (chip->state != FL_STATUS) cfi_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, cmd_adr); - if ((status & status_OK) == status_OK) - break; - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; - case FL_ERASING: - if (!extp || - !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1))) - goto sleep; /* We don't support erase suspend */ - - cfi_write (map, CMD(0xb0), adr); + status = cfi_read(map, cmd_adr); - /* If the flash has finished erasing, then 'erase suspend' - * appears to make some (28F320) flash devices switch to - * 'read' mode. Make sure that we switch to 'read status' - * mode so we get the right data. --rmk - */ - cfi_write(map, CMD(0x70), adr); - chip->oldstate = FL_ERASING; - chip->state = FL_ERASE_SUSPENDING; - for (;;) { - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - if (time_after(jiffies, timeo)) { - /* Urgh */ - cfi_write(map, CMD(0xd0), adr); - /* make sure we're in 'read status' mode */ - cfi_write(map, CMD(0x70), adr); - chip->state = FL_ERASING; - spin_unlock(chip->mutex); - printk(KERN_ERR "Chip not ready after erase " - "suspended: status = 0x%x\n", status); - return -EIO; - } - - spin_unlock(chip->mutex); - cfi_udelay(1); - spin_lock(chip->mutex); - } - suspended = 1; - chip->state = FL_STATUS; - break; - - default: - sleep: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; - } - /* We know we're now in FL_STATUS mode, and 'status' is current */ /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise @@ -1185,7 +1003,6 @@ /* Argh. Not ready for write to buffer */ cfi_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; - DISABLE_VPP(map); printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr)); /* Odd. Clear status bits */ cfi_write(map, CMD(0x50), cmd_adr); @@ -1196,20 +1013,42 @@ } /* Write length of data to come */ - cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr ); + bytes = len & (CFIDEV_BUSWIDTH-1); + words = len / CFIDEV_BUSWIDTH; + cfi_write(map, CMD(words - !bytes), cmd_adr ); /* Write data */ - for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { + z = 0; + while(z < words * CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { - map->write8 (map, *((__u8*)buf)++, adr+z); + map_write8 (map, *((__u8*)buf)++, adr+z); } else if (cfi_buswidth_is_2()) { - map->write16 (map, *((__u16*)buf)++, adr+z); + map_write16 (map, *((__u16*)buf)++, adr+z); } else if (cfi_buswidth_is_4()) { - map->write32 (map, *((__u32*)buf)++, adr+z); + map_write32 (map, *((__u32*)buf)++, adr+z); } else if (cfi_buswidth_is_8()) { - map->write64 (map, *((__u64*)buf)++, adr+z); + map_write64 (map, *((__u64*)buf)++, adr+z); + } else { + ret = -EINVAL; + goto out; + } + z += CFIDEV_BUSWIDTH; + } + if (bytes) { + int i = 0, n = 0; + u_char tmp_buf[8], *tmp_p = tmp_buf; + + while (bytes--) + tmp_buf[i++] = buf[n++]; + while (i < CFIDEV_BUSWIDTH) + tmp_buf[i++] = 0xff; + if (cfi_buswidth_is_2()) { + map_write16 (map, *((__u16*)tmp_p)++, adr+z); + } else if (cfi_buswidth_is_4()) { + map_write32 (map, *((__u32*)tmp_p)++, adr+z); + } else if (cfi_buswidth_is_8()) { + map_write64 (map, *((__u64*)tmp_p)++, adr+z); } else { - DISABLE_VPP(map); ret = -EINVAL; goto out; } @@ -1227,6 +1066,7 @@ for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock(chip->mutex); @@ -1244,7 +1084,6 @@ /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; - DISABLE_VPP(map); printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); ret = -EIO; goto out; @@ -1265,7 +1104,8 @@ chip->buffer_write_time++; /* Done and happy. */ - chip->state = FL_STATUS; + chip->state = FL_STATUS; + /* check for lock bit */ if (status & CMD(0x02)) { /* clear status */ @@ -1273,26 +1113,10 @@ /* put back into read status register mode */ cfi_write(map, CMD(0x70), adr); ret = -EROFS; - goto out; } - out: - if (suspended) { - chip->state = chip->oldstate; - /* What if one interleaved chip has finished and the - other hasn't? The old code would leave the finished - one in READY mode. That's bad, and caused -EROFS - errors to be returned from do_erase_oneblock because - that's the only bit it checked for at the time. - As the state machine appears to explicitly allow - sending the 0x70 (Read Status) command to an erasing - chip and expecting it to be ignored, that's what we - do. */ - cfi_write(map, CMD(0xd0), adr); - cfi_write(map, CMD(0x70), adr); - } else - DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */ - wake_up(&chip->wq); + out: + put_chip(map, chip, cmd_adr); spin_unlock(chip->mutex); return ret; } @@ -1336,12 +1160,12 @@ } /* Write buffer is worth it only if more than one word to write... */ - while(len > CFIDEV_BUSWIDTH) { + while(len) { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) - size = len & ~(CFIDEV_BUSWIDTH-1); + size = len; ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size); if (ret) @@ -1359,17 +1183,6 @@ return 0; } } - - /* ... and write the remaining bytes */ - if (len > 0) { - size_t local_retlen; - ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift), - len, &local_retlen, buf); - if (ret) - return ret; - (*retlen) += local_retlen; - } - return 0; } @@ -1479,45 +1292,12 @@ /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; -retry: + retry: spin_lock(chip->mutex); - - /* Check that the chip's ready to talk to us. */ - switch (chip->state) { - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - case FL_READY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in erase\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; - - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); + ret = get_chip(map, chip, adr, FL_ERASING); + if (ret) { spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + return ret; } ENABLE_VPP(map); @@ -1528,7 +1308,7 @@ cfi_write(map, CMD(0x20), adr); cfi_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; - chip->oldstate = 0; + chip->erase_suspended = 0; spin_unlock(chip->mutex); set_current_state(TASK_UNINTERRUPTIBLE); @@ -1550,11 +1330,11 @@ spin_lock(chip->mutex); continue; } - if (chip->oldstate) { + if (chip->erase_suspended) { /* This erase was suspended and resumed. Adjust the timeout */ timeo = jiffies + (HZ*20); /* FIXME */ - chip->oldstate = 0; + chip->erase_suspended = 0; } status = cfi_read(map, adr); @@ -1658,39 +1438,22 @@ int i; struct flchip *chip; int ret = 0; - DECLARE_WAITQUEUE(wait, current); for (i=0; !ret && inumchips; i++) { chip = &cfi->chips[i]; - retry: spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_SYNCING); - switch(chip->state) { - case FL_READY: - case FL_STATUS: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: + if (!ret) { chip->oldstate = chip->state; chip->state = FL_SYNCING; /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ - case FL_SYNCING: - spin_unlock(chip->mutex); - break; - - default: - /* Not an idle state */ - add_wait_queue(&chip->wq, &wait); - - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - - goto retry; } + spin_unlock(chip->mutex); } /* Unlock the chips again */ @@ -1731,52 +1494,18 @@ struct cfi_private *cfi = map->fldrv_priv; cfi_word status, status_OK; unsigned long timeo = jiffies + HZ; - DECLARE_WAITQUEUE(wait, current); + int ret; adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; -retry: spin_lock(chip->mutex); - - /* Check that the chip's ready to talk to us. */ - switch (chip->state) { - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - case FL_READY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock(chip->mutex); - printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); - goto retry; - - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); + ret = get_chip(map, chip, adr, FL_LOCKING); + if (ret) { spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + return ret; } ENABLE_VPP(map); @@ -1823,8 +1552,7 @@ /* Done and happy. */ chip->state = FL_STATUS; - DISABLE_VPP(map); - wake_up(&chip->wq); + put_chip(map, chip, adr); spin_unlock(chip->mutex); return 0; } @@ -1889,22 +1617,23 @@ spin_lock(chip->mutex); - switch(chip->state) { + switch (chip->state) { case FL_READY: case FL_STATUS: case FL_CFI_QUERY: case FL_JEDEC_QUERY: - chip->oldstate = chip->state; - chip->state = FL_PM_SUSPENDED; - /* No need to wake_up() on this state change - - * as the whole point is that nobody can do anything - * with the chip now anyway. - */ - case FL_PM_SUSPENDED: + if (chip->oldstate == FL_READY) { + chip->oldstate = chip->state; + chip->state = FL_PM_SUSPENDED; + /* No need to wake_up() on this state change - + * as the whole point is that nobody can do anything + * with the chip now anyway. + */ + } break; - default: ret = -EAGAIN; + case FL_PM_SUSPENDED: break; } spin_unlock(chip->mutex); diff -Nru a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c --- a/drivers/mtd/chips/cfi_cmdset_0002.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/cfi_cmdset_0002.c Thu Dec 4 16:24:25 2003 @@ -6,16 +6,22 @@ * * 2_by_8 routines added by Simon Munton * + * 4_by_16 work by Carolyn J. Smith + * + * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com + * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.62 2003/01/24 23:30:13 dwmw2 Exp $ + * $Id: cfi_cmdset_0002.c,v 1.93 2003/11/20 08:39:35 dwmw2 Exp $ * */ +#include #include #include #include #include +#include #include #include @@ -23,16 +29,50 @@ #include #include #include +#include #include +#include #include #define AMD_BOOTLOC_BUG +#define FORCE_WORD_WRITE 0 + + +/* + * This is an attempt to coalesce the retry logic in one place - that way + * there aren't #ifdefs scattered throughout. + */ +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + +#ifndef CONFIG_MTD_CFI_AMDSTD_RETRY_MAX +#define CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0 +#endif + +#define RETRY_CMD_LABEL retry_cmd: do {} while (0) +#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, retry_cmd_cnt, adr, datum, prev_oldstatus, prev_status, oldstatus, status) +static int retry_cmd_max = CONFIG_MTD_CFI_AMDSTD_RETRY_MAX; +#define DECLARE_RETRY_CMD_CNT() int retry_cmd_cnt = 0 +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY +#define CHECK_RETRIES() do { if (++retry_cmd_cnt <= retry_cmd_max) goto retry_cmd; } while (0) +#endif + +#else + +#define RETRY_CMD_LABEL do {} while (0) +#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, adr, datum, prev_oldstatus, prev_status, oldstatus, status) +#define DECLARE_RETRY_CMD_CNT() +#define CHECK_RETRIES() + +#endif /* !defined(CONFIG_MTD_CFI_AMDSTD_RETRY) */ + static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); -static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *); static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); +static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t); +static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t); static void cfi_amdstd_sync (struct mtd_info *); static int cfi_amdstd_suspend (struct mtd_info *); static void cfi_amdstd_resume (struct mtd_info *); @@ -45,55 +85,136 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { - probe: NULL, /* Not usable directly */ - destroy: cfi_amdstd_destroy, - name: "cfi_cmdset_0002", - module: THIS_MODULE + .probe = NULL, /* Not usable directly */ + .destroy = cfi_amdstd_destroy, + .name = "cfi_cmdset_0002", + .module = THIS_MODULE }; + +/* #define DEBUG_LOCK_BITS */ +/* #define DEBUG_CFI_FEATURES */ + + +#ifdef DEBUG_CFI_FEATURES +static void cfi_tell_features(struct cfi_pri_amdstd *extp) +{ + const char* erase_suspend[3] = { + "Not supported", "Read only", "Read/write" + }; + const char* top_bottom[6] = { + "No WP", "8x8KiB sectors at top & bottom, no WP", + "Bottom boot", "Top boot", + "Uniform, Bottom WP", "Uniform, Top WP" + }; + + printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); + printk(" Address sensitive unlock: %s\n", + (extp->SiliconRevision & 1) ? "Not required" : "Required"); + + if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) + printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]); + else + printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend); + + if (extp->BlkProt == 0) + printk(" Block protection: Not supported\n"); + else + printk(" Block protection: %d sectors per group\n", extp->BlkProt); + + + printk(" Temporary block unprotect: %s\n", + extp->TmpBlkUnprotect ? "Supported" : "Not supported"); + printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot); + printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps); + printk(" Burst mode: %s\n", + extp->BurstMode ? "Supported" : "Not supported"); + if (extp->PageMode == 0) + printk(" Page mode: Not supported\n"); + else + printk(" Page mode: %d word page\n", extp->PageMode << 2); + + printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", + extp->VppMin >> 4, extp->VppMin & 0xf); + printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", + extp->VppMax >> 4, extp->VppMax & 0xf); + + if (extp->TopBottom < ARRAY_SIZE(top_bottom)) + printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]); + else + printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom); +} +#endif + +#ifdef AMD_BOOTLOC_BUG +/* Wheee. Bring me the head of someone at AMD. */ +static void fixup_amd_bootblock(struct map_info *map, void* param) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + __u8 major = extp->MajorVersion; + __u8 minor = extp->MinorVersion; + + if (((major << 8) | minor) < 0x3131) { + /* CFI version 1.0 => don't trust bootloc */ + if (cfi->id & 0x80) { + printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id); + extp->TopBottom = 3; /* top boot */ + } else { + extp->TopBottom = 2; /* bottom boot */ + } + } +} +#endif + +static struct cfi_fixup fixup_table[] = { +#ifdef AMD_BOOTLOC_BUG + { + 0x0001, /* AMD */ + CFI_ID_ANY, + fixup_amd_bootblock, NULL + }, +#endif + { 0, 0, NULL, NULL } +}; + + struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; unsigned char bootloc; - int ofs_factor = cfi->interleave * cfi->device_type; int i; - __u8 major, minor; - __u32 base = cfi->chips[0].start; if (cfi->cfi_mode==CFI_MODE_CFI){ + /* + * It's a real CFI chip, not one for which the probe + * routine faked a CFI structure. So we read the feature + * table from it. + */ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; + struct cfi_pri_amdstd *extp; - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - - major = cfi_read_query(map, base + (adr+3)*ofs_factor); - minor = cfi_read_query(map, base + (adr+4)*ofs_factor); - - printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n", - major, minor, adr); - cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); - - cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); - cfi->mfr = cfi_read_query(map, base); - cfi->id = cfi_read_query(map, base + ofs_factor); + extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); + if (!extp) + return NULL; + + /* Install our own private info structure */ + cfi->cmdset_priv = extp; + + cfi_fixup(map, fixup_table); + +#ifdef DEBUG_CFI_FEATURES + /* Tell the user about it in lots of lovely detail */ + cfi_tell_features(extp); +#endif + + bootloc = extp->TopBottom; + if ((bootloc != 2) && (bootloc != 3)) { + printk(KERN_WARNING "%s: CFI does not contain boot " + "bank location. Assuming top.\n", map->name); + bootloc = 2; + } - /* Wheee. Bring me the head of someone at AMD. */ -#ifdef AMD_BOOTLOC_BUG - if (((major << 8) | minor) < 0x3131) { - /* CFI version 1.0 => don't trust bootloc */ - if (cfi->id & 0x80) { - printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id); - bootloc = 3; /* top boot */ - } else { - bootloc = 2; /* bottom boot */ - } - } else -#endif - { - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor); - } if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); @@ -106,28 +227,37 @@ cfi->cfiq->EraseRegionInfo[j] = swap; } } - switch (cfi->device_type) { - case CFI_DEVICETYPE_X8: - cfi->addr_unlock1 = 0x555; - cfi->addr_unlock2 = 0x2aa; - break; - case CFI_DEVICETYPE_X16: - cfi->addr_unlock1 = 0xaaa; - if (map->buswidth == cfi->interleave) { - /* X16 chip(s) in X8 mode */ - cfi->addr_unlock2 = 0x555; - } else { - cfi->addr_unlock2 = 0x554; + /* + * These might already be setup (more correctly) by + * jedec_probe.c - still need it for cfi_probe.c path. + */ + if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) { + switch (cfi->device_type) { + case CFI_DEVICETYPE_X8: + cfi->addr_unlock1 = 0x555; + cfi->addr_unlock2 = 0x2aa; + break; + case CFI_DEVICETYPE_X16: + cfi->addr_unlock1 = 0xaaa; + if (map->buswidth == cfi->interleave) { + /* X16 chip(s) in X8 mode */ + cfi->addr_unlock2 = 0x555; + } else { + cfi->addr_unlock2 = 0x554; + } + break; + case CFI_DEVICETYPE_X32: + cfi->addr_unlock1 = 0x1555; + cfi->addr_unlock2 = 0xaaa; + break; + default: + printk(KERN_WARNING + "MTD %s(): Unsupported device type %d\n", + __func__, cfi->device_type); + return NULL; } - break; - case CFI_DEVICETYPE_X32: - cfi->addr_unlock1 = 0x1555; - cfi->addr_unlock2 = 0xaaa; - break; - default: - printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type); - return NULL; } + } /* CFI mode */ for (i=0; i< cfi->numchips; i++) { @@ -138,23 +268,25 @@ map->fldrv = &cfi_amdstd_chipdrv; - cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); return cfi_amdstd_setup(map); } + static struct mtd_info *cfi_amdstd_setup(struct map_info *map) { struct cfi_private *cfi = map->fldrv_priv; struct mtd_info *mtd; unsigned long devsize = (1<cfiq->DevSize) * cfi->interleave; + unsigned long offset = 0; + int i,j; mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); printk(KERN_NOTICE "number of %s chips: %d\n", - (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); + (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); if (!mtd) { - printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); - goto setup_err; + printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); + goto setup_err; } memset(mtd, 0, sizeof(*mtd)); @@ -162,77 +294,81 @@ mtd->type = MTD_NORFLASH; /* Also select the correct geometry setup too */ mtd->size = devsize * cfi->numchips; - - if (cfi->cfiq->NumEraseRegions == 1) { - /* No need to muck about with multiple erase sizes */ - mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave; - } else { - unsigned long offset = 0; - int i,j; - mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { - printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); - goto setup_err; - } + mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; + mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) + * mtd->numeraseregions, GFP_KERNEL); + if (!mtd->eraseregions) { + printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); + goto setup_err; + } - for (i=0; icfiq->NumEraseRegions; i++) { - unsigned long ernum, ersize; - ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; - ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; + for (i=0; icfiq->NumEraseRegions; i++) { + unsigned long ernum, ersize; + ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; + ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; - if (mtd->erasesize < ersize) { - mtd->erasesize = ersize; - } - for (j=0; jnumchips; j++) { - mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; - mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; - mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; - } - offset += (ersize * ernum); - } - if (offset != devsize) { - /* Argh */ - printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - goto setup_err; + if (mtd->erasesize < ersize) { + mtd->erasesize = ersize; } + for (j=0; jnumchips; j++) { + mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; + mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; + mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; + } + offset += (ersize * ernum); + } + if (offset != devsize) { + /* Argh */ + printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); + goto setup_err; + } #if 0 - // debug - for (i=0; inumeraseregions;i++){ - printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].numblocks); - } -#endif + // debug + for (i=0; inumeraseregions;i++){ + printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", + i,mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); } +#endif switch (CFIDEV_BUSWIDTH) { case 1: case 2: case 4: -#if 1 - if (mtd->numeraseregions > 1) - mtd->erase = cfi_amdstd_erase_varsize; - else +#ifdef CFI_WORD_64 + case 8: #endif - if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) + if (mtd->numeraseregions == 1 + && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) { mtd->erase = cfi_amdstd_erase_chip; - else - mtd->erase = cfi_amdstd_erase_onesize; + } else { + mtd->erase = cfi_amdstd_erase_varsize; + mtd->lock = cfi_amdstd_lock_varsize; + mtd->unlock = cfi_amdstd_unlock_varsize; + } + + if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { + DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); + mtd->write = cfi_amdstd_write_buffers; + } else { + DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" ); + mtd->write = cfi_amdstd_write_words; + } + mtd->read = cfi_amdstd_read; - mtd->write = cfi_amdstd_write; break; default: - printk(KERN_WARNING "Unsupported buswidth\n"); + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); goto setup_err; break; } if (cfi->fast_prog) { - /* In cfi_amdstd_write() we frob the protection stuff + /* In cfi_amdstd_write_words() we frob the protection stuff without paying any attention to the state machine. This upsets in-progress erases. So we turn this flag off for now till the code gets fixed. */ @@ -266,7 +402,7 @@ mtd->flags = MTD_CAP_NORFLASH; map->fldrv = &cfi_amdstd_chipdrv; mtd->name = map->name; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; setup_err: @@ -280,46 +416,200 @@ return NULL; } -static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) + +/* This is more work to coalesce the retry #ifdefs in one location */ +static inline void handle_wacky_state(const char *func, +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + int retry_cmd_cnt, +#endif + unsigned long adr, + cfi_word datum, + cfi_word prev_oldstatus, + cfi_word prev_status, + cfi_word oldstatus, + cfi_word status) +{ +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + if ( retry_cmd_cnt == retry_cmd_max ) { +#endif + printk(KERN_WARNING + "MTD %s(): Wacky! Unable to decode failure status\n" + "Possible buggy device - try " +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + "increasing retry_cmd_max from %d\n" +#else + "enabling CONFIG_MTD_CFI_AMDSTD_RETRY\n" + "in your kernel config and setting driver retry_cmd_max\n" +#endif + , func +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + , retry_cmd_max +#endif + ); + + printk(KERN_WARNING + "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", + func, adr, datum, + prev_oldstatus, prev_status, + oldstatus, status); +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY + } +#endif +} + + +static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { DECLARE_WAITQUEUE(wait, current); - unsigned long timeo = jiffies + HZ; + struct cfi_private *cfi = map->fldrv_priv; + cfi_word status, oldstatus; + cfi_word dq6 = CMD(1<<6); + cfi_word dq2 = CMD(1<<2); + unsigned long timeo; + struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv; + resettime: + timeo = jiffies + HZ; retry: - cfi_spin_lock(chip->mutex); + switch (chip->state) { - if (chip->state != FL_READY){ -#if 0 - printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state); -#endif + case FL_STATUS: + for (;;) { + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + if (((oldstatus ^ status) & (dq6 | dq2)) == 0) + break; + + if (time_after(jiffies, timeo)) { + printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", + (long long)status); + cfi_spin_unlock(chip->mutex); + return -EIO; + } + cfi_spin_unlock(chip->mutex); + cfi_udelay(1); + cfi_spin_lock(chip->mutex); + /* Someone else might have been playing with it. */ + goto retry; + } + + case FL_READY: + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + return 0; + + case FL_ERASING: + if (!(mode == FL_READY || mode == FL_POINT + || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)) + || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)))) + goto sleep; + + /* Erase suspend */ + /* FIXME - is there a way to verify suspend? */ + cfi_write(map, CMD(0xB0), adr); + chip->oldstate = FL_ERASING; + chip->state = FL_ERASE_SUSPENDING; + chip->erase_suspended = 1; + for (;;) { + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + if (((oldstatus ^ status) & dq2) == dq2) + break; + + if (time_after(jiffies, timeo)) { + /* Urgh. Resume and pretend we weren't here. */ + /* FIXME - is there a way to verify resume? */ + cfi_write(map, CMD(0x30), adr); + chip->state = FL_ERASING; + chip->oldstate = FL_READY; + printk(KERN_ERR "Chip not ready after erase " + "suspended: status = 0x%x\n", status); + return -EIO; + } + + cfi_spin_unlock(chip->mutex); + cfi_udelay(1); + cfi_spin_lock(chip->mutex); + /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. + So we can just loop here. */ + } + chip->state = FL_STATUS; + return 0; + + case FL_POINT: + /* Only if there's no operation suspended... */ + if (mode == FL_READY && chip->oldstate == FL_READY) + return 0; + + default: + sleep: set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); - schedule(); remove_wait_queue(&chip->wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; -#endif - timeo = jiffies + HZ; + cfi_spin_lock(chip->mutex); + goto resettime; + } +} - goto retry; - } + +static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + + switch(chip->oldstate) { + case FL_ERASING: + chip->state = chip->oldstate; + cfi_write(map, CMD(0x30), adr); + chip->oldstate = FL_READY; + chip->state = FL_ERASING; + break; + + case FL_READY: + case FL_STATUS: + /* We should really make set_vpp() count, rather than doing this */ + DISABLE_VPP(map); + break; + default: + printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate); + } + wake_up(&chip->wq); +} + + +static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) +{ + unsigned long cmd_addr; + struct cfi_private *cfi = map->fldrv_priv; + int ret; adr += chip->start; - chip->state = FL_READY; + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); - map->copy_from(map, buf, adr, len); + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, cmd_addr, FL_READY); + if (ret) { + cfi_spin_unlock(chip->mutex); + return ret; + } - wake_up(&chip->wq); - cfi_spin_unlock(chip->mutex); + if (chip->state != FL_POINT && chip->state != FL_READY) { + cfi_write(map, CMD(0xf0), cmd_addr); + chip->state = FL_READY; + } + + map_copy_from(map, buf, adr, len); + put_chip(map, chip, cmd_addr); + + cfi_spin_unlock(chip->mutex); return 0; } + static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct map_info *map = mtd->priv; @@ -361,6 +651,7 @@ return ret; } + static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) { DECLARE_WAITQUEUE(wait, current); @@ -393,13 +684,15 @@ adr += chip->start; chip->state = FL_READY; - + + /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); + /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -454,125 +747,241 @@ return ret; } -static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast) + +static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast) { - unsigned long timeo = jiffies + HZ; - unsigned int oldstatus, status; - unsigned int dq6, dq5; struct cfi_private *cfi = map->fldrv_priv; - DECLARE_WAITQUEUE(wait, current); + unsigned long timeo = jiffies + HZ; + cfi_word oldstatus, status, prev_oldstatus, prev_status; + cfi_word dq6 = CMD(1<<6); + /* + * We use a 1ms + 1 jiffies generic timeout for writes (most devices + * have a max write time of a few hundreds usec). However, we should + * use the maximum timeout value given by the chip at probe time + * instead. Unfortunately, struct flchip does have a field for + * maximum timeout, only for typical which can be far too short + * depending of the conditions. The ' + 1' is to avoid having a + * timeout of 0 jiffies if HZ is smaller than 1000. + */ + unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; int ret = 0; + int ta = 0; + DECLARE_RETRY_CMD_CNT(); - retry: - cfi_spin_lock(chip->mutex); + adr += chip->start; - if (chip->state != FL_READY) { -#if 0 - printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state); -#endif - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_WRITING); + if (ret) { cfi_spin_unlock(chip->mutex); + return ret; + } - schedule(); - remove_wait_queue(&chip->wq, &wait); -#if 0 - printk(KERN_DEBUG "Wake up to write:\n"); - if(signal_pending(current)) - return -EINTR; -#endif - timeo = jiffies + HZ; - - goto retry; - } - - chip->state = FL_WRITING; + RETRY_CMD_LABEL; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n", + __func__, adr, datum ); + + /* + * Check for a NOP for the case when the datum to write is already + * present - it saves time and works around buggy chips that corrupt + * data at other locations when 0xff is written to a location that + * already contains 0xff. + */ + status = cfi_read(map, adr); + if (status == datum) { + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP 0x%.8x == 0x%.8x\n", + __func__, status, datum ); + goto op_done; + } - adr += chip->start; ENABLE_VPP(map); if (fast) { /* Unlock bypass */ cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL); + } else { + /* + * The CFI_DEVICETYPE_X8 argument is needed even when + * cfi->device_type != CFI_DEVICETYPE_X8. The addresses for + * command sequences don't scale even when the device is + * wider. This is the case for many of the cfi_send_gen_cmd() + * below. I'm not sure, however, why some use + * cfi->device_type. + */ + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); } - else { - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - } - cfi_write(map, datum, adr); + chip->state = FL_WRITING; cfi_spin_unlock(chip->mutex); cfi_udelay(chip->word_write_time); cfi_spin_lock(chip->mutex); - /* Polling toggle bits instead of reading back many times - This ensures that write operation is really completed, - or tells us why it failed. */ - dq6 = CMD(1<<6); - dq5 = CMD(1<<5); - timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */ - - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); - - while( (status & dq6) != (oldstatus & dq6) && - (status & dq5) != dq5 && - !time_after(jiffies, timeo) ) { + /* + * Polling toggle bits instead of reading back many times This ensures + * that write operation is really completed, or tells us why it + * failed. + * + * It may appear that the polling and decoding of error state might be + * simplified. Don't do it unless you really know what you are doing. + * + * You must remember that JESD21-C 3.5.3 states that the status must + * be read back an _additional_ two times before a failure is + * determined. This is because these devices have internal state + * machines that are asynchronous to the external data bus. During an + * erase or write the read-back status of the polling bits might be + * transitioning internaly when the external read-back occurs. This + * means that the bits aren't in the final state and they might appear + * to report an error as they are in a transient state: dq7 is + * asynchronous with dq6 and other status bits. + * + * This asynchronous behaviour can cause infrequent errors that will + * usually disappear the next time an erase or write happens (Try + * tracking those errors down!). To ensure that the bits are not in + * transition, the location must be read-back two more times and + * compared against what was written - BOTH reads MUST match what was + * written. Don't think this can be simplified to only the last read + * matching the datum written: status bits *can* match the datum + * written. + * + * If the final comparison fails, error state can *then* be decoded. + * + * - Thayne Harbaugh + */ + /* See comment above for timeout value. */ + timeo = jiffies + uWriteTimeout; + for (;;) { + if (chip->state != FL_WRITING) { + /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); - if (need_resched()) { + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); cfi_spin_unlock(chip->mutex); - yield(); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ / 2); /* FIXME */ cfi_spin_lock(chip->mutex); - } else - udelay(1); + continue; + } - oldstatus = cfi_read( map, adr ); - status = cfi_read( map, adr ); + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + /* + * This only checks if dq6 is still toggling and that our + * timer hasn't expired. We purposefully ignore the chip's + * internal timer that will assert dq5 and leave dq6 toggling. + * This is done for a variety of reasons: + * + * 1) Not all chips support dq5. + * + * 2) Dealing with asynchronous status bit and data updates + * and reading a device two more times creates _messy_ logic + * when trying to deal with interleaved devices - some may be + * changing while others are still busy. + * + * 3) Checking dq5 only helps to optimize an error case that + * should at worst be infrequent and at best non-existent. + * + * If our timeout occurs _then_ we will check dq5 to see if + * the device also had an internal timeout. + */ + if ( (((status ^ oldstatus) & dq6) == 0) + || ( ta = time_after(jiffies, timeo)) ) + break; + + /* Latency issues. Drop the lock, wait a while and retry */ + cfi_spin_unlock(chip->mutex); + cfi_udelay(1); + cfi_spin_lock(chip->mutex); } - - if( (status & dq6) != (oldstatus & dq6) ) { - /* The erasing didn't stop?? */ - if( (status & dq5) == dq5 ) { - /* When DQ5 raises, we must check once again - if DQ6 is toggling. If not, the erase has been - completed OK. If not, reset chip. */ - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); - - if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) { - printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" ); - } else { - /* DQ5 is active so we can do a reset and stop the erase */ - cfi_write(map, CMD(0xF0), chip->start); - printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" ); - } + + /* + * Something kicked us out of the read-back loop. We'll check success + * befor checking failure. Even though dq6 might be true data, it is + * unkown if all of the other bits have changed to true data due to + * the asynchronous nature of the internal state machine. We will + * read two more times and use this to either verify that the write + * completed successfully or that something really went wrong. BOTH + * reads must match what was written - this certifies that bits aren't + * still changing and that the status bits erroneously match the datum + * that was written. + */ + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( oldstatus == datum && status == datum ) { + /* success - do nothing */ + goto op_done; + } + + if ( ta ) { + /* Only check dq5 on the chips that are still toggling. */ + cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n", + __func__, + status & dq5mask, status, datum ); } else { - printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword."); - - chip->state = FL_READY; - wake_up(&chip->wq); - cfi_spin_unlock(chip->mutex); - DISABLE_VPP(map); - ret = -EIO; + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); } + goto op_failed; } - DISABLE_VPP(map); + /* + * If we get to here then it means that something + * is wrong and it's not a timeout. Something + * is seriously wacky! Dump some debug info. + */ + /* + * Found a clue about the chips that reach this state. + * Some flash chips (SST >cough<) + * are horribly broken. They do not ignore traffic that is + * destined to other devices. This happens because some solutions + * are on shared busses, the erase and program sequences have + * have multiple commands, and the sequence is interspersed with + * commands destined to other devices. A good flash chip will + * examine the command and destination address and will ignore + * commands that are for other devices. + */ + HANDLE_WACKY_STATE(); + + op_failed: + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + CHECK_RETRIES(); + ret = -EIO; + + op_done: chip->state = FL_READY; - wake_up(&chip->wq); + put_chip(map, chip, adr); cfi_spin_unlock(chip->mutex); return ret; } -static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) + +static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int ret = 0; int chipnum; unsigned long ofs, chipstart; + DECLARE_WAITQUEUE(wait, current); *retlen = 0; if (!len) @@ -587,23 +996,56 @@ unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); int i = ofs - bus_ofs; int n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; - map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); - while (len && i < CFIDEV_BUSWIDTH) - tmp_buf[i++] = buf[n++], len--; + retry: + cfi_spin_lock(cfi->chips[chipnum].mutex); + if (cfi->chips[chipnum].state != FL_READY) { +#if 0 + printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); +#endif + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&cfi->chips[chipnum].wq, &wait); + + cfi_spin_unlock(cfi->chips[chipnum].mutex); + + schedule(); + remove_wait_queue(&cfi->chips[chipnum].wq, &wait); +#if 0 + if(signal_pending(current)) + return -EINTR; +#endif + goto retry; + } + + map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); + + cfi_spin_unlock(cfi->chips[chipnum].mutex); + + while (len && i < CFIDEV_BUSWIDTH) { + tmp_buf[i++] = buf[n++]; + len--; + } + + /* already know that buswidth > 1 */ if (cfi_buswidth_is_2()) { datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)tmp_buf; +#endif } else { - return -EINVAL; /* should never happen, but be safe */ + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + return -EINVAL; } ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum, 0); + bus_ofs, datum, 0); if (ret) return ret; @@ -628,7 +1070,7 @@ /* We are now aligned, write as much as possible */ while(len >= CFIDEV_BUSWIDTH) { - __u32 datum; + cfi_word datum; if (cfi_buswidth_is_1()) { datum = *(__u8*)buf; @@ -636,7 +1078,13 @@ datum = *(__u16*)buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)buf; +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)buf; +#endif } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); return -EINVAL; } ret = do_write_oneword(map, &cfi->chips[chipnum], @@ -685,10 +1133,34 @@ /* Write the trailing bytes if any */ if (len & (CFIDEV_BUSWIDTH-1)) { int i = 0, n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; + + retry1: + cfi_spin_lock(cfi->chips[chipnum].mutex); + + if (cfi->chips[chipnum].state != FL_READY) { +#if 0 + printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); +#endif + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&cfi->chips[chipnum].wq, &wait); + + cfi_spin_unlock(cfi->chips[chipnum].mutex); + + schedule(); + remove_wait_queue(&cfi->chips[chipnum].wq, &wait); +#if 0 + if(signal_pending(current)) + return -EINTR; +#endif + goto retry1; + } + + map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); + + cfi_spin_unlock(cfi->chips[chipnum].mutex); - map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); while (len--) tmp_buf[i++] = buf[n++]; @@ -696,8 +1168,14 @@ datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)tmp_buf; +#endif } else { - return -EINVAL; /* should never happen, but be safe */ + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + return -EINVAL; } ret = do_write_oneword(map, &cfi->chips[chipnum], @@ -711,289 +1189,445 @@ return 0; } -static inline int do_erase_chip(struct map_info *map, struct flchip *chip) + +/* + * FIXME: interleaved mode not tested, and probably not supported! + */ +static inline int do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const u_char *buf, int len) { - unsigned int oldstatus, status; - unsigned int dq6, dq5; - unsigned long timeo = jiffies + HZ; - unsigned int adr; struct cfi_private *cfi = map->fldrv_priv; - DECLARE_WAITQUEUE(wait, current); + unsigned long timeo = jiffies + HZ; + cfi_word oldstatus, status, prev_oldstatus, prev_status; + cfi_word dq6 = CMD(1<<6); + /* see comments in do_write_oneword() regarding uWriteTimeo. */ + static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; + int ret = -EIO; + int ta = 0; + unsigned long cmd_adr; + int z, bytes, words; + cfi_word datum; + DECLARE_RETRY_CMD_CNT(); - retry: - cfi_spin_lock(chip->mutex); + adr += chip->start; + cmd_adr = adr; - if (chip->state != FL_READY){ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_WRITING); + if (ret) { cfi_spin_unlock(chip->mutex); + return ret; + } - schedule(); - remove_wait_queue(&chip->wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; + if (cfi_buswidth_is_1()) { + datum = *(__u8*)buf; + } else if (cfi_buswidth_is_2()) { + datum = *(__u16*)buf; + } else if (cfi_buswidth_is_4()) { + datum = *(__u32*)buf; +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)buf; #endif - timeo = jiffies + HZ; + } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + return -EINVAL; + } - goto retry; - } + RETRY_CMD_LABEL; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n", + __func__, adr, datum ); - chip->state = FL_ERASING; - - /* Handle devices with one erase region, that only implement - * the chip erase command. - */ ENABLE_VPP(map); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - timeo = jiffies + (HZ*20); - adr = cfi->addr_unlock1; + //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - /* Wait for the end of programing/erasure by using the toggle method. - * As long as there is a programming procedure going on, bit 6 of the last - * written byte is toggling it's state with each consectuve read. - * The toggling stops as soon as the procedure is completed. - * - * If the process has gone on for too long on the chip bit 5 gets. - * After bit5 is set you can kill the operation by sending a reset - * command to the chip. - */ - dq6 = CMD(1<<6); - dq5 = CMD(1<<5); + /* Write Buffer Load */ + cfi_write(map, CMD(0x25), cmd_adr); - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); - while( ((status & dq6) != (oldstatus & dq6)) && - ((status & dq5) != dq5) && - !time_after(jiffies, timeo)) { - int wait_reps; + chip->state = FL_WRITING_TO_BUFFER; - /* an initial short sleep */ - cfi_spin_unlock(chip->mutex); - schedule_timeout(HZ/100); - cfi_spin_lock(chip->mutex); + /* Write length of data to come */ + bytes = len & (CFIDEV_BUSWIDTH-1); + words = len / CFIDEV_BUSWIDTH; + cfi_write(map, CMD(words - !bytes), cmd_adr ); + /* Write data */ + z = 0; + while(z < words * CFIDEV_BUSWIDTH) { + if (cfi_buswidth_is_1()) { + datum = *((__u8*)buf); + map_write8 (map, *((__u8*)buf)++, adr+z); + } else if (cfi_buswidth_is_2()) { + datum = *((__u16*)buf); + map_write16 (map, *((__u16*)buf)++, adr+z); + } else if (cfi_buswidth_is_4()) { + datum = *((__u32*)buf); + map_write32 (map, *((__u32*)buf)++, adr+z); +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *((__u64*)buf); + map_write64 (map, *((__u64*)buf)++, adr+z); +#endif + } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + ret = -EINVAL; + goto op_failed; + } + z += CFIDEV_BUSWIDTH; + } + if (bytes) { + int i = 0, n = 0; + u_char tmp_buf[8], *tmp_p = tmp_buf; + + while (bytes--) + tmp_buf[i++] = buf[n++]; + while (i < CFIDEV_BUSWIDTH) + tmp_buf[i++] = 0xff; + if (cfi_buswidth_is_2()) { + datum = *((__u16*)tmp_p); + map_write16 (map, *((__u16*)tmp_p)++, adr+z); + } else if (cfi_buswidth_is_4()) { + datum = *((__u32*)tmp_p); + map_write32 (map, *((__u32*)tmp_p)++, adr+z); +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + datum = *((__u64*)tmp_p); + map_write64 (map, *((__u64*)tmp_p)++, adr+z); +#endif + } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + ret = -EINVAL; + goto op_failed; + } + } else if (words > 0) { + z -= CFIDEV_BUSWIDTH; + } + + adr += z; + + /* Write Buffer Program Confirm: GO GO GO */ + cfi_write(map, CMD(0x29), cmd_adr); + chip->state = FL_WRITING; + + cfi_spin_unlock(chip->mutex); + cfi_udelay(chip->buffer_write_time); + cfi_spin_lock(chip->mutex); + + timeo = jiffies + uWriteTimeout; - if (chip->state != FL_ERASING) { - /* Someone's suspended the erase. Sleep */ + for (;;) { + if (chip->state != FL_WRITING) { + /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); - printk("erase suspended. Sleeping\n"); - schedule(); remove_wait_queue(&chip->wq, &wait); -#if 0 - if (signal_pending(current)) - return -EINTR; -#endif - timeo = jiffies + (HZ*2); /* FIXME */ + timeo = jiffies + (HZ / 2); /* FIXME */ cfi_spin_lock(chip->mutex); continue; } - /* Busy wait for 1/10 of a milisecond */ - for(wait_reps = 0; - (wait_reps < 100) && - ((status & dq6) != (oldstatus & dq6)) && - ((status & dq5) != dq5); - wait_reps++) { - - /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - - cfi_udelay(1); - - cfi_spin_lock(chip->mutex); - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); - } oldstatus = cfi_read(map, adr); status = cfi_read(map, adr); - } - if ((status & dq6) != (oldstatus & dq6)) { - /* The erasing didn't stop?? */ - if ((status & dq5) == dq5) { - /* dq5 is active so we can do a reset and stop the erase */ - cfi_write(map, CMD(0xF0), chip->start); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + /* See comments in do_write_oneword() about checking status */ + if ( (((status ^ oldstatus) & dq6) == 0) + || ( ta = time_after(jiffies, timeo)) ) { + break; } - chip->state = FL_READY; - wake_up(&chip->wq); + + /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); - printk("waiting for erase to complete timed out."); - DISABLE_VPP(map); - return -EIO; + cfi_udelay(1); + cfi_spin_lock(chip->mutex); } - DISABLE_VPP(map); + + /* See comments in do_write_oneword() about "two more checks" */ + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( oldstatus == datum && status == datum ) { + /* success - do nothing */ + goto op_done; + } + + if ( ta ) { + /* Only check dq5 on the chips that are still toggling. */ + cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n", + __func__, + status & dq5mask, status, datum ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); + } + goto op_failed; + } + + HANDLE_WACKY_STATE(); + + op_failed: + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + CHECK_RETRIES(); + ret = -EIO; + + op_done: chip->state = FL_READY; - wake_up(&chip->wq); + put_chip(map, chip, adr); cfi_spin_unlock(chip->mutex); + return ret; +} + + +static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; + int ret = 0; + int chipnum; + unsigned long ofs; + + *retlen = 0; + if (!len) + return 0; + + chipnum = to >> cfi->chipshift; + ofs = to - (chipnum << cfi->chipshift); + + /* If it's not bus-aligned, do the first word write */ + if (ofs & (CFIDEV_BUSWIDTH-1)) { + size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1); + if (local_len > len) + local_len = len; + ret = cfi_amdstd_write_words(mtd, to, local_len, + retlen, buf); + if (ret) + return ret; + ofs += local_len; + buf += local_len; + len -= local_len; + + if (ofs >> cfi->chipshift) { + chipnum ++; + ofs = 0; + if (chipnum == cfi->numchips) + return 0; + } + } + + /* Write buffer is worth it only if more than one word to write... */ + while (len) { + /* We must not cross write block boundaries */ + int size = wbufsize - (ofs & (wbufsize-1)); + + if (size > len) + size = len; + ret = do_write_buffer(map, &cfi->chips[chipnum], + ofs, buf, size); + if (ret) + return ret; + + ofs += size; + buf += size; + (*retlen) += size; + len -= size; + + if (ofs >> cfi->chipshift) { + chipnum ++; + ofs = 0; + if (chipnum == cfi->numchips) + return 0; + } + } + return 0; } -static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) + +/* + * Handle devices with one erase region, that only implement + * the chip erase command. + */ +static inline int do_erase_chip(struct map_info *map, struct flchip *chip) { - unsigned int oldstatus, status; - unsigned int dq6, dq5; - unsigned long timeo = jiffies + HZ; struct cfi_private *cfi = map->fldrv_priv; + cfi_word oldstatus, status, prev_oldstatus, prev_status; + cfi_word dq6 = CMD(1<<6); + unsigned long timeo = jiffies + HZ; + unsigned long int adr; DECLARE_WAITQUEUE(wait, current); + int ret = 0; + int ta = 0; + cfi_word datum = 0; + DECLARE_RETRY_CMD_CNT(); - retry: - cfi_spin_lock(chip->mutex); + adr = cfi->addr_unlock1; - if (chip->state != FL_READY){ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_WRITING); + if (ret) { cfi_spin_unlock(chip->mutex); + return ret; + } - schedule(); - remove_wait_queue(&chip->wq, &wait); -#if 0 - if(signal_pending(current)) - return -EINTR; -#endif - timeo = jiffies + HZ; - - goto retry; - } - - chip->state = FL_ERASING; + RETRY_CMD_LABEL; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + __func__, chip->start ); - adr += chip->start; ENABLE_VPP(map); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_write(map, CMD(0x30), adr); - - timeo = jiffies + (HZ*20); + cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - /* Wait for the end of programing/erasure by using the toggle method. - * As long as there is a programming procedure going on, bit 6 of the last - * written byte is toggling it's state with each consectuve read. - * The toggling stops as soon as the procedure is completed. - * - * If the process has gone on for too long on the chip bit 5 gets. - * After bit5 is set you can kill the operation by sending a reset - * command to the chip. - */ - dq6 = CMD(1<<6); - dq5 = CMD(1<<5); + chip->state = FL_ERASING; + chip->erase_suspended = 0; + + cfi_spin_unlock(chip->mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((chip->erase_time*HZ)/(2*1000)); + cfi_spin_lock(chip->mutex); - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); - while( ((status & dq6) != (oldstatus & dq6)) && - ((status & dq5) != dq5) && - !time_after(jiffies, timeo)) { - int wait_reps; + timeo = jiffies + (HZ*20); - /* an initial short sleep */ - cfi_spin_unlock(chip->mutex); - schedule_timeout(HZ/100); - cfi_spin_lock(chip->mutex); - + for (;;) { if (chip->state != FL_ERASING) { /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); - printk(KERN_DEBUG "erase suspended. Sleeping\n"); - schedule(); remove_wait_queue(&chip->wq, &wait); -#if 0 - if (signal_pending(current)) - return -EINTR; -#endif - timeo = jiffies + (HZ*2); /* FIXME */ cfi_spin_lock(chip->mutex); continue; } - - /* Busy wait for 1/10 of a milisecond */ - for(wait_reps = 0; - (wait_reps < 100) && - ((status & dq6) != (oldstatus & dq6)) && - ((status & dq5) != dq5); - wait_reps++) { - - /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - - cfi_udelay(1); - - cfi_spin_lock(chip->mutex); - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); + if (chip->erase_suspended) { + /* This erase was suspended and resumed. + Adjust the timeout */ + timeo = jiffies + (HZ*20); /* FIXME */ + chip->erase_suspended = 0; } + oldstatus = cfi_read(map, adr); status = cfi_read(map, adr); - } - if( (status & dq6) != (oldstatus & dq6) ) - { - /* The erasing didn't stop?? */ - if( ( status & dq5 ) == dq5 ) - { - /* When DQ5 raises, we must check once again if DQ6 is toggling. - If not, the erase has been completed OK. If not, reset chip. */ - oldstatus = cfi_read( map, adr ); - status = cfi_read( map, adr ); - - if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) ) - { - printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" ); - } - else - { - /* DQ5 is active so we can do a reset and stop the erase */ - cfi_write(map, CMD(0xF0), chip->start); - printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" ); - } - } - else - { - printk( "Waiting for erase to complete timed out in do_erase_oneblock."); - - chip->state = FL_READY; - wake_up(&chip->wq); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + if ( (((status ^ oldstatus) & dq6) == 0) + || ( ta = time_after(jiffies, timeo)) ) + break; + + /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); - DISABLE_VPP(map); - return -EIO; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + cfi_spin_lock(chip->mutex); } + + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( cfi_buswidth_is_1() ) { + datum = (__u8)~0; + } else if ( cfi_buswidth_is_2() ) { + datum = (__u16)~0; + } else if ( cfi_buswidth_is_4() ) { + datum = (__u32)~0; +#ifdef CFI_WORD_64 + } else if ( cfi_buswidth_is_8() ) { + datum = (__u64)~0; +#endif + } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + goto op_failed; + } + + if ( oldstatus == datum && status == datum ) { + /* success - do nothing */ + goto op_done; + } + + if ( ta ) { + /* Only check dq5 on the chips that are still toggling. */ + cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x\n", + __func__, + status & dq5mask ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); + } + goto op_failed; } - DISABLE_VPP(map); + HANDLE_WACKY_STATE(); + + op_failed: + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + CHECK_RETRIES(); + ret = -EIO; + + op_done: chip->state = FL_READY; - wake_up(&chip->wq); + put_chip(map, chip, adr); cfi_spin_unlock(chip->mutex); - return 0; + + return ret; } -static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) + +typedef int (*frob_t)(struct map_info *map, struct flchip *chip, + unsigned long adr, void *thunk); + + +static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob, + loff_t ofs, size_t len, void *thunk) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr, len; + unsigned long adr; int chipnum, ret = 0; int i, first; struct mtd_erase_region_info *regions = mtd->eraseregions; - if (instr->addr > mtd->size) + if (ofs > mtd->size) return -EINVAL; - if ((instr->len + instr->addr) > mtd->size) + if ((len + ofs) > mtd->size) return -EINVAL; /* Check that both start and end of the requested erase are @@ -1008,7 +1642,7 @@ start of the requested erase, and then go back one. */ - while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) + while (i < mtd->numeraseregions && ofs >= regions[i].offset) i++; i--; @@ -1018,7 +1652,7 @@ effect here. */ - if (instr->addr & (regions[i].erasesize-1)) + if (ofs & (regions[i].erasesize-1)) return -EINVAL; /* Remember the erase region we start on */ @@ -1028,7 +1662,7 @@ * with the erase region at that address. */ - while (inumeraseregions && (instr->addr + instr->len) >= regions[i].offset) + while (inumeraseregions && (ofs + len) >= regions[i].offset) i++; /* As before, drop back one to point at the region in which @@ -1036,18 +1670,17 @@ */ i--; - if ((instr->addr + instr->len) & (regions[i].erasesize-1)) + if ((ofs + len) & (regions[i].erasesize-1)) return -EINVAL; - - chipnum = instr->addr >> cfi->chipshift; - adr = instr->addr - (chipnum << cfi->chipshift); - len = instr->len; - i=first; + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); - while(len) { - ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); + i=first; + while (len) { + ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk); + if (ret) return ret; @@ -1066,51 +1699,171 @@ } } - instr->state = MTD_ERASE_DONE; - if (instr->callback) - instr->callback(instr); - return 0; } -static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr) + +static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) { - struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr, len; - int chipnum, ret = 0; + cfi_word oldstatus, status, prev_oldstatus, prev_status; + cfi_word dq6 = CMD(1<<6); + unsigned long timeo = jiffies + HZ; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + int ta = 0; + cfi_word datum = 0; + DECLARE_RETRY_CMD_CNT(); - if (instr->addr & (mtd->erasesize - 1)) - return -EINVAL; + adr += chip->start; - if (instr->len & (mtd->erasesize -1)) - return -EINVAL; + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_ERASING); + if (ret) { + cfi_spin_unlock(chip->mutex); + return ret; + } - if ((instr->len + instr->addr) > mtd->size) - return -EINVAL; + RETRY_CMD_LABEL; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + __func__, adr ); - chipnum = instr->addr >> cfi->chipshift; - adr = instr->addr - (chipnum << cfi->chipshift); - len = instr->len; + ENABLE_VPP(map); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_write(map, CMD(0x30), adr); - while(len) { - ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); + chip->state = FL_ERASING; + chip->erase_suspended = 0; + + cfi_spin_unlock(chip->mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((chip->erase_time*HZ)/(2*1000)); + cfi_spin_lock(chip->mutex); - if (ret) - return ret; + timeo = jiffies + (HZ*20); - adr += mtd->erasesize; - len -= mtd->erasesize; + /* Wait for the end of programing/erasure by using the toggle method. + * As long as there is a programming procedure going on, bit 6 is + * toggling its state with each consecutive read. The toggling stops + * as soon as the procedure is completed. + * + * If the process has gone on for too long on the chip, bit 5 gets + * set. After bit5 is set you can kill the operation by sending a + * reset command to the chip. + */ + /* See comments in do_write_oneword(). */ - if (adr >> cfi->chipshift) { - adr = 0; - chipnum++; - - if (chipnum >= cfi->numchips) + for (;;) { + if (chip->state != FL_ERASING) { + /* Someone's suspended the erase. Sleep */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + cfi_spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + cfi_spin_lock(chip->mutex); + continue; + } + if (chip->erase_suspended) { + /* This erase was suspended and resumed. + Adjust the timeout */ + timeo = jiffies + (HZ*20); /* FIXME */ + chip->erase_suspended = 0; + } + + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + if ( (((status ^ oldstatus) & dq6) == 0) + || ( ta = time_after(jiffies, timeo)) ) break; + + /* Latency issues. Drop the lock, wait a while and retry */ + cfi_spin_unlock(chip->mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + cfi_spin_lock(chip->mutex); + } + + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( cfi_buswidth_is_1() ) { + datum = (__u8)~0; + } else if ( cfi_buswidth_is_2() ) { + datum = (__u16)~0; + } else if ( cfi_buswidth_is_4() ) { + datum = (__u32)~0; +#ifdef CFI_WORD_64 + } else if ( cfi_buswidth_is_8() ) { + datum = (__u64)~0; +#endif + } else { + printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", + __func__, CFIDEV_BUSWIDTH); + goto op_failed; + } + + if ( oldstatus == datum && status == datum ) { + /* success - do nothing */ + goto op_done; + } + + if ( ta ) { + /* Only check dq5 on the chips that are still toggling. */ + cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x\n", + __func__, + status & dq5mask ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); } + goto op_failed; } - + + HANDLE_WACKY_STATE(); + + op_failed: + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + CHECK_RETRIES(); + ret = -EIO; + + op_done: + chip->state = FL_READY; + put_chip(map, chip, adr); + cfi_spin_unlock(chip->mutex); + return ret; +} + + +int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) +{ + unsigned long ofs, len; + int ret; + + ofs = instr->addr; + len = instr->len; + + ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0); + if (ret) + return ret; + instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); @@ -1118,6 +1871,7 @@ return 0; } + static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) { struct map_info *map = mtd->priv; @@ -1141,6 +1895,7 @@ return 0; } + static void cfi_amdstd_sync (struct mtd_info *mtd) { struct map_info *map = mtd->priv; @@ -1254,6 +2009,7 @@ return ret; } + static void cfi_amdstd_resume(struct mtd_info *mtd) { struct map_info *map = mtd->priv; @@ -1279,6 +2035,137 @@ } } + +#ifdef DEBUG_LOCK_BITS + +static int do_printlockstatus_oneblock(struct map_info *map, + struct flchip *chip, + unsigned long adr, + void *thunk) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ofs_factor = cfi->interleave * cfi->device_type; + + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", + adr, cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); + + return 0; +} + + +#define debug_dump_locks(mtd, frob, ofs, len, thunk) \ + cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk)) + +#else + +#define debug_dump_locks(...) + +#endif /* DEBUG_LOCK_BITS */ + + +struct xxlock_thunk { + cfi_word val; + flstate_t state; +}; + + +#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING}) +#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING}) + + +/* + * FIXME - this is *very* specific to a particular chip. It likely won't + * work for all chips that require unlock. It also hasn't been tested + * with interleaved chips. + */ +static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk; + int ret; + + /* + * This is easy because these are writes to registers and not writes + * to flash memory - that means that we don't have to check status + * and timeout. + */ + + adr += chip->start; + /* + * lock block registers: + * - on 64k boundariesand + * - bit 1 set high + * - block lock registers are 4MiB lower - overflow subtract (danger) + */ + adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff; + + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_LOCKING); + if (ret) { + cfi_spin_unlock(chip->mutex); + return ret; + } + + chip->state = xxlt->state; + cfi_write(map, CMD(xxlt->val), adr); + + /* Done and happy. */ + chip->state = FL_READY; + put_chip(map, chip, adr); + cfi_spin_unlock(chip->mutex); + return 0; +} + + +static int cfi_amdstd_lock_varsize(struct mtd_info *mtd, + loff_t ofs, + size_t len) +{ + int ret; + + DEBUG(MTD_DEBUG_LEVEL3, + "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", + __func__, ofs, len); + debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); + + ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, + (void *)&DO_XXLOCK_ONEBLOCK_LOCK); + + DEBUG(MTD_DEBUG_LEVEL3, + "%s: lock status after, ret=%d\n", + __func__, ret); + + debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); + + return ret; +} + + +static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd, + loff_t ofs, + size_t len) +{ + int ret; + + DEBUG(MTD_DEBUG_LEVEL3, + "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", + __func__, ofs, len); + debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); + + ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, + (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK); + + DEBUG(MTD_DEBUG_LEVEL3, + "%s: lock status after, ret=%d\n", + __func__, ret); + debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); + + return ret; +} + + static void cfi_amdstd_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; @@ -1291,17 +2178,20 @@ static char im_name[]="cfi_cmdset_0002"; + int __init cfi_amdstd_init(void) { inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002); return 0; } + static void __exit cfi_amdstd_exit(void) { inter_module_unregister(im_name); } + module_init(cfi_amdstd_init); module_exit(cfi_amdstd_exit); @@ -1309,3 +2199,7 @@ MODULE_AUTHOR("Crossnet Co. et al."); MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips"); +#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY +MODULE_PARM(retry_cmd_max, "i"); +MODULE_PARM_DESC(retry_cmd_max, "Number of times to retry an erase or program command if it fails - should only be needed by buggy hardware: default 0"); +#endif diff -Nru a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c --- a/drivers/mtd/chips/cfi_cmdset_0020.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/cfi_cmdset_0020.c Thu Dec 4 16:24:25 2003 @@ -21,16 +21,19 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include -#include +#include static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -51,10 +54,10 @@ static struct mtd_info *cfi_staa_setup (struct map_info *); static struct mtd_chip_driver cfi_staa_chipdrv = { - probe: NULL, /* Not usable directly */ - destroy: cfi_staa_destroy, - name: "cfi_cmdset_0020", - module: THIS_MODULE + .probe = NULL, /* Not usable directly */ + .destroy = cfi_staa_destroy, + .name = "cfi_cmdset_0020", + .module = THIS_MODULE }; /* #define DEBUG_LOCK_BITS */ @@ -113,7 +116,6 @@ { struct cfi_private *cfi = map->fldrv_priv; int i; - __u32 base = cfi->chips[0].start; if (cfi->cfi_mode) { /* @@ -123,36 +125,11 @@ */ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; struct cfi_pri_intelext *extp; - int ofs_factor = cfi->interleave * cfi->device_type; - printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr); - if (!adr) + extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics"); + if (!extp) return NULL; - /* Switch it into Query Mode */ - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - - extp = kmalloc(sizeof(*extp), GFP_KERNEL); - if (!extp) { - printk(KERN_ERR "Failed to allocate memory\n"); - return NULL; - } - - /* Read in the Extended Query Table */ - for (i=0; iMajorVersion != '1' || - (extp->MinorVersion < '0' || extp->MinorVersion > '2')) { - printk(KERN_WARNING " Unknown staa Extended Query " - "version %c.%c.\n", extp->MajorVersion, - extp->MinorVersion); - kfree(extp); - return NULL; - } - /* Do some byteswapping if necessary */ extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); @@ -172,11 +149,6 @@ cfi->chips[i].erase_time = 1024; } - map->fldrv = &cfi_staa_chipdrv; - MOD_INC_USE_COUNT; - - /* Make sure it's in read mode */ - cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); return cfi_staa_setup(map); } @@ -208,6 +180,7 @@ if (!mtd->eraseregions) { printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); kfree(cfi->cmdset_priv); + kfree(mtd); return NULL; } @@ -232,6 +205,7 @@ printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); kfree(mtd->eraseregions); kfree(cfi->cmdset_priv); + kfree(mtd); return NULL; } @@ -256,7 +230,7 @@ mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */ mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ map->fldrv = &cfi_staa_chipdrv; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); mtd->name = map->name; return mtd; } @@ -288,7 +262,7 @@ */ switch (chip->state) { case FL_ERASING: - if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2) + if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) goto sleep; /* We don't support erase suspend */ cfi_write (map, CMD(0xb0), cmd_addr); @@ -374,7 +348,7 @@ goto retry; } - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); if (suspended) { chip->state = chip->oldstate; @@ -540,11 +514,11 @@ /* Write data */ for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { - map->write8 (map, *((__u8*)buf)++, adr+z); + map_write8 (map, *((__u8*)buf)++, adr+z); } else if (cfi_buswidth_is_2()) { - map->write16 (map, *((__u16*)buf)++, adr+z); + map_write16 (map, *((__u16*)buf)++, adr+z); } else if (cfi_buswidth_is_4()) { - map->write32 (map, *((__u32*)buf)++, adr+z); + map_write32 (map, *((__u32*)buf)++, adr+z); } else { DISABLE_VPP(map); return -EINVAL; @@ -1436,13 +1410,13 @@ static char im_name[]="cfi_cmdset_0020"; -mod_init_t cfi_staa_init(void) +int __init cfi_staa_init(void) { inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020); return 0; } -mod_exit_t cfi_staa_exit(void) +static void __exit cfi_staa_exit(void) { inter_module_unregister(im_name); } diff -Nru a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c --- a/drivers/mtd/chips/cfi_probe.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/chips/cfi_probe.c Thu Dec 4 16:24:26 2003 @@ -1,13 +1,14 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: cfi_probe.c,v 1.69 2002/05/11 22:13:03 dwmw2 Exp $ + $Id: cfi_probe.c,v 1.73 2003/11/08 00:51:21 dsaxena Exp $ */ #include #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ #endif static int cfi_probe_chip(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi); + unsigned long *chip_map, struct cfi_private *cfi); static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi); struct mtd_info *cfi_probe(struct map_info *map); @@ -48,7 +49,7 @@ } static int cfi_probe_chip(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi) + unsigned long *chip_map, struct cfi_private *cfi) { int i; @@ -65,10 +66,6 @@ return 0; } cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - - /* some devices don't respond to 0xF0, so send 0xFF to be sure */ - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); if (!qry_present(map,base,cfi)) @@ -81,20 +78,24 @@ } /* Check each previous chip to see if it's an alias */ - for (i=0; inumchips; i++) { + for (i=0; i < (base >> cfi->chipshift); i++) { + unsigned long start; + if(!test_bit(i, chip_map)) { + /* Skip location; no valid chip at this address */ + continue; + } + start = i << cfi->chipshift; /* This chip should be in read mode if it's one we've already touched. */ - if (qry_present(map,chips[i].start,cfi)) { + if (qry_present(map, start, cfi)) { /* Eep. This chip also had the QRY marker. * Is it an alias for the new one? */ - cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL); - /* some devices don't respond to 0xF0, so send 0xFF to be sure */ - cfi_send_gen_cmd(0xFF, 0, chips[i].start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); /* If the QRY marker goes away, it's an alias */ - if (!qry_present(map, chips[i].start, cfi)) { + if (!qry_present(map, start, cfi)) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", - map->name, base, chips[i].start); + map->name, base, start); return 0; } /* Yes, it's actually got QRY for data. Most @@ -102,11 +103,10 @@ * too and if it's the same, assume it's an alias. */ /* FIXME: Use other modes to do a proper check */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - /* some devices don't respond to 0xF0, so send 0xFF to be sure */ - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + if (qry_present(map, base, cfi)) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", - map->name, base, chips[i].start); + map->name, base, start); return 0; } } @@ -114,22 +114,12 @@ /* OK, if we got to here, then none of the previous chips appear to be aliases for the current one. */ - if (cfi->numchips == MAX_CFI_CHIPS) { - printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS); - /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */ - return -1; - } - chips[cfi->numchips].start = base; - chips[cfi->numchips].state = FL_READY; + set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ cfi->numchips++; /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - /* some devices don't respond to 0xF0, so send 0xFF to be sure */ - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); - - printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", map->name, cfi->interleave, cfi->device_type*8, base, map->buswidth*8); @@ -176,20 +166,6 @@ cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc); cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize); - /* - * ST screwed up the CFI interface for buffer writes on their parts, - * so this needs to be fixed up by hand here. - * - * A possible enhancment is that instead of just reverting back - * to word write (as this does), we could use the ST specific double - * word write instead. - */ - - if (cfi_read_query(map,base) == 0x20){ - cfi->cfiq->BufWriteTimeoutTyp = 0; - cfi->cfiq->BufWriteTimeoutMax = 0; - } - #ifdef DEBUG_CFI /* Dump the information therein */ print_cfi_ident(cfi->cfiq); @@ -204,11 +180,27 @@ (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); #endif } + + /* Note we put the device back into Read Mode BEFORE going into Auto + * Select Mode, as some devices support nesting of modes, others + * don't. This way should always work. + * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and + * so should be treated as nops or illegal (and so put the device + * back into Read Mode, which is a nop in this case). + */ + cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); + cfi->mfr = cfi_read_query(map, base); + cfi->id = cfi_read_query(map, base + ofs_factor); + /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - /* some devices don't respond to 0xF0, so send 0xFF to be sure */ - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", + map->name, cfi->interleave, cfi->device_type*8, base, + map->buswidth*8); return 1; } @@ -268,11 +260,11 @@ printk("No Alternate Algorithm Table\n"); - printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); - printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); + printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); + printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); if (cfip->VppMin) { - printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf); - printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf); + printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf); + printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf); } else printk("No Vpp line\n"); @@ -331,8 +323,8 @@ #endif /* DEBUG_CFI */ static struct chip_probe cfi_chip_probe = { - name: "CFI", - probe_chip: cfi_probe_chip + .name = "CFI", + .probe_chip = cfi_probe_chip }; struct mtd_info *cfi_probe(struct map_info *map) @@ -345,9 +337,9 @@ } static struct mtd_chip_driver cfi_chipdrv = { - probe: cfi_probe, - name: "cfi_probe", - module: THIS_MODULE + .probe = cfi_probe, + .name = "cfi_probe", + .module = THIS_MODULE }; int __init cfi_probe_init(void) diff -Nru a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/chips/cfi_util.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,91 @@ +/* + * Common Flash Interface support: + * Generic utility functions not dependant on command set + * + * Copyright (C) 2002 Red Hat + * Copyright (C) 2003 STMicroelectronics Limited + * + * This code is covered by the GPL. + * + * $Id: cfi_util.c,v 1.3 2003/11/14 19:50:03 thayne Exp $ + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +struct cfi_extquery * +cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) +{ + struct cfi_private *cfi = map->fldrv_priv; + __u32 base = 0; // cfi->chips[0].start; + int ofs_factor = cfi->interleave * cfi->device_type; + int i; + struct cfi_extquery *extp = NULL; + + printk(" %s Extended Query Table at 0x%4.4X\n", name, adr); + if (!adr) + goto out; + + /* Switch it into Query Mode */ + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); + + extp = kmalloc(size, GFP_KERNEL); + if (!extp) { + printk(KERN_ERR "Failed to allocate memory\n"); + goto out; + } + + /* Read in the Extended Query Table */ + for (i=0; iMajorVersion != '1' || + (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { + printk(KERN_WARNING " Unknown %s Extended Query " + "version %c.%c.\n", name, extp->MajorVersion, + extp->MinorVersion); + kfree(extp); + extp = NULL; + goto out; + } + +out: + /* Make sure it's in read mode */ + cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); + + return extp; +} + +EXPORT_SYMBOL(cfi_read_pri); + +void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_fixup *f; + + for (f=fixups; f->fixup; f++) { + if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && + ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { + f->fixup(map, f->param); + } + } +} + +EXPORT_SYMBOL(cfi_fixup); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c --- a/drivers/mtd/chips/chipreg.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/chips/chipreg.c Thu Dec 4 16:24:26 2003 @@ -1,5 +1,5 @@ /* - * $Id: chipreg.c,v 1.13 2002/02/21 08:26:58 dwmw2 Exp $ + * $Id: chipreg.c,v 1.16 2003/05/29 09:36:15 dwmw2 Exp $ * * Registration for chip drivers * @@ -7,10 +7,13 @@ #include #include +#include #include #include -#include +#include #include +#include +#include spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(chip_drvs_list); @@ -44,10 +47,8 @@ break; } } - if (ret && !try_inc_mod_count(ret->module)) { - /* Eep. Failed. */ + if (ret && !try_module_get(ret->module)) ret = NULL; - } spin_unlock(&chip_drvs_lock); @@ -64,32 +65,46 @@ drv = get_mtd_chip_driver(name); - if (!drv && !request_module(name)) + if (!drv && !request_module("%s", name)) drv = get_mtd_chip_driver(name); if (!drv) return NULL; ret = drv->probe(map); -#ifdef CONFIG_MODULES + /* We decrease the use count here. It may have been a probe-only module, which is no longer required from this point, having given us a handle on (and increased the use count of) the actual driver code. */ - if(drv->module) - __MOD_DEC_USE_COUNT(drv->module); -#endif + module_put(drv->module); if (ret) return ret; return NULL; } +/* + * Destroy an MTD device which was created for a map device. + * Make sure the MTD device is already unregistered before calling this + */ +void map_destroy(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + + if (map->fldrv->destroy) + map->fldrv->destroy(mtd); + + module_put(map->fldrv->module); + + kfree(mtd); +} EXPORT_SYMBOL(register_mtd_chip_driver); EXPORT_SYMBOL(unregister_mtd_chip_driver); EXPORT_SYMBOL(do_map_probe); +EXPORT_SYMBOL(map_destroy); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse "); diff -Nru a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c --- a/drivers/mtd/chips/gen_probe.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/gen_probe.c Thu Dec 4 16:24:25 2003 @@ -1,14 +1,17 @@ /* * Routines common to all CFI-type probes. - * (C) 2001, 2001 Red Hat, Inc. + * (C) 2001-2003 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.9 2002/09/05 05:15:32 acurtis Exp $ + * $Id: gen_probe.c,v 1.14 2003/11/08 00:51:21 dsaxena Exp $ */ #include +#include +#include #include #include #include +#include #include static struct mtd_info *check_cmd_set(struct map_info *, int); @@ -50,11 +53,11 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) { - unsigned long base=0; struct cfi_private cfi; struct cfi_private *retcfi; - struct flchip chip[MAX_CFI_CHIPS]; - int i; + unsigned long *chip_map; + int i, j; + int max_chips; memset(&cfi, 0, sizeof(cfi)); @@ -77,8 +80,6 @@ return NULL; } #endif - chip[0].start = 0; - chip[0].state = FL_READY; cfi.chipshift = cfi.cfiq->DevSize; switch(cfi.interleave) { @@ -102,21 +103,29 @@ cfi.numchips = 1; + /* + * Allocate memory for bitmap of valid chips. + * Align bitmap storage size to full byte. + */ + max_chips = map->size >> cfi.chipshift; + chip_map = kmalloc((max_chips / 8) + ((max_chips % 8) ? 1 : 0), GFP_KERNEL); + if (!chip_map) { + printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); + kfree(cfi.cfiq); + return NULL; + } + + set_bit(0, chip_map); /* Mark first chip valid */ + /* * Now probe for other chips, checking sensibly for aliases while * we're at it. The new_chip probe above should have let the first * chip in read mode. - * - * NOTE: Here, we're checking if there is room for another chip - * the same size within the mapping. Therefore, - * base + chipsize <= map->size is the correct thing to do, - * because, base + chipsize would be the _first_ byte of the - * next chip, not the one we're currently pondering. */ - for (base = (1<size; - base += (1<probe_chip(map, base, &chip[0], &cfi); + for (i = 1; i < max_chips; i++) { + cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); + } /* * Now allocate the space for the structures we need to return to @@ -128,19 +137,26 @@ if (!retcfi) { printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); kfree(cfi.cfiq); + kfree(chip_map); return NULL; } memcpy(retcfi, &cfi, sizeof(cfi)); - memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips); + memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); - /* Fix up the stuff that breaks when you move it */ - for (i=0; i< retcfi->numchips; i++) { - init_waitqueue_head(&retcfi->chips[i].wq); - spin_lock_init(&retcfi->chips[i]._spinlock); - retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock; + for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { + if(test_bit(i, chip_map)) { + struct flchip *pchip = &retcfi->chips[j++]; + + pchip->start = (i << cfi.chipshift); + pchip->state = FL_READY; + init_waitqueue_head(&pchip->wq); + spin_lock_init(&pchip->_spinlock); + pchip->mutex = &pchip->_spinlock; + } } + kfree(chip_map); return retcfi; } @@ -277,6 +293,7 @@ extern cfi_cmdset_fn_t cfi_cmdset_0001; extern cfi_cmdset_fn_t cfi_cmdset_0002; +extern cfi_cmdset_fn_t cfi_cmdset_0020; static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, int primary) diff -Nru a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c --- a/drivers/mtd/chips/jedec.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/jedec.c Thu Dec 4 16:24:25 2003 @@ -11,10 +11,16 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.14 2002/06/27 02:19:12 dwmw2 Exp $ + * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $ */ +#include +#include +#include #include +#include +#include +#include static struct mtd_info *jedec_probe(struct map_info *); static int jedec_probe8(struct map_info *map,unsigned long base, @@ -33,14 +39,51 @@ /* Listing of parts and sizes. We need this table to learn the sector size of the chip and the total length */ -static const struct JEDECTable JEDEC_table[] = - {{0x013D,"AMD Am29F017D",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, - {0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, - {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH}, - {0x01A4,"AMD Am29F040",512*1024,64*1024,MTD_CAP_NORFLASH}, - {0x20E3,"AMD Am29W040B",512*1024,64*1024,MTD_CAP_NORFLASH}, - {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, - {}}; +static const struct JEDECTable JEDEC_table[] = { + { + .jedec = 0x013D, + .name = "AMD Am29F017D", + .size = 2*1024*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { + .jedec = 0x01AD, + .name = "AMD Am29F016", + .size = 2*1024*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { + .jedec = 0x01D5, + .name = "AMD Am29F080", + .size = 1*1024*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { + .jedec = 0x01A4, + .name = "AMD Am29F040", + .size = 512*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { + .jedec = 0x20E3, + .name = "AMD Am29W040B", + .size = 512*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { + .jedec = 0xC2AD, + .name = "Macronix MX29F016", + .size = 2*1024*1024, + .sectorsize = 64*1024, + .capabilities = MTD_CAP_NORFLASH + }, + { .jedec = 0x0 } +}; static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); static void jedec_sync(struct mtd_info *mtd) {}; @@ -54,9 +97,9 @@ static struct mtd_chip_driver jedec_chipdrv = { - probe: jedec_probe, - name: "jedec", - module: THIS_MODULE + .probe = jedec_probe, + .name = "jedec", + .module = THIS_MODULE }; /* Probe entry point */ @@ -131,8 +174,7 @@ /* Generate a part name that includes the number of different chips and other configuration information */ count = 1; - strncpy(Part,map->name,sizeof(Part)-10); - Part[sizeof(Part)-11] = 0; + strlcpy(Part,map->name,sizeof(Part)-10); strcat(Part," "); Uniq = 0; for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) @@ -209,8 +251,7 @@ // printk("Part: '%s'\n",Part); memset(MTD,0,sizeof(*MTD)); - // strncpy(MTD->name,Part,sizeof(MTD->name)); - // MTD->name[sizeof(MTD->name)-1] = 0; + // strlcpy(MTD->name,Part,sizeof(MTD->name)); MTD->name = map->name; MTD->type = MTD_NORFLASH; MTD->flags = MTD_CAP_NORFLASH; @@ -229,7 +270,7 @@ MTD->priv = map; map->fldrv_priv = priv; map->fldrv = &jedec_chipdrv; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return MTD; } @@ -351,8 +392,8 @@ static int jedec_probe8(struct map_info *map,unsigned long base, struct jedec_private *priv) { - #define flread(x) map->read8(map,base+x) - #define flwrite(v,x) map->write8(map,v,base+x) + #define flread(x) map_read8(map,base+x) + #define flwrite(v,x) map_write8(map,v,base+x) const unsigned long AutoSel1 = 0xAA; const unsigned long AutoSel2 = 0x55; @@ -411,8 +452,8 @@ static int jedec_probe32(struct map_info *map,unsigned long base, struct jedec_private *priv) { - #define flread(x) map->read32(map,base+((x)<<2)) - #define flwrite(v,x) map->write32(map,v,base+((x)<<2)) + #define flread(x) map_read32(map,base+((x)<<2)) + #define flwrite(v,x) map_write32(map,v,base+((x)<<2)) const unsigned long AutoSel1 = 0xAAAAAAAA; const unsigned long AutoSel2 = 0x55555555; @@ -490,7 +531,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } @@ -514,7 +555,7 @@ get = priv->bank_fill[0] - offset; bank /= priv->bank_fill[0]; - map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); + map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); len -= get; *retlen += get; @@ -545,8 +586,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { // Does IO to the currently selected chip - #define flread(x) map->read8(map,chip->base+((x)<addrshift)) - #define flwrite(v,x) map->write8(map,v,chip->base+((x)<addrshift)) + #define flread(x) map_read8(map,chip->base+((x)<addrshift)) + #define flwrite(v,x) map_write8(map,v,chip->base+((x)<addrshift)) unsigned long Time = 0; unsigned long NoTime = 0; @@ -608,7 +649,7 @@ /* Poll the flash for erasure completion, specs say this can take as long as 480 seconds to do all the sectors (for a 2 meg flash). - Erasure time is dependant on chip age, temp and wear.. */ + Erasure time is dependent on chip age, temp and wear.. */ /* This being a generic routine assumes a 32 bit bus. It does read32s and bundles interleved chips into the same grouping. This will work @@ -651,19 +692,19 @@ or this is not really flash ;> */ switch (map->buswidth) { case 1: - Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 2: - Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 3: - Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); break; } Count = 3; @@ -699,13 +740,13 @@ switch (map->buswidth) { case 1: - Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 2: - Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 4: - Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); break; } Count++; @@ -755,10 +796,10 @@ size_t *retlen, const u_char *buf) { /* Does IO to the currently selected chip. It takes the bank addressing - base (which is divisable by the chip size) adds the necesary lower bits - of addrshift (interleve index) and then adds the control register index. */ - #define flread(x) map->read8(map,base+(off&((1<addrshift)-1))+((x)<addrshift)) - #define flwrite(v,x) map->write8(map,v,base+(off&((1<addrshift)-1))+((x)<addrshift)) + base (which is divisible by the chip size) adds the necessary lower bits + of addrshift (interleave index) and then adds the control register index. */ + #define flread(x) map_read8(map,base+(off&((1<addrshift)-1))+((x)<addrshift)) + #define flwrite(v,x) map_write8(map,v,base+(off&((1<addrshift)-1))+((x)<addrshift)) struct map_info *map = (struct map_info *)mtd->priv; struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv; @@ -794,7 +835,7 @@ // Loop over this page for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) { - unsigned char oldbyte = map->read8(map,base+off); + unsigned char oldbyte = map_read8(map,base+off); unsigned char Last[4]; unsigned long Count = 0; @@ -809,10 +850,10 @@ flwrite(0xAA,0x555); flwrite(0x55,0x2AA); flwrite(0xA0,0x555); - map->write8(map,*buf,base + off); - Last[0] = map->read8(map,base + off); - Last[1] = map->read8(map,base + off); - Last[2] = map->read8(map,base + off); + map_write8(map,*buf,base + off); + Last[0] = map_read8(map,base + off); + Last[1] = map_read8(map,base + off); + Last[2] = map_read8(map,base + off); /* Wait for the flash to finish the operation. We store the last 4 status bytes that have been retrieved so we can determine why @@ -820,7 +861,7 @@ failure */ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++) - Last[Count % 4] = map->read8(map,base + off); + Last[Count % 4] = map_read8(map,base + off); if (Last[(Count - 1) % 4] != *buf) { jedec_flash_failed(Last[(Count - 3) % 4]); diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c --- a/drivers/mtd/chips/jedec_probe.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/jedec_probe.c Thu Dec 4 16:24:25 2003 @@ -1,9 +1,11 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.19 2002/11/12 13:12:10 dwmw2 Exp $ + $Id: jedec_probe.c,v 1.44 2003/11/17 15:57:35 thayne Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. + + Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com */ #include @@ -15,7 +17,9 @@ #include #include #include +#include +#include #include #include #include @@ -26,20 +30,24 @@ #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_INTEL 0x0089 #define MANUFACTURER_MACRONIX 0x00C2 -#define MANUFACTURER_ST 0x0020 +#define MANUFACTURER_PMC 0x009D #define MANUFACTURER_SST 0x00BF +#define MANUFACTURER_ST 0x0020 #define MANUFACTURER_TOSHIBA 0x0098 +#define MANUFACTURER_WINBOND 0x00da /* AMD */ #define AM29F800BB 0x2258 #define AM29F800BT 0x22D6 +#define AM29LV400BB 0x22BA +#define AM29LV400BT 0x22B9 #define AM29LV800BB 0x225B #define AM29LV800BT 0x22DA #define AM29LV160DT 0x22C4 #define AM29LV160DB 0x2249 #define AM29F017D 0x003D -#define AM29F016 0x00AD +#define AM29F016D 0x00AD #define AM29F080 0x00D5 #define AM29F040 0x00A4 #define AM29LV040B 0x004F @@ -54,6 +62,7 @@ #define AT49BV32XT 0x00C9 /* Fujitsu */ +#define MBM29F040C 0x00A4 #define MBM29LV650UE 0x22D7 #define MBM29LV320TE 0x22F6 #define MBM29LV320BE 0x22F9 @@ -61,6 +70,9 @@ #define MBM29LV160BE 0x2249 #define MBM29LV800BA 0x225B #define MBM29LV800TA 0x22DA +#define MBM29LV400TC 0x22B9 +#define MBM29LV400BC 0x22BA + /* Intel */ #define I28F004B3T 0x00d4 @@ -93,8 +105,14 @@ #define MX29F004T 0x0045 #define MX29F004B 0x0046 +/* PMC */ +#define PM49FL002 0x006D +#define PM49FL004 0x006E +#define PM49FL008 0x006A + /* ST - www.st.com */ -#define M29W800T 0x00D7 +#define M29W800DT 0x00D7 +#define M29W800DB 0x005B #define M29W160DT 0x22C4 #define M29W160DB 0x2249 #define M29W040B 0x00E3 @@ -110,6 +128,7 @@ #define SST39LF040 0x00D7 #define SST39SF010A 0x00B5 #define SST39SF020A 0x00B6 +#define SST49LF004B 0x0060 #define SST49LF030A 0x001C #define SST49LF040A 0x0051 #define SST49LF080A 0x005B @@ -122,15 +141,87 @@ #define TC58FVT641 0x0093 #define TC58FVB641 0x0095 +/* Winbond */ +#define W49V002A 0x00b0 + + +/* + * Unlock address sets for AMD command sets. + * Intel command sets use the MTD_UADDR_UNNECESSARY. + * Each identifier, except MTD_UADDR_UNNECESSARY, and + * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[]. + * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure + * initialization need not require initializing all of the + * unlock addresses for all bit widths. + */ +enum uaddr { + MTD_UADDR_NOT_SUPPORTED = 0, /* data width not supported */ + MTD_UADDR_0x0555_0x02AA, + MTD_UADDR_0x0555_0x0AAA, + MTD_UADDR_0x5555_0x2AAA, + MTD_UADDR_0x0AAA_0x0555, + MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ + MTD_UADDR_UNNECESSARY, /* Does not require any address */ +}; + + +struct unlock_addr { + int addr1; + int addr2; +}; + + +/* + * I don't like the fact that the first entry in unlock_addrs[] + * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore, + * should not be used. The problem is that structures with + * initializers have extra fields initialized to 0. It is _very_ + * desireable to have the unlock address entries for unsupported + * data widths automatically initialized - that means that + * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here + * must go unused. + */ +static const struct unlock_addr unlock_addrs[] = { + [MTD_UADDR_NOT_SUPPORTED] = { + .addr1 = 0xffff, + .addr2 = 0xffff + }, + + [MTD_UADDR_0x0555_0x02AA] = { + .addr1 = 0x0555, + .addr2 = 0x02aa + }, + + [MTD_UADDR_0x0555_0x0AAA] = { + .addr1 = 0x0555, + .addr2 = 0x0aaa + }, + + [MTD_UADDR_0x5555_0x2AAA] = { + .addr1 = 0x5555, + .addr2 = 0x2aaa + }, + + [MTD_UADDR_0x0AAA_0x0555] = { + .addr1 = 0x0AAA, + .addr2 = 0x0555 + }, + + [MTD_UADDR_DONT_CARE] = { + .addr1 = 0x0000, /* Doesn't matter which address */ + .addr2 = 0x0000 /* is used - must be last entry */ + } +}; + struct amd_flash_info { const __u16 mfr_id; const __u16 dev_id; const char *name; const int DevSize; - const int InterfaceDesc; const int NumEraseRegions; const int CmdSet; + const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */ const ulong regions[4]; }; @@ -145,760 +236,1214 @@ #define SIZE_4MiB 22 #define SIZE_8MiB 23 + +/* + * Please keep this list ordered by manufacturer! + * Fortunately, the list isn't searched often and so a + * slow, linear search isn't so bad. + */ static const struct amd_flash_info jedec_table[] = { { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F032B, - name: "AMD AM29F032B", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,64) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV160DT, - name: "AMD AM29LV160DT", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV160DB, - name: "AMD AM29LV160DB", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVT160, - name: "Toshiba TC58FVT160", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVB160, - name: "Toshiba TC58FVB160", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVB321, - name: "Toshiba TC58FVB321", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x02000,8), - ERASEINFO(0x10000,63) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVT321, - name: "Toshiba TC58FVT321", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x10000,63), - ERASEINFO(0x02000,8) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVB641, - name: "Toshiba TC58FVB641", - DevSize: SIZE_8MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x02000,8), - ERASEINFO(0x10000,127) - } - }, { - mfr_id: MANUFACTURER_TOSHIBA, - dev_id: TC58FVT641, - name: "Toshiba TC58FVT641", - DevSize: SIZE_8MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x10000,127), - ERASEINFO(0x02000,8) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV650UE, - name: "Fujitsu MBM29LV650UE", - DevSize: SIZE_8MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,128) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV320TE, - name: "Fujitsu MBM29LV320TE", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x10000,63), - ERASEINFO(0x02000,8) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV320BE, - name: "Fujitsu MBM29LV320BE", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x02000,8), - ERASEINFO(0x10000,63) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV160TE, - name: "Fujitsu MBM29LV160TE", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV160BE, - name: "Fujitsu MBM29LV160BE", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV800BA, - name: "Fujitsu MBM29LV800BA", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,15) - } - }, { - mfr_id: MANUFACTURER_FUJITSU, - dev_id: MBM29LV800TA, - name: "Fujitsu MBM29LV800TA", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BB, - name: "AMD AM29LV800BB", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,15), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F800BB, - name: "AMD AM29F800BB", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,15), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BT, - name: "AMD AM29LV800BT", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F800BT, - name: "AMD AM29F800BT", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV800BB, - name: "AMD AM29LV800BB", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F004B3B, - name: "Intel 28F004B3B", - DevSize: SIZE_512KiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F032B, + .name = "AMD AM29F032B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,64) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DT, + .name = "AMD AM29LV160DT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DB, + .name = "AMD AM29LV160DB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV400BB, + .name = "AMD AM29LV400BB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV400BT, + .name = "AMD AM29LV400BT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BB, + .name = "AMD AM29F800BB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BT, + .name = "AMD AM29LV800BT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BT, + .name = "AMD AM29F800BT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F017D, + .name = "AMD AM29F017D", + .uaddr = { + [0] = MTD_UADDR_DONT_CARE /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F016D, + .name = "AMD AM29F016D", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F080, + .name = "AMD AM29F080", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F040, + .name = "AMD AM29F040", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV040B, + .name = "AMD AM29LV040B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV512, + .name = "Atmel AT49BV512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,1) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT29LV512, + .name = "Atmel AT29LV512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x80,256), + ERASEINFO(0x80,256) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV16X, + .name = "Atmel AT49BV16X", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV16XT, + .name = "Atmel AT49BV16XT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV32X, + .name = "Atmel AT49BV32X", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV32XT, + .name = "Atmel AT49BV32XT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29F040C, + .name = "Fujitsu MBM29F040C", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV650UE, + .name = "Fujitsu MBM29LV650UE", + .uaddr = { + [0] = MTD_UADDR_DONT_CARE /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,128) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV320TE, + .name = "Fujitsu MBM29LV320TE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV320BE, + .name = "Fujitsu MBM29LV320BE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160TE, + .name = "Fujitsu MBM29LV160TE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160BE, + .name = "Fujitsu MBM29LV160BE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800BA, + .name = "Fujitsu MBM29LV800BA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800TA, + .name = "Fujitsu MBM29LV800TA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV400BC, + .name = "Fujitsu MBM29LV400BC", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV400TC, + .name = "Fujitsu MBM29LV400TC", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F004B3B, + .name = "Intel 28F004B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 7), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F004B3T, - name: "Intel 28F004B3T", - DevSize: SIZE_512KiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F004B3T, + .name = "Intel 28F004B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 7), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F400B3B, - name: "Intel 28F400B3B", - DevSize: SIZE_512KiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F400B3B, + .name = "Intel 28F400B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 7), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F400B3T, - name: "Intel 28F400B3T", - DevSize: SIZE_512KiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F400B3T, + .name = "Intel 28F400B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 7), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F008B3B, - name: "Intel 28F008B3B", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008B3B, + .name = "Intel 28F008B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 15), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F008B3T, - name: "Intel 28F008B3T", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008B3T, + .name = "Intel 28F008B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 15), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F008S5, - name: "Intel 28F008S5", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_EXT, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,16), - } - }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F016S5, - name: "Intel 28F016S5", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_EXT, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,32), - } - }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F008SA, - name: "Intel 28F008SA", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 1, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008S5, + .name = "Intel 28F008S5", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016S5, + .name = "Intel 28F016S5", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008SA, + .name = "Intel 28F008SA", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 1, + .regions = { ERASEINFO(0x10000, 16), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F800B3B, - name: "Intel 28F800B3B", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F800B3B, + .name = "Intel 28F800B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 15), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F800B3T, - name: "Intel 28F800B3T", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F800B3T, + .name = "Intel 28F800B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 15), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F016B3B, - name: "Intel 28F016B3B", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016B3B, + .name = "Intel 28F016B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 31), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F016S3, - name: "Intel I28F016S3", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 1, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016S3, + .name = "Intel I28F016S3", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 1, + .regions = { ERASEINFO(0x10000, 32), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F016B3T, - name: "Intel 28F016B3T", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016B3T, + .name = "Intel 28F016B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 31), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F160B3B, - name: "Intel 28F160B3B", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F160B3B, + .name = "Intel 28F160B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 31), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F160B3T, - name: "Intel 28F160B3T", - DevSize: SIZE_2MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F160B3T, + .name = "Intel 28F160B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 31), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F320B3B, - name: "Intel 28F320B3B", - DevSize: SIZE_4MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F320B3B, + .name = "Intel 28F320B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 63), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F320B3T, - name: "Intel 28F320B3T", - DevSize: SIZE_4MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F320B3T, + .name = "Intel 28F320B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 63), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F640B3B, - name: "Intel 28F640B3B", - DevSize: SIZE_8MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F640B3B, + .name = "Intel 28F640B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x02000, 8), ERASEINFO(0x10000, 127), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I28F640B3T, - name: "Intel 28F640B3T", - DevSize: SIZE_8MiB, - CmdSet: P_ID_INTEL_STD, - NumEraseRegions: 2, - regions: { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F640B3T, + .name = "Intel 28F640B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { ERASEINFO(0x10000, 127), ERASEINFO(0x02000, 8), } }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I82802AB, - name: "Intel 82802AB", - DevSize: SIZE_512KiB, - CmdSet: P_ID_INTEL_EXT, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,8), - } - }, { - mfr_id: MANUFACTURER_INTEL, - dev_id: I82802AC, - name: "Intel 82802AC", - DevSize: SIZE_1MiB, - CmdSet: P_ID_INTEL_EXT, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,16), - } - }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W800T, - name: "ST M29W800T", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W160DT, - name: "ST M29W160DT", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W160DB, - name: "ST M29W160DB", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49BV512, - name: "Atmel AT49BV512", - DevSize: SIZE_64KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,1) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT29LV512, - name: "Atmel AT29LV512", - DevSize: SIZE_64KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: { - ERASEINFO(0x80,256), - ERASEINFO(0x80,256) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49BV16X, - name: "Atmel AT49BV16X", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x02000,8), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49BV16XT, - name: "Atmel AT49BV16XT", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x02000,8) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49BV32X, - name: "Atmel AT49BV32X", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x02000,8), - ERASEINFO(0x10000,63) - } - }, { - mfr_id: MANUFACTURER_ATMEL, - dev_id: AT49BV32XT, - name: "Atmel AT49BV32XT", - DevSize: SIZE_4MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 2, - regions: {ERASEINFO(0x10000,63), - ERASEINFO(0x02000,8) - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F017D, - name: "AMD AM29F017D", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,32), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F016, - name: "AMD AM29F016", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,32), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F080, - name: "AMD AM29F080", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,16), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F040, - name: "AMD AM29F040", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,8), - } - }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29LV040B, - name: "AMD AM29LV040B", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,8), + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I82802AB, + .name = "Intel 82802AB", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I82802AC, + .name = "Intel 82802AC", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29LV160T, + .name = "MXIC MX29LV160T", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29LV160B, + .name = "MXIC MX29LV160B", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F016, + .name = "Macronix MX29F016", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), } }, { - mfr_id: MANUFACTURER_ST, - dev_id: M29W040B, - name: "ST M29W040B", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,8), - } - }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29LV160T, - name: "MXIC MX29LV160T", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29LV160B, - name: "MXIC MX29LV160B", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29F016, - name: "Macronix MX29F016", - DevSize: SIZE_2MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x10000,32), + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F004T, + .name = "Macronix MX29F004T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), } }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29F004T, - name: "Macronix MX29F004T", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,7), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1), + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F004B, + .name = "Macronix MX29F004B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7), + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL002, + .name = "PMC Pm49FL002", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 64 ) + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL004, + .name = "PMC Pm49FL004", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 128 ) + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL008, + .name = "PMC Pm49FL008", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 256 ) } }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29F004B, - name: "Macronix MX29F004B", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 4, - regions: {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,7), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF512, + .name = "SST 39LF512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,16), } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39LF512, - name: "SST 39LF512", - DevSize: SIZE_64KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,16), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF010, + .name = "SST 39LF010", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_128KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,32), } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39LF010, - name: "SST 39LF010", - DevSize: SIZE_128KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,32), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF020, + .name = "SST 39LF020", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,64), } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39LF020, - name: "SST 39LF020", - DevSize: SIZE_256KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,64), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF040, + .name = "SST 39LF040", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39LF040, - name: "SST 39LF040", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,128), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39SF010A, + .name = "SST 39SF010A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_128KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,32), } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39SF010A, - name: "SST 39SF010A", - DevSize: SIZE_128KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,32), + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39SF020A, + .name = "SST 39SF020A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,64), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF004B, + .name = "SST 49LF004B", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF030A, + .name = "SST 49LF030A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,96), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF040A, + .name = "SST 49LF040A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF080A, + .name = "SST 49LF080A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,256), + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W800DT, + .name = "ST M29W800DT", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W800DB, + .name = "ST M29W800DB", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W160DT, + .name = "ST M29W160DT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W160DB, + .name = "ST M29W160DB", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) } }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST39SF020A, - name: "SST 39SF020A", - DevSize: SIZE_256KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,64), - } - }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST49LF030A, - name: "SST 49LF030A", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,96), - } - }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST49LF040A, - name: "SST 49LF040A", - DevSize: SIZE_512KiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,128), - } - }, { - mfr_id: MANUFACTURER_SST, - dev_id: SST49LF080A, - name: "SST 49LF080A", - DevSize: SIZE_1MiB, - CmdSet: P_ID_AMD_STD, - NumEraseRegions: 1, - regions: {ERASEINFO(0x01000,256), + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W040B, + .name = "ST M29W040B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT160, + .name = "Toshiba TC58FVT160", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB160, + .name = "Toshiba TC58FVB160", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB321, + .name = "Toshiba TC58FVB321", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT321, + .name = "Toshiba TC58FVT321", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB641, + .name = "Toshiba TC58FVB641", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,127) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT641, + .name = "Toshiba TC58FVT641", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,127), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_WINBOND, + .dev_id = W49V002A, + .name = "Winbond W49V002A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000, 3), + ERASEINFO(0x08000, 1), + ERASEINFO(0x02000, 2), + ERASEINFO(0x04000, 1), } } }; @@ -907,7 +1452,7 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index); static int jedec_probe_chip(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi); + unsigned long *chip_map, struct cfi_private *cfi); struct mtd_info *jedec_probe(struct map_info *map); @@ -944,11 +1489,43 @@ * this should be safe. */ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + /* FIXME - should have reset delay before continuing */ +} + + +static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type) +{ + int uaddr_idx; + __u8 uaddr = MTD_UADDR_NOT_SUPPORTED; + + switch ( device_type ) { + case CFI_DEVICETYPE_X8: uaddr_idx = 0; break; + case CFI_DEVICETYPE_X16: uaddr_idx = 1; break; + case CFI_DEVICETYPE_X32: uaddr_idx = 2; break; + default: + printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n", + __func__, device_type); + goto uaddr_done; + } + + uaddr = finfo->uaddr[uaddr_idx]; + if (uaddr != MTD_UADDR_NOT_SUPPORTED ) { + /* ASSERT("The unlock addresses for non-8-bit mode + are bollocks. We don't really need an array."); */ + uaddr = finfo->uaddr[0]; + } + + uaddr_done: + return uaddr; } + + static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) { int i,num_erase_regions; + unsigned long mask; + __u8 uaddr; printk("Found: %s\n",jedec_table[index].name); @@ -971,41 +1548,170 @@ p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i]; } p_cfi->cmdset_priv = 0; + + /* This may be redundant for some cases, but it doesn't hurt */ + p_cfi->mfr = jedec_table[index].mfr_id; + p_cfi->id = jedec_table[index].dev_id; + + uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type); + if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { + kfree( p_cfi->cfiq ); + return 0; + } + + /* Mask out address bits which are smaller than the device type */ + mask = ~(p_cfi->device_type-1); + p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask; + p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask; + return 1; /* ok */ } + +/* + * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing + * the mapped address, unlock addresses, and proper chip ID. This function + * attempts to minimize errors. It is doubtfull that this probe will ever + * be perfect - consequently there should be some module parameters that + * could be manually specified to force the chip info. + */ +static inline int jedec_match( __u32 base, + struct map_info *map, + struct cfi_private *cfi, + const struct amd_flash_info *finfo ) +{ + int rc = 0; /* failure until all tests pass */ + u32 mfr, id; + __u8 uaddr; + unsigned long mask; + + /* + * The IDs must match. For X16 and X32 devices operating in + * a lower width ( X8 or X16 ), the device ID's are usually just + * the lower byte(s) of the larger device ID for wider mode. If + * a part is found that doesn't fit this assumption (device id for + * smaller width mode is completely unrealated to full-width mode) + * then the jedec_table[] will have to be augmented with the IDs + * for different widths. + */ + switch (cfi->device_type) { + case CFI_DEVICETYPE_X8: + mfr = (__u8)finfo->mfr_id; + id = (__u8)finfo->dev_id; + break; + case CFI_DEVICETYPE_X16: + mfr = (__u16)finfo->mfr_id; + id = (__u16)finfo->dev_id; + break; + case CFI_DEVICETYPE_X32: + mfr = (__u16)finfo->mfr_id; + id = (__u32)finfo->dev_id; + break; + default: + printk(KERN_WARNING + "MTD %s(): Unsupported device type %d\n", + __func__, cfi->device_type); + goto match_done; + } + if ( cfi->mfr != mfr || cfi->id != id ) { + goto match_done; + } + + /* the part size must fit in the memory window */ + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", + __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) ); + if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", + __func__, finfo->mfr_id, finfo->dev_id, + 1 << finfo->DevSize ); + goto match_done; + } + + uaddr = finfo_uaddr(finfo, cfi->device_type); + if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { + goto match_done; + } + + mask = ~(cfi->device_type-1); + + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", + __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); + if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr + && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 || + (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): 0x%.4x 0x%.4x did not match\n", + __func__, + unlock_addrs[uaddr].addr1 & mask, + unlock_addrs[uaddr].addr2 & mask); + goto match_done; + } + + /* + * Make sure the ID's dissappear when the device is taken out of + * ID mode. The only time this should fail when it should succeed + * is when the ID's are written as data to the same + * addresses. For this rare and unfortunate case the chip + * cannot be probed correctly. + * FIXME - write a driver that takes all of the chip info as + * module parameters, doesn't probe but forces a load. + */ + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): check ID's disappear when not in ID mode\n", + __func__ ); + jedec_reset( base, map, cfi ); + mfr = jedec_read_mfr( map, base, cfi ); + id = jedec_read_id( map, base, cfi ); + if ( mfr == cfi->mfr && id == cfi->id ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" + "You might need to manually specify JEDEC parameters.\n", + __func__, cfi->mfr, cfi->id ); + goto match_done; + } + + /* all tests passed - mark as success */ + rc = 1; + + /* + * Put the device back in ID mode - only need to do this if we + * were truly frobbing a real device. + */ + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); + if(cfi->addr_unlock1) { + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + } + cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + /* FIXME - should have a delay before continuing */ + + match_done: + return rc; +} + + static int jedec_probe_chip(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi) + unsigned long *chip_map, struct cfi_private *cfi) { int i; - int unlockpass = 0; + enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED; + retry: if (!cfi->numchips) { - switch (cfi->device_type) { - case CFI_DEVICETYPE_X8: - cfi->addr_unlock1 = 0x555; - cfi->addr_unlock2 = 0x2aa; - break; - case CFI_DEVICETYPE_X16: - cfi->addr_unlock1 = 0xaaa; - if (map->buswidth == cfi->interleave) { - /* X16 chip(s) in X8 mode */ - cfi->addr_unlock2 = 0x555; - } else { - cfi->addr_unlock2 = 0x554; - } - break; - case CFI_DEVICETYPE_X32: - cfi->addr_unlock1 = 0x1555; - cfi->addr_unlock2 = 0xaaa; - break; - default: - printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type); - return 0; - } + unsigned long mask = ~(cfi->device_type-1); + + uaddr_idx++; + + if (MTD_UADDR_UNNECESSARY == uaddr_idx) + return 0; + + /* Mask out address bits which are smaller than the device type */ + cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask; + cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask; } - retry: /* Make certain we aren't probing past the end of map */ if (base >= map->size) { printk(KERN_NOTICE @@ -1038,6 +1744,7 @@ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); } cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + /* FIXME - should have a delay before continuing */ if (!cfi->numchips) { /* This is the first time we're called. Set up the CFI @@ -1045,26 +1752,21 @@ cfi->mfr = jedec_read_mfr(map, base, cfi); cfi->id = jedec_read_id(map, base, cfi); - printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + DEBUG(MTD_DEBUG_LEVEL3, + "Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi->interleave, cfi->device_type); for (i=0; imfr == jedec_table[i].mfr_id && - cfi->id == jedec_table[i].dev_id) { + if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", + __func__, cfi->mfr, cfi->id, + cfi->addr_unlock1, cfi->addr_unlock2 ); if (!cfi_jedec_setup(cfi, i)) return 0; goto ok_out; } } - switch(unlockpass++) { - case 0: - cfi->addr_unlock1 |= cfi->addr_unlock1 << 4; - cfi->addr_unlock2 |= cfi->addr_unlock2 << 4; - goto retry; - case 1: - cfi->addr_unlock1 = cfi->addr_unlock2 = 0; - goto retry; - } - return 0; + goto retry; } else { __u16 mfr; __u16 id; @@ -1081,21 +1783,24 @@ } } - /* Check each previous chip to see if it's an alias */ - for (i=0; inumchips; i++) { - /* This chip should be in read mode if it's one - we've already touched. */ - if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr && - jedec_read_id(map, chips[i].start, cfi) == cfi->id) { + /* Check each previous chip locations to see if it's an alias */ + for (i=0; i < (base >> cfi->chipshift); i++) { + unsigned long start; + if(!test_bit(i, chip_map)) { + continue; /* Skip location; no valid chip at this address */ + } + start = i << cfi->chipshift; + if (jedec_read_mfr(map, start, cfi) == cfi->mfr && + jedec_read_id(map, start, cfi) == cfi->id) { /* Eep. This chip also looks like it's in autoselect mode. Is it an alias for the new one? */ - jedec_reset(chips[i].start, map, cfi); + jedec_reset(start, map, cfi); /* If the device IDs go away, it's an alias */ if (jedec_read_mfr(map, base, cfi) != cfi->mfr || jedec_read_id(map, base, cfi) != cfi->id) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", - map->name, base, chips[i].start); + map->name, base, start); return 0; } @@ -1107,7 +1812,7 @@ if (jedec_read_mfr(map, base, cfi) == cfi->mfr && jedec_read_id(map, base, cfi) == cfi->id) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", - map->name, base, chips[i].start); + map->name, base, start); return 0; } } @@ -1115,13 +1820,7 @@ /* OK, if we got to here, then none of the previous chips appear to be aliases for the current one. */ - if (cfi->numchips == MAX_CFI_CHIPS) { - printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS); - /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */ - return -1; - } - chips[cfi->numchips].start = base; - chips[cfi->numchips].state = FL_READY; + set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ cfi->numchips++; ok_out: @@ -1136,8 +1835,8 @@ } static struct chip_probe jedec_chip_probe = { - name: "JEDEC", - probe_chip: jedec_probe_chip + .name = "JEDEC", + .probe_chip = jedec_probe_chip }; struct mtd_info *jedec_probe(struct map_info *map) @@ -1150,9 +1849,9 @@ } static struct mtd_chip_driver jedec_chipdrv = { - probe: jedec_probe, - name: "jedec_probe", - module: THIS_MODULE + .probe = jedec_probe, + .name = "jedec_probe", + .module = THIS_MODULE }; int __init jedec_probe_init(void) diff -Nru a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c --- a/drivers/mtd/chips/map_absent.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/map_absent.c Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* * Common code to handle absent "placeholder" devices * Copyright 2001 Resilience Corporation - * $Id: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_absent.c,v 1.4 2003/05/28 12:51:49 dwmw2 Exp $ * * This map driver is used to allocate "placeholder" MTD * devices on systems that have socketed/removable media. @@ -23,9 +23,10 @@ #include #include #include - +#include +#include #include - +#include static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -36,10 +37,10 @@ static struct mtd_chip_driver map_absent_chipdrv = { - probe: map_absent_probe, - destroy: map_absent_destroy, - name: "map_absent", - module: THIS_MODULE + .probe = map_absent_probe, + .destroy = map_absent_destroy, + .name = "map_absent", + .module = THIS_MODULE }; static struct mtd_info *map_absent_probe(struct map_info *map) @@ -65,7 +66,7 @@ mtd->flags = 0; mtd->erasesize = PAGE_SIZE; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } diff -Nru a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c --- a/drivers/mtd/chips/map_ram.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/map_ram.c Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* * Common code to handle map devices which are simple RAM * (C) 2000 Red Hat. GPL'd. - * $Id: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $ */ #include @@ -11,8 +11,10 @@ #include #include #include - +#include +#include #include +#include static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -23,9 +25,9 @@ static struct mtd_chip_driver mapram_chipdrv = { - probe: map_ram_probe, - name: "map_ram", - module: THIS_MODULE + .probe = map_ram_probe, + .name = "map_ram", + .module = THIS_MODULE }; static struct mtd_info *map_ram_probe(struct map_info *map) @@ -34,21 +36,21 @@ /* Check the first byte is RAM */ #if 0 - map->write8(map, 0x55, 0); - if (map->read8(map, 0) != 0x55) + map_write8(map, 0x55, 0); + if (map_read8(map, 0) != 0x55) return NULL; - map->write8(map, 0xAA, 0); - if (map->read8(map, 0) != 0xAA) + map_write8(map, 0xAA, 0); + if (map_read8(map, 0) != 0xAA) return NULL; /* Check the last byte is RAM */ - map->write8(map, 0x55, map->size-1); - if (map->read8(map, map->size-1) != 0x55) + map_write8(map, 0x55, map->size-1); + if (map_read8(map, map->size-1) != 0x55) return NULL; - map->write8(map, 0xAA, map->size-1); - if (map->read8(map, map->size-1) != 0xAA) + map_write8(map, 0xAA, map->size-1); + if (map_read8(map, map->size-1) != 0xAA) return NULL; #endif /* OK. It seems to be RAM. */ @@ -74,7 +76,7 @@ while(mtd->size & (mtd->erasesize - 1)) mtd->erasesize >>= 1; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } @@ -83,7 +85,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } @@ -92,7 +94,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_to(map, to, buf, len); + map_copy_to(map, to, buf, len); *retlen = len; return 0; } @@ -105,7 +107,7 @@ unsigned long i; for (i=0; ilen; i++) - map->write8(map, 0xFF, instr->addr + i); + map_write8(map, 0xFF, instr->addr + i); if (instr->callback) instr->callback(instr); diff -Nru a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c --- a/drivers/mtd/chips/map_rom.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/map_rom.c Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* * Common code to handle map devices which are simple ROM * (C) 2000 Red Hat. GPL'd. - * $Id: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $ */ #include @@ -12,8 +12,10 @@ #include #include #include - +#include +#include #include +#include static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -21,9 +23,9 @@ struct mtd_info *map_rom_probe(struct map_info *map); static struct mtd_chip_driver maprom_chipdrv = { - probe: map_rom_probe, - name: "map_rom", - module: THIS_MODULE + .probe = map_rom_probe, + .name = "map_rom", + .module = THIS_MODULE }; struct mtd_info *map_rom_probe(struct map_info *map) @@ -49,7 +51,7 @@ while(mtd->size & (mtd->erasesize - 1)) mtd->erasesize >>= 1; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } @@ -58,7 +60,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } diff -Nru a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c --- a/drivers/mtd/chips/sharp.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/chips/sharp.c Thu Dec 4 16:24:25 2003 @@ -4,7 +4,7 @@ * Copyright 2000,2001 David A. Schleef * 2000,2001 Lineo, Inc. * - * $Id: sharp.c,v 1.8 2002/05/17 08:59:19 dwmw2 Exp $ + * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $ * * Devices supported: * LH28F016SCT Symmetrical block flash memory, 2Mx8 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -98,10 +99,10 @@ static void sharp_destroy(struct mtd_info *mtd); static struct mtd_chip_driver sharp_chipdrv = { - probe: sharp_probe, - destroy: sharp_destroy, - name: "sharp", - module: THIS_MODULE + .probe = sharp_probe, + .destroy = sharp_destroy, + .name = "sharp", + .module = THIS_MODULE }; @@ -116,8 +117,10 @@ return NULL; sharp = kmalloc(sizeof(*sharp), GFP_KERNEL); - if(!sharp) + if(!sharp) { + kfree(mtd); return NULL; + } memset(mtd, 0, sizeof(*mtd)); @@ -163,12 +166,12 @@ u32 read0, read4; int width = 4; - tmp = map->read32(map, base+0); + tmp = map_read32(map, base+0); - map->write32(map, CMD_READ_ID, base+0); + map_write32(map, CMD_READ_ID, base+0); - read0=map->read32(map, base+0); - read4=map->read32(map, base+4); + read0=map_read32(map, base+0); + read4=map_read32(map, base+4); if(read0 == 0x89898989){ printk("Looks like sharp flash\n"); switch(read4){ @@ -196,10 +199,10 @@ printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n", read0,read4); } - }else if((map->read32(map, base+0) == CMD_READ_ID)){ + }else if((map_read32(map, base+0) == CMD_READ_ID)){ /* RAM, probably */ printk("Looks like RAM\n"); - map->write32(map, tmp, base+0); + map_write32(map, tmp, base+0); }else{ printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n", read0,read4); @@ -221,10 +224,10 @@ switch(chip->state){ case FL_READY: - map->write32(map,CMD_READ_STATUS,adr); + map_write32(map,CMD_READ_STATUS,adr); chip->state = FL_STATUS; case FL_STATUS: - status = map->read32(map,adr); + status = map_read32(map,adr); //printk("status=%08x\n",status); udelay(100); @@ -252,7 +255,7 @@ goto retry; } - map->write32(map,CMD_RESET, adr); + map_write32(map,CMD_RESET, adr); chip->state = FL_READY; @@ -293,7 +296,7 @@ if(ret<0) break; - map->copy_from(map,buf,ofs,thislen); + map_copy_from(map,buf,ofs,thislen); sharp_release(&sharp->chips[chipnum]); @@ -354,17 +357,17 @@ ret = sharp_wait(map,chip); for(try=0;try<10;try++){ - map->write32(map,CMD_BYTE_WRITE,adr); + map_write32(map,CMD_BYTE_WRITE,adr); /* cpu_to_le32 -> hack to fix the writel be->le conversion */ - map->write32(map,cpu_to_le32(datum),adr); + map_write32(map,cpu_to_le32(datum),adr); chip->state = FL_WRITING; timeo = jiffies + (HZ/2); - map->write32(map,CMD_READ_STATUS,adr); + map_write32(map,CMD_READ_STATUS,adr); for(i=0;i<100;i++){ - status = map->read32(map,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY) break; } @@ -377,9 +380,9 @@ printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); } - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; wake_up(&chip->wq); @@ -436,14 +439,14 @@ int status; DECLARE_WAITQUEUE(wait, current); - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); timeo = jiffies + HZ; while(time_before(jiffies, timeo)){ - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY){ ret = 0; goto out; @@ -485,26 +488,26 @@ sharp_unlock_oneblock(map,chip,adr); #endif - map->write32(map,CMD_BLOCK_ERASE_1,adr); - map->write32(map,CMD_BLOCK_ERASE_2,adr); + map_write32(map,CMD_BLOCK_ERASE_1,adr); + map_write32(map,CMD_BLOCK_ERASE_2,adr); chip->state = FL_ERASING; ret = sharp_do_wait_for_ready(map,chip,adr); if(ret<0)return ret; - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if(!(status&SR_ERRORS)){ - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; //spin_unlock_bh(chip->mutex); return 0; } printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); //spin_unlock_bh(chip->mutex); @@ -518,17 +521,17 @@ int i; int status; - map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); - map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); + map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); + map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); udelay(100); - status = map->read32(map,adr); + status = map_read32(map,adr); printk("status=%08x\n",status); for(i=0;i<1000;i++){ - //map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + //map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY) break; udelay(100); @@ -538,13 +541,13 @@ } if(!(status&SR_ERRORS)){ - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; return; } printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); } #endif diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c --- a/drivers/mtd/cmdlinepart.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/cmdlinepart.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: cmdlinepart.c,v 1.6 2002/11/16 01:37:39 dneuer Exp $ + * $Id: cmdlinepart.c,v 1.11 2003/10/23 08:32:45 dwmw2 Exp $ * * Read flash partition table from command line * @@ -28,7 +28,7 @@ #include #include -#include +#include #include /* error message prefix */ @@ -178,8 +178,7 @@ parts[this_part].mask_flags = mask_flags; if (name) { - strncpy(extra_mem, name, name_len); - extra_mem[name_len] = 0; + strlcpy(extra_mem, name, name_len + 1); } else { @@ -258,8 +257,7 @@ this_mtd->parts = parts; this_mtd->num_parts = num_parts; this_mtd->mtd_id = (char*)(this_mtd + 1); - strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len); - this_mtd->mtd_id[mtd_id_len] = 0; + strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); /* link into chain */ this_mtd->next = partitions; @@ -291,13 +289,14 @@ * information. It returns partitions for the requested mtd device, or * the first one in the chain if a NULL mtd_id is passed in. */ -int parse_cmdline_partitions(struct mtd_info *master, +static int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, - const char *mtd_id) + unsigned long origin) { unsigned long offset; int i; struct cmdline_mtd_partition *part; + char *mtd_id = master->name; if(!cmdline) return -EINVAL; @@ -349,7 +348,25 @@ __setup("mtdparts=", mtdpart_setup); -EXPORT_SYMBOL(parse_cmdline_partitions); +static struct mtd_part_parser cmdline_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_cmdline_partitions, + .name = "cmdlinepart", +}; + +static int __init cmdline_parser_init(void) +{ + return register_mtd_parser(&cmdline_parser); +} + +static void __exit cmdline_parser_exit(void) +{ + deregister_mtd_parser(&cmdline_parser); +} + +module_init(cmdline_parser_init); +module_exit(cmdline_parser_exit); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marius Groeger "); diff -Nru a/drivers/mtd/devices/Config.in b/drivers/mtd/devices/Config.in --- a/drivers/mtd/devices/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/Config.in Thu Dec 4 16:24:25 2003 @@ -1,6 +1,6 @@ -# drivers/mtd/maps/Config.in +# drivers/mtd/devices/Config.in -# $Id: Config.in,v 1.8 2003/01/24 23:25:14 dwmw2 Exp $ +# $Id: Config.in,v 1.11 2003/05/28 10:54:23 dwmw2 Exp $ mainmenu_option next_comment @@ -17,15 +17,6 @@ if [ "$CONFIG_SA1100_LART" = "y" ]; then dep_tristate ' 28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD fi -if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then - dep_tristate ' SyncFlash driver for MX1ADS' CONFIG_MTD_SYNCFLASH $CONFIG_MTD -fi -if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then - dep_tristate ' AT91RM9200 DataFlash support' CONFIG_MTD_AT91_DATAFLASH $CONFIG_MTD - if [ "$CONFIG_MTD_AT91_DATAFLASH" = "y" -o "$CONFIG_MTD_AT91_DATAFLASH" = "m" ]; then - bool ' Enable DataFlash card? ' CONFIG_MTD_AT91_DATAFLASH_CARD - fi -fi dep_tristate ' Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then int 'MTDRAM device size in KiB' CONFIG_MTDRAM_TOTAL_SIZE 4096 @@ -37,13 +28,13 @@ dep_tristate ' MTD emulation using block device' CONFIG_MTD_BLKMTD $CONFIG_MTD comment 'Disk-On-Chip Device Drivers' - dep_tristate ' M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD dep_tristate ' M-Systems Disk-On-Chip 2000 and Millennium' CONFIG_MTD_DOC2000 $CONFIG_MTD dep_tristate ' M-Systems Disk-On-Chip Millennium-only alternative driver (see help)' CONFIG_MTD_DOC2001 $CONFIG_MTD - if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then + dep_tristate ' M-Systems Disk-On-Chip Millennium Plus driver (see help)' CONFIG_MTD_DOC2001PLUS $CONFIG_MTD + if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then define_bool CONFIG_MTD_DOCPROBE y else - if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then + if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then define_bool CONFIG_MTD_DOCPROBE m else define_bool CONFIG_MTD_DOCPROBE n diff -Nru a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile --- a/drivers/mtd/devices/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/Makefile Thu Dec 4 16:24:25 2003 @@ -1,9 +1,12 @@ # # linux/drivers/devices/Makefile # -# $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $ +# $Id: Makefile.common,v 1.4 2003/08/21 17:52:29 joern Exp $ +ifeq ($(PATCHLEVEL),4) O_TARGET := devlink.o +export-objs := docecc.o +endif # *** BIG UGLY NOTE *** # @@ -12,16 +15,16 @@ # here where previously there was none. We now have to ensure that # doc200[01].o are linked before docprobe.o -obj-$(CONFIG_MTD_DOC1000) += doc1000.o obj-$(CONFIG_MTD_DOC2000) += doc2000.o obj-$(CONFIG_MTD_DOC2001) += doc2001.o +obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o +obj-$(CONFIG_MTD_PHRAM) += phram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o -obj-$(CONFIG_MTD_SYNCFLASH) += syncflash.o obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o -include $(TOPDIR)/Rules.make +-include $(TOPDIR)/Rules.make diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c --- a/drivers/mtd/devices/blkmtd.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/blkmtd.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: blkmtd.c,v 1.17 2003/01/24 13:00:24 dwmw2 Exp $ + * $Id: blkmtd.c,v 1.20 2003/06/27 15:10:35 dwmw2 Exp $ * * blkmtd.c - use a block device as a fake MTD * @@ -143,7 +143,7 @@ for(cnt = 0; cnt < pages; cnt++) { page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]); pagelst[cnt] = page; - if(!PageUptodate(page)) { + if(!Page_Uptodate(page)) { iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt]; iobuf->maplist[iobuf->nr_pages++] = page; } @@ -912,7 +912,7 @@ dev->mtd_info.point = 0; dev->mtd_info.unpoint = 0; dev->mtd_info.priv = dev; - dev->mtd_info.module = THIS_MODULE; + dev->mtd_info.owner = THIS_MODULE; list_add(&dev->list, &blkmtd_device_list); if (add_mtd_device(&dev->mtd_info)) { diff -Nru a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c --- a/drivers/mtd/devices/doc2000.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/doc2000.c Thu Dec 4 16:24:25 2003 @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2000.c,v 1.50 2002/12/10 15:05:42 gleixner Exp $ + * $Id: doc2000.c,v 1.58 2003/11/05 16:42:25 dwmw2 Exp $ */ #include @@ -25,6 +25,7 @@ #include #define DOC_SUPPORT_2000 +#define DOC_SUPPORT_2000TSOP #define DOC_SUPPORT_MILLENNIUM #ifdef DOC_SUPPORT_2000 @@ -33,7 +34,7 @@ #define DoC_is_2000(doc) (0) #endif -#ifdef DOC_SUPPORT_MILLENNIUM +#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM) #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil) #else #define DoC_is_Millennium(doc) (0) @@ -56,6 +57,9 @@ size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); +static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel); static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf); static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, @@ -92,6 +96,10 @@ /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(doc, 2); + if (time_after(jiffies, timeo)) { DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); return -EIO; @@ -145,6 +153,8 @@ /* Send the command */ WriteDOC_(command, docptr, doc->ioreg); + if (DoC_is_Millennium(doc)) + WriteDOC(command, docptr, WritePipeTerm); /* Lower the CLE line */ WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); @@ -206,6 +216,9 @@ } } + if (DoC_is_Millennium(doc)) + WriteDOC(ofs & 0xff, docptr, WritePipeTerm); + DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ /* FIXME: The SlowIO's for millennium could be replaced by @@ -344,15 +357,25 @@ /* Read the manufacturer and device id codes from the device */ - /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ - dummy = ReadDOC(doc->virtadr, CDSNSlowIO); - DoC_Delay(doc, 2); - mfr = ReadDOC_(doc->virtadr, doc->ioreg); - - /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ - dummy = ReadDOC(doc->virtadr, CDSNSlowIO); - DoC_Delay(doc, 2); - id = ReadDOC_(doc->virtadr, doc->ioreg); + if (DoC_is_Millennium(doc)) { + DoC_Delay(doc, 2); + dummy = ReadDOC(doc->virtadr, ReadPipeInit); + mfr = ReadDOC(doc->virtadr, LastDataRead); + + DoC_Delay(doc, 2); + dummy = ReadDOC(doc->virtadr, ReadPipeInit); + id = ReadDOC(doc->virtadr, LastDataRead); + } else { + /* CDSN Slow IO register see Software Req 11.4 item 5. */ + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc, 2); + mfr = ReadDOC_(doc->virtadr, doc->ioreg); + + /* CDSN Slow IO register see Software Req 11.4 item 5. */ + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc, 2); + id = ReadDOC_(doc->virtadr, doc->ioreg); + } /* No response - return failure */ if (mfr == 0xff || mfr == 0) @@ -410,20 +433,16 @@ /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ -static void DoC_ScanChips(struct DiskOnChip *this) +static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) { int floor, chip; int numchips[MAX_FLOORS]; - int maxchips = MAX_CHIPS; int ret = 1; this->numchips = 0; this->mfr = 0; this->id = 0; - if (DoC_is_Millennium(this)) - maxchips = MAX_CHIPS_MIL; - /* For each floor, find the number of valid chips it contains */ for (floor = 0; floor < MAX_FLOORS; floor++) { ret = 1; @@ -515,6 +534,7 @@ { struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; struct DiskOnChip *old = NULL; + int maxchips; /* We must avoid being called twice for the same device. */ @@ -538,14 +558,28 @@ switch (this->ChipID) { + case DOC_ChipID_Doc2kTSOP: + mtd->name = "DiskOnChip 2000 TSOP"; + this->ioreg = DoC_Mil_CDSN_IO; + /* Pretend it's a Millennium */ + this->ChipID = DOC_ChipID_DocMil; + maxchips = MAX_CHIPS; + break; case DOC_ChipID_Doc2k: mtd->name = "DiskOnChip 2000"; this->ioreg = DoC_2k_CDSN_IO; + maxchips = MAX_CHIPS; break; case DOC_ChipID_DocMil: mtd->name = "DiskOnChip Millennium"; this->ioreg = DoC_Mil_CDSN_IO; + maxchips = MAX_CHIPS_MIL; break; + default: + printk("Unknown ChipID 0x%02x\n", this->ChipID); + kfree(mtd); + iounmap((void *) this->virtadr); + return; } printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name, @@ -553,11 +587,12 @@ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; + mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; mtd->oobblock = 512; mtd->oobsize = 16; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->erase = doc_erase; mtd->point = NULL; mtd->unpoint = NULL; @@ -565,6 +600,7 @@ mtd->write = doc_write; mtd->read_ecc = doc_read_ecc; mtd->write_ecc = doc_write_ecc; + mtd->writev_ecc = doc_writev_ecc; mtd->read_oob = doc_read_oob; mtd->write_oob = doc_write_oob; mtd->sync = NULL; @@ -577,7 +613,7 @@ init_MUTEX(&this->lock); /* Ident all the chips present. */ - DoC_ScanChips(this); + DoC_ScanChips(this, maxchips); if (!this->totlen) { kfree(mtd); @@ -608,6 +644,7 @@ unsigned char syndrome[6]; volatile char dummy; int i, len256 = 0, ret=0; + size_t left = len; docptr = this->virtadr; @@ -617,122 +654,131 @@ down(&this->lock); - /* Don't allow a single read to cross a 512-byte block boundary */ - if (from + len > ((from | 0x1ff) + 1)) - len = ((from | 0x1ff) + 1) - from; - - /* The ECC will not be calculated correctly if less than 512 is read */ - if (len != 0x200 && eccbuf) - printk(KERN_WARNING - "ECC needs a full sector read (adr: %lx size %lx)\n", - (long) from, (long) len); + *retlen = 0; + while (left) { + len = left; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ((from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; - /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */ + /* The ECC will not be calculated correctly if less than 512 is read */ + if (len != 0x200 && eccbuf) + printk(KERN_WARNING + "ECC needs a full sector read (adr: %lx size %lx)\n", + (long) from, (long) len); + /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */ - /* Find the chip which is to be used and select it */ - mychip = &this->chips[from >> (this->chipshift)]; - if (this->curfloor != mychip->floor) { - DoC_SelectFloor(this, mychip->floor); - DoC_SelectChip(this, mychip->chip); - } else if (this->curchip != mychip->chip) { - DoC_SelectChip(this, mychip->chip); - } + /* Find the chip which is to be used and select it */ + mychip = &this->chips[from >> (this->chipshift)]; - this->curfloor = mychip->floor; - this->curchip = mychip->chip; + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } - DoC_Command(this, - (!this->page256 - && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, - CDSN_CTRL_WP); - DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, - CDSN_CTRL_ECC_IO); - - if (eccbuf) { - /* Prime the ECC engine */ - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_EN, docptr, ECCConf); - } else { - /* disable the ECC engine */ - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; - /* treat crossing 256-byte sector for 2M x 8bits devices */ - if (this->page256 && from + len > (from | 0xff) + 1) { - len256 = (from | 0xff) + 1 - from; - DoC_ReadBuf(this, buf, len256); + DoC_Command(this, + (!this->page256 + && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, + CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, + CDSN_CTRL_ECC_IO); - DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP); - DoC_Address(this, ADDR_COLUMN_PAGE, from + len256, - CDSN_CTRL_WP, CDSN_CTRL_ECC_IO); - } + if (eccbuf) { + /* Prime the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN, docptr, ECCConf); + } else { + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + } - DoC_ReadBuf(this, &buf[len256], len - len256); + /* treat crossing 256-byte sector for 2M x 8bits devices */ + if (this->page256 && from + len > (from | 0xff) + 1) { + len256 = (from | 0xff) + 1 - from; + DoC_ReadBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, from + len256, + CDSN_CTRL_WP, CDSN_CTRL_ECC_IO); + } - /* Let the caller know we completed it */ - *retlen = len; + DoC_ReadBuf(this, &buf[len256], len - len256); - if (eccbuf) { - /* Read the ECC data through the DiskOnChip ECC logic */ - /* Note: this will work even with 2M x 8bit devices as */ - /* they have 8 bytes of OOB per 256 page. mf. */ - DoC_ReadBuf(this, eccbuf, 6); + /* Let the caller know we completed it */ + *retlen += len; - /* Flush the pipeline */ - if (DoC_is_Millennium(this)) { - dummy = ReadDOC(docptr, ECCConf); - dummy = ReadDOC(docptr, ECCConf); - i = ReadDOC(docptr, ECCConf); - } else { - dummy = ReadDOC(docptr, 2k_ECCStatus); - dummy = ReadDOC(docptr, 2k_ECCStatus); - i = ReadDOC(docptr, 2k_ECCStatus); - } + if (eccbuf) { + /* Read the ECC data through the DiskOnChip ECC logic */ + /* Note: this will work even with 2M x 8bit devices as */ + /* they have 8 bytes of OOB per 256 page. mf. */ + DoC_ReadBuf(this, eccbuf, 6); + + /* Flush the pipeline */ + if (DoC_is_Millennium(this)) { + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + i = ReadDOC(docptr, ECCConf); + } else { + dummy = ReadDOC(docptr, 2k_ECCStatus); + dummy = ReadDOC(docptr, 2k_ECCStatus); + i = ReadDOC(docptr, 2k_ECCStatus); + } - /* Check the ECC Status */ - if (i & 0x80) { - int nb_errors; - /* There was an ECC error */ + /* Check the ECC Status */ + if (i & 0x80) { + int nb_errors; + /* There was an ECC error */ #ifdef ECC_DEBUG - printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); + printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. - These syndrome will be all ZERO when there is no error */ - for (i = 0; i < 6; i++) { - syndrome[i] = - ReadDOC(docptr, ECCSyndrome0 + i); - } - nb_errors = doc_decode_ecc(buf, syndrome); + /* Read the ECC syndrom through the DiskOnChip ECC logic. + These syndrome will be all ZERO when there is no error */ + for (i = 0; i < 6; i++) { + syndrome[i] = + ReadDOC(docptr, ECCSyndrome0 + i); + } + nb_errors = doc_decode_ecc(buf, syndrome); #ifdef ECC_DEBUG - printk(KERN_ERR "Errors corrected: %x\n", nb_errors); + printk(KERN_ERR "Errors corrected: %x\n", nb_errors); #endif - if (nb_errors < 0) { - /* We return error, but have actually done the read. Not that - this can be told to user-space, via sys_read(), but at least - MTD-aware stuff can know about it by checking *retlen */ - ret = -EIO; - } - } + if (nb_errors < 0) { + /* We return error, but have actually done the read. Not that + this can be told to user-space, via sys_read(), but at least + MTD-aware stuff can know about it by checking *retlen */ + ret = -EIO; + } + } #ifdef PSYCHO_DEBUG - printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", - (long)from, eccbuf[0], eccbuf[1], eccbuf[2], - eccbuf[3], eccbuf[4], eccbuf[5]); + printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long)from, eccbuf[0], eccbuf[1], eccbuf[2], + eccbuf[3], eccbuf[4], eccbuf[5]); #endif - /* disable the ECC engine */ - WriteDOC(DOC_ECC_DIS, docptr , ECCConf); - } + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + } - /* according to 11.4.1, we need to wait for the busy line - * drop if we read to the end of the page. */ - if(0 == ((from + *retlen) & 0x1ff)) - { - DoC_WaitReady(this); + /* according to 11.4.1, we need to wait for the busy line + * drop if we read to the end of the page. */ + if(0 == ((from + len) & 0x1ff)) + { + DoC_WaitReady(this); + } + + from += len; + left -= len; + buf += len; } up(&this->lock); @@ -757,6 +803,8 @@ volatile char dummy; int len256 = 0; struct Nand *mychip; + size_t left = len; + int status; docptr = this->virtadr; @@ -766,65 +814,133 @@ down(&this->lock); - /* Don't allow a single write to cross a 512-byte block boundary */ - if (to + len > ((to | 0x1ff) + 1)) - len = ((to | 0x1ff) + 1) - to; - - /* The ECC will not be calculated correctly if less than 512 is written */ - if (len != 0x200 && eccbuf) - printk(KERN_WARNING - "ECC needs a full sector write (adr: %lx size %lx)\n", - (long) to, (long) len); + *retlen = 0; + while (left) { + len = left; + + /* Don't allow a single write to cross a 512-byte block boundary */ + if (to + len > ((to | 0x1ff) + 1)) + len = ((to | 0x1ff) + 1) - to; + + /* The ECC will not be calculated correctly if less than 512 is written */ +/* DBB- + if (len != 0x200 && eccbuf) + printk(KERN_WARNING + "ECC needs a full sector write (adr: %lx size %lx)\n", + (long) to, (long) len); + -DBB */ - /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */ + /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */ - /* Find the chip which is to be used and select it */ - mychip = &this->chips[to >> (this->chipshift)]; + /* Find the chip which is to be used and select it */ + mychip = &this->chips[to >> (this->chipshift)]; - if (this->curfloor != mychip->floor) { - DoC_SelectFloor(this, mychip->floor); - DoC_SelectChip(this, mychip->chip); - } else if (this->curchip != mychip->chip) { - DoC_SelectChip(this, mychip->chip); - } + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } - this->curfloor = mychip->floor; - this->curchip = mychip->chip; + this->curfloor = mychip->floor; + this->curchip = mychip->chip; - /* Set device to main plane of flash */ - DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP); - DoC_Command(this, - (!this->page256 - && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, - CDSN_CTRL_WP); + /* Set device to main plane of flash */ + DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_Command(this, + (!this->page256 + && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, + CDSN_CTRL_WP); - DoC_Command(this, NAND_CMD_SEQIN, 0); - DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); - if (eccbuf) { - /* Prime the ECC engine */ - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); - } else { - /* disable the ECC engine */ - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - } + if (eccbuf) { + /* Prime the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + } else { + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + } - /* treat crossing 256-byte sector for 2M x 8bits devices */ - if (this->page256 && to + len > (to | 0xff) + 1) { - len256 = (to | 0xff) + 1 - to; - DoC_WriteBuf(this, buf, len256); + /* treat crossing 256-byte sector for 2M x 8bits devices */ + if (this->page256 && to + len > (to | 0xff) + 1) { + len256 = (to | 0xff) + 1 - to; + DoC_WriteBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_PAGEPROG, 0); + + DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); + /* There's an implicit DoC_WaitReady() in DoC_Command */ + + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + + if (ReadDOC_(docptr, this->ioreg) & 1) { + printk(KERN_ERR "Error programming flash\n"); + /* Error in programming */ + *retlen = 0; + up(&this->lock); + return -EIO; + } + + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0, + CDSN_CTRL_ECC_IO); + } + + DoC_WriteBuf(this, &buf[len256], len - len256); + + if (eccbuf) { + WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, + CDSNControl); + + if (DoC_is_Millennium(this)) { + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + } else { + WriteDOC_(0, docptr, this->ioreg); + WriteDOC_(0, docptr, this->ioreg); + WriteDOC_(0, docptr, this->ioreg); + } + + WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, + CDSNControl); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (di = 0; di < 6; di++) { + eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); + } + + /* Reset the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + +#ifdef PSYCHO_DEBUG + printk + ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + } DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); /* There's an implicit DoC_WaitReady() in DoC_Command */ - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } - if (ReadDOC_(docptr, this->ioreg) & 1) { + if (status & 1) { printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; @@ -832,82 +948,97 @@ return -EIO; } - DoC_Command(this, NAND_CMD_SEQIN, 0); - DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0, - CDSN_CTRL_ECC_IO); + /* Let the caller know we completed it */ + *retlen += len; + + if (eccbuf) { + unsigned char x[8]; + size_t dummy; + int ret; + + /* Write the ECC data to flash */ + for (di=0; di<6; di++) + x[di] = eccbuf[di]; + + x[6]=0x55; + x[7]=0x55; + + ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); + if (ret) { + up(&this->lock); + return ret; + } + } + + to += len; + left -= len; + buf += len; } - DoC_WriteBuf(this, &buf[len256], len - len256); + up(&this->lock); + return 0; +} - if (eccbuf) { - WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, - CDSNControl); +static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + static char static_buf[512]; + static DECLARE_MUTEX(writev_buf_sem); - if (DoC_is_Millennium(this)) { - WriteDOC(0, docptr, NOP); - WriteDOC(0, docptr, NOP); - WriteDOC(0, docptr, NOP); - } else { - WriteDOC_(0, docptr, this->ioreg); - WriteDOC_(0, docptr, this->ioreg); - WriteDOC_(0, docptr, this->ioreg); - } + size_t totretlen = 0; + size_t thisvecofs = 0; + int ret= 0; - /* Read the ECC data through the DiskOnChip ECC logic */ - for (di = 0; di < 6; di++) { - eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); - } + down(&writev_buf_sem); - /* Reset the ECC engine */ - WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + while(count) { + size_t thislen, thisretlen; + unsigned char *buf; -#ifdef PSYCHO_DEBUG - printk - ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", - (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], - eccbuf[4], eccbuf[5]); -#endif - } + buf = vecs->iov_base + thisvecofs; + thislen = vecs->iov_len - thisvecofs; - DoC_Command(this, NAND_CMD_PAGEPROG, 0); - DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); - /* There's an implicit DoC_WaitReady() in DoC_Command */ + if (thislen >= 512) { + thislen = thislen & ~(512-1); + thisvecofs += thislen; + } else { + /* Not enough to fill a page. Copy into buf */ + memcpy(static_buf, buf, thislen); + buf = &static_buf[thislen]; + + while(count && thislen < 512) { + vecs++; + count--; + thisvecofs = min((512-thislen), vecs->iov_len); + memcpy(buf, vecs->iov_base, thisvecofs); + thislen += thisvecofs; + buf += thisvecofs; + } + buf = static_buf; + } + if (count && thisvecofs == vecs->iov_len) { + thisvecofs = 0; + vecs++; + count--; + } + ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel); - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); + totretlen += thisretlen; - if (ReadDOC_(docptr, this->ioreg) & 1) { - printk(KERN_ERR "Error programming flash\n"); - /* Error in programming */ - *retlen = 0; - up(&this->lock); - return -EIO; - } + if (ret || thisretlen != thislen) + break; - /* Let the caller know we completed it */ - *retlen = len; - - if (eccbuf) { - unsigned char x[8]; - size_t dummy; - int ret; - - /* Write the ECC data to flash */ - for (di=0; di<6; di++) - x[di] = eccbuf[di]; - - x[6]=0x55; - x[7]=0x55; - - ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); - up(&this->lock); - return ret; - } - up(&this->lock); - return 0; + to += thislen; + } + + up(&writev_buf_sem); + *retlen = totretlen; + return ret; } + static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, u_char * buf) { @@ -977,6 +1108,7 @@ unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; volatile int dummy; + int status; // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); @@ -1025,10 +1157,16 @@ DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } - if (ReadDOC_(docptr, this->ioreg) & 1) { + if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; @@ -1044,10 +1182,16 @@ DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } - if (ReadDOC_(docptr, this->ioreg) & 1) { + if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; @@ -1080,6 +1224,7 @@ volatile int dummy; unsigned long docptr; struct Nand *mychip; + int status; down(&this->lock); @@ -1111,10 +1256,16 @@ DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); - - if (ReadDOC_(docptr, this->ioreg) & 1) { + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } + + if (status & 1) { printk(KERN_ERR "Error erasing at 0x%x\n", ofs); /* There was an error */ instr->state = MTD_ERASE_FAILED; diff -Nru a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c --- a/drivers/mtd/devices/doc2001.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/devices/doc2001.c Thu Dec 4 16:24:26 2003 @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001.c,v 1.38 2002/12/10 15:05:42 gleixner Exp $ + * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $ */ #include @@ -359,14 +359,15 @@ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; + mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; - /* FIXME: erase size is not always 8kB */ + /* FIXME: erase size is not always 8KiB */ mtd->erasesize = 0x2000; mtd->oobblock = 512; mtd->oobsize = 16; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->erase = doc_erase; mtd->point = NULL; mtd->unpoint = NULL; diff -Nru a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c --- a/drivers/mtd/devices/docecc.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/docecc.c Thu Dec 4 16:24:25 2003 @@ -7,7 +7,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $ * * 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 @@ -518,6 +518,8 @@ kfree(Index_of); return nb_errors; } + +EXPORT_SYMBOL_GPL(doc_decode_ecc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Fabrice Bellard "); diff -Nru a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c --- a/drivers/mtd/devices/docprobe.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/docprobe.c Thu Dec 4 16:24:25 2003 @@ -4,7 +4,7 @@ /* (C) 1999 Machine Vision Holdings, Inc. */ /* (C) 1999-2003 David Woodhouse */ -/* $Id: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $ */ +/* $Id: docprobe.c,v 1.40 2003/11/05 10:51:37 dwmw2 Exp $ */ @@ -31,14 +31,12 @@ /* DOC_SINGLE_DRIVER: Millennium driver has been merged into DOC2000 driver. - The newly-merged driver doesn't appear to work for writing. It's the - same with the DiskOnChip 2000 and the Millennium. If you have a - Millennium and you want write support to work, remove the definition - of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver. - - Otherwise, it's left on in the hope that it'll annoy someone with - a Millennium enough that they go through and work out what the - difference is :) + The old Millennium-only driver has been retained just in case there + are problems with the new code. If the combined driver doesn't work + for you, you can try the old one by undefining DOC_SINGLE_DRIVER + below and also enabling it in your configuration. If this fixes the + problems, please send a report to the MTD mailing list at + . */ #define DOC_SINGLE_DRIVER @@ -47,18 +45,15 @@ #include #include #include -#include -#include -#include #include #include -#include #include #include #include #include #include +#include /* Where to look for the devices? */ #ifndef CONFIG_MTD_DOCPROBE_ADDRESS @@ -95,14 +90,14 @@ ##else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif - 0 }; + 0xffffffff }; /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ static inline int __init doccheck(unsigned long potential, unsigned long physadr) { unsigned long window=potential; - unsigned char tmp, ChipID; + unsigned char tmp, tmpb, tmpc, ChipID; #ifndef DOC_PASSIVE_PROBE unsigned char tmp2; #endif @@ -140,26 +135,80 @@ window, DOCControl); #endif /* !DOC_PASSIVE_PROBE */ + /* We need to read the ChipID register four times. For some + newer DiskOnChip 2000 units, the first three reads will + return the DiskOnChip Millennium ident. Don't ask. */ ChipID = ReadDOC(window, ChipID); switch (ChipID) { case DOC_ChipID_Doc2k: /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; - if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp) + tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) return ChipID; break; case DOC_ChipID_DocMil: + /* Check for the new 2000 with Millennium ASIC */ + ReadDOC(window, ChipID); + ReadDOC(window, ChipID); + if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil) + ChipID = DOC_ChipID_Doc2kTSOP; + /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; - if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp) + tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) return ChipID; break; + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + case 0: + /* Possible Millennium+, need to do more checks */ +#ifndef DOC_PASSIVE_PROBE + /* Possibly release from power down mode */ + for (tmp = 0; (tmp < 4); tmp++) + ReadDOC(window, Mplus_Power); + + /* Reset the DiskOnChip ASIC */ + tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + + mdelay(1); + /* Enable the DiskOnChip ASIC */ + tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + mdelay(1); +#endif /* !DOC_PASSIVE_PROBE */ + + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + /* Check the TOGGLE bit in the toggle register */ + tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) + return ChipID; + default: + break; + } + /* FALL TRHU */ + default: -#ifndef CONFIG_MTD_DOCPROBE_55AA - printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", + +#ifdef CONFIG_MTD_DOCPROBE_55AA + printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", ChipID, physadr); #endif #ifndef DOC_PASSIVE_PROBE @@ -221,6 +270,12 @@ sprintf(namebuf, "with ChipID %2.2X", ChipID); switch(ChipID) { + case DOC_ChipID_Doc2kTSOP: + name="2000 TSOP"; + im_funcname = "DoC2k_init"; + im_modname = "doc2000"; + break; + case DOC_ChipID_Doc2k: name="2000"; im_funcname = "DoC2k_init"; @@ -237,6 +292,13 @@ im_modname = "doc2001"; #endif /* DOC_SINGLE_DRIVER */ break; + + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + name="MillenniumPlus"; + im_funcname = "DoCMilPlus_init"; + im_modname = "doc2001plus"; + break; } if (im_funcname) @@ -248,6 +310,7 @@ return; } printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr); + kfree(mtd); } iounmap((void *)docptr); } @@ -267,7 +330,7 @@ printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); DoC_Probe(doc_config_location); } else { - for (i=0; doc_locations[i]; i++) { + for (i=0; (doc_locations[i] != 0xffffffff); i++) { DoC_Probe(doc_locations[i]); } } @@ -275,11 +338,7 @@ found, so the user knows we at least tried. */ if (!docfound) printk(KERN_INFO "No recognised DiskOnChip devices found\n"); - /* So it looks like we've been used and we get unloaded */ - MOD_INC_USE_COUNT; - MOD_DEC_USE_COUNT; - return 0; - + return -EAGAIN; } module_init(init_doc); diff -Nru a/drivers/mtd/devices/ixm1200.c b/drivers/mtd/devices/ixm1200.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/devices/ixm1200.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,574 @@ +/* + * drivers/mtd/devices/ixm1200.c + * + * MTD driver for the 28F320C3 Flash Memory on IXM1200 NPU Base Card + * + * Inspired Abraham vd Merwe 28F160F3 Flash memory driver on Lart. + * + * Copyright (c) 2001, 2d3D, Inc. + * + * Ported to 28F320C3 by Nikunj A Dadhania + * + * This code 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. + * + * + */ + +/* Comment this for prodution release */ +// #define IXM1200_DEBUG */ + +/* partition support */ +#define HAVE_PARTITIONS + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PARTITIONS +#include +#endif + +#include + +#ifndef CONFIG_ARCH_IXM1200 +#error This is for IXM1200 NPU Base Board only +#endif + +static char module_name[] = "ixm1200"; + +/* + * These values is specific to 28FxxC3 flash memory. + * See in "3 Volt Advanced+ Boot Block Flash Memory" Intel Datasheet + * + * The documentation is actually incorrect. It says that each param + * block is 4096 and that the 32Mb(4MB) part has 63 main blocks + * at 32K each. 32K * 63 + 4K * 8 == 16Mb (2MB). So either the + * block size or the block count is wrong in the docs. + * + */ +#define FLASH_BLOCKSIZE_PARAM (8192) +#define FLASH_NUMBLOCKS_16m_PARAM 8 +#define FLASH_NUMBLOCKS_8m_PARAM 8 + +/* + * These values is specific to 28FxxxC3 flash memory. + * See in "3 Volt Advanced+ Boot Block Flash Memory" Intel Datasheet + */ +#define FLASH_BLOCKSIZE_MAIN (65536) +#define FLASH_NUMBLOCKS_16m_MAIN 63 +#define FLASH_NUMBLOCKS_8m_MAIN 15 + +/* + * These values are specific to IMX1200 + */ + +/* don't change this - a lot of the code _will_ break if you change this */ +#define BUSWIDTH 4 + +/* + * See Table 6 in "3 Volt Advanced+ Boot Block Flash Memory" Intel Datasheet + */ +#define F28CMD_READ_ID 0x90909090 +#define F28CMD_ERASE_SETUP 0x20202020 +#define F28CMD_ERASE_CONFIRM 0xd0d0d0d0 +#define F28CMD_PROGRAM_SETUP 0x40404040 +#define F28CMD_READ_ARRAY 0xFFFFFFFF +#define F28CMD_READ_STATUS 0x70707070 +#define F28CMD_CLEAR_STATUS 0x50505050 +#define F28CMD_RESET F28CMD_READ_ARRAY +#define F28CMD_CFGSETUP 0x60606060 +#define F28CMD_CFGUNLOCK 0xd0d0d0d0 + +#define F28_MANUF_ID 0x0089 +#define FTYPE_28F320C3B 0x88C5 + +#define BOOT_BLOCK_GROUP_SIZE 0x10000 +#define FLASH_DEVICE_SIZE 0x400000 + +#define BIT(i) (1 << (i)) + +unsigned long flash_base = 0; + +void ixm1200_clear_status(void) +{ + volatile unsigned long *lptr = (unsigned long *)flash_base; + *lptr = F28CMD_CLEAR_STATUS; +} + +void ixm1200_reset(void) +{ + volatile unsigned long *lptr = (unsigned long *)flash_base; + *lptr = F28CMD_RESET; +} + +static __u8 ixm1200_read8 (__u32 offset) +{ + volatile __u8 *data = (__u8 *) (flash_base + offset); +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n",__FUNCTION__,offset,*data); +#endif + return (*data); +} + +static __u32 ixm1200_read32 (__u32 offset) +{ + volatile __u32 *data = (__u32 *) (flash_base + offset); +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n",__FUNCTION__,offset,*data); +#endif + return (*data); +} + + +/* + * If I don't use this delay the hardware which I am working is not + * behaving consistently so the delay can be removed if not required. + */ +void si_write(volatile unsigned long *lptr, unsigned long data) +{ + *lptr = F28CMD_PROGRAM_SETUP; + mdelay(1); + *lptr = data; + + /* after writing the flash will always be in read status register mode */ + + while(!(*lptr & BIT(7))) /* status of the first device */ + ; +} + +static int ixm1200_probe (void) +{ + unsigned long l_mfrid; + unsigned short mfrid, devid; + + /* setup "Read Identifier Codes" mode */ + *(unsigned long *)flash_base = F28CMD_READ_ID; + + l_mfrid = ixm1200_read32 (0x00000000); + mfrid = (unsigned short)l_mfrid; + devid = (unsigned short)(l_mfrid >>16); + + /* put the flash back into command mode */ + ixm1200_reset(); + + printk("Flash manufacturer id %x device id %x at %x\n", mfrid, devid, flash_base); + + return (mfrid == F28_MANUF_ID && (devid == FTYPE_28F320C3B )); +} + +/* + * Erase one block of flash memory at offset ``offset'' which is any + * address within the block which should be erased. + * + * Returns 1 if successful, 0 otherwise. + */ +static inline int ixm1200_erase_block (__u32 offset) +{ + volatile unsigned long *data = + (unsigned long*)(flash_base + 2 * offset); + int ix; + +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(): %#010x\n",__FUNCTION__,data); +#endif + + *data = F28CMD_CFGSETUP; + *data = F28CMD_CFGUNLOCK; + + *data = F28CMD_ERASE_SETUP; + /* I am playing little safe. This will be removed when I am sure that its not really required */ + mdelay(1); + *data = F28CMD_ERASE_CONFIRM; + + + /* after erasing, the flash will always be in read status register mode */ + + for(ix = (BUSWIDTH/2) - 1; ix >=0; ix--) + { + while(!(*data & BIT(7))) /* status of the first device */ + ; + + if(*data & BIT(6)) { + printk("Erasing suspended status %x\n", *data); + *data = F28CMD_ERASE_CONFIRM; + printk("Trying to resume erasing\n"); + while(!(*data & BIT(7))) /* status of the first device */ + ; + + } + + if((*data & (BIT(6) | BIT(5) | BIT(3) | BIT(1))) ) { + printk("%s(): Error in erasing flash, status is %x\n",__FUNCTION__, *data); + ixm1200_clear_status(); + return 0; + } + ixm1200_clear_status(); + ixm1200_reset(); + return (1); + } +} + +static int ixm1200_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + __u32 addr,len; + int i,first; + +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); +#endif + + /* sanity checks */ + if (instr->addr + instr->len > mtd->size) return (-EINVAL); + + /* + * check that both start and end of the requested erase are + * aligned with the erasesize at the appropriate addresses. + * + * skip all erase regions which are ended before the start of + * the requested erase. Actually, to save on the calculations, + * we skip to the first erase region which starts after the + * start of the requested erase, and then go back one. + */ + for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ; + i--; + + /* + * ok, now i is pointing at the erase region in which this + * erase request starts. Check the start of the requested + * erase range is aligned with the erase size which is in + * effect here. + */ + if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); + + /* Remember the erase region we start on */ + first = i; + + /* + * next, check that the end of the requested erase is aligned + * with the erase region at that address. + * + * as before, drop back one to point at the region in which + * the address actually falls + */ + for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ; + i--; + + /* is the end aligned on a block boundary? */ + if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) + return (-EINVAL); + + addr = instr->addr; + len = instr->len; + + i = first; + +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(erasesize = 0x%.8x)\n",__FUNCTION__,mtd->eraseregions[i].erasesize); +#endif + + /* now erase those blocks */ + while (len) + { + if(!ixm1200_erase_block (addr)) + { + instr->state = MTD_ERASE_FAILED; + return (-EIO); + } + + addr += mtd->eraseregions[i].erasesize; + len -= mtd->eraseregions[i].erasesize; + + if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++; + } + + instr->state = MTD_ERASE_DONE; + if (instr->callback) instr->callback (instr); + + return (0); +} + +static int ixm1200_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf) +{ +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,len); +#endif + + /* sanity checks */ + if (!len) return (0); + if (from + len > mtd->size) return (-EINVAL); + + /* we always read len bytes */ + *retlen = len; + + /* first, we read bytes until we reach a dword boundary */ + if (from & (BUSWIDTH - 1)) + { + int gap = BUSWIDTH - (from & (BUSWIDTH - 1)); + + while (len && gap--) *buf++ = ixm1200_read8(from++), len--; + + } + + /* now we read dwords until we reach a non-dword boundary */ + while (len >= BUSWIDTH) + { + *((__u32 *) buf) = ixm1200_read32(from); + + buf += BUSWIDTH; + from += BUSWIDTH; + len -= BUSWIDTH; + } + + /* top up the last unaligned bytes */ + if (len & (BUSWIDTH - 1)) + while (len--) *buf++ = ixm1200_read8(from++); + + return (0); +} + +/* + * Write one dword ``x'' to flash memory at offset ``offset''. ``offset'' + * must be 32 bits, i.e. it must be on a dword boundary. + * + * Returns 1 if successful, 0 otherwise. + */ +static inline int ixm1200_write_dword (__u32 offset, __u32 x) +{ + +/* + * Due to some unidentified reasons which I not able to comprehend the + * char driver that Intel has provided writes to the offset * 2 if he + * wants to write a dword at offset with respect to the flash_base. + * + */ + unsigned long *lptr = (unsigned long *)(flash_base + 2 * offset); +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n",__FUNCTION__,offset,x); +#endif + + *lptr = F28CMD_CFGSETUP; + *lptr = F28CMD_CFGUNLOCK; + +#ifdef IXM1200_DEBUG + printk(KERN_DEBUG "programming %x in location %x\n", x & 0xffff, lptr); +#endif + + si_write(lptr++ ,x & 0xFFFF); + si_write(lptr++ ,(x >> 16) & 0xFFFF); + + if ((*lptr) & (BIT(5) | BIT(4) | BIT(3) | BIT(1))) + { + printk("Status is : %x\n",*lptr); + ixm1200_clear_status(); + ixm1200_reset(); + return -ENXIO; + } + ixm1200_reset(); + return (1); +} + + +static int ixm1200_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) +{ + int retVal=0, i, n, gap, count=0; + unsigned long *lptr = (unsigned long *)(flash_base + 2 * to); + unsigned long *lbuf = (unsigned long *)buf; + __u8 tmp[4]; + +#ifdef IXM1200_DEBUG + printk ("%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len); +#endif + + *retlen = 0; + + /* sanity checks */ + if (!len) return (0); + if (to + len > mtd->size) return (-EINVAL); + /* Write until we hit the dword boundary */ + if(to & (BUSWIDTH - 1)) + { + __u32 aligned = to & ~(BUSWIDTH - 1); + gap = to - aligned; + *((u32 *)tmp) = ixm1200_read32(aligned); + + i = n = 0; + + while(gap--) i++; + while(len-- && i < BUSWIDTH) tmp[i++] = buf[n++]; + // while(i < BUSWIDTH) tmp[i++]=0xFF; + + lbuf=(unsigned long *)tmp; + + if(ixm1200_write_dword(aligned, tmp) != 1) return -EIO; + + to += n; + buf += n; + *retlen +=n; + } + + while(len >=BUSWIDTH) + { + u32 val = *((u32 *)buf); + + if(ixm1200_write_dword(to, val) != 1) return -EIO; + to += BUSWIDTH; + buf += BUSWIDTH; + *retlen += BUSWIDTH; + len -= BUSWIDTH; + } + n = *retlen; + if (len & (BUSWIDTH - 1)) + { + *((u32 *)tmp) = ixm1200_read32(to); + + printk(KERN_DEBUG "Read (%#010x) from flash\n", *((u32 *)tmp)); + + i = n = 0; + while (len--) { + printk(KERN_DEBUG "Unaligned bytes %c(%#04x) %d %d\n", buf[n], buf[n], n, i); + tmp[i++] = buf[n++]; + } + + printk(KERN_DEBUG "Write (%#010x) to flash\n", *((u32 *)tmp)); + + if(ixm1200_write_dword(to, *((__u32 *)tmp)) != 1) return -EIO; + *retlen += n; + } + + ixm1200_reset(); + return (0); +} + + +#define NB_OF(x) (sizeof (x) / sizeof (x[0])) + +static struct mtd_info mtd; + +static struct mtd_erase_region_info si_erase_regions[] = +{ + /* parameter blocks */ + { + offset: 0x00000000, + erasesize: FLASH_BLOCKSIZE_PARAM, + numblocks: FLASH_NUMBLOCKS_16m_PARAM + }, + /* main blocks */ + { + offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, + erasesize: FLASH_BLOCKSIZE_MAIN, + numblocks: FLASH_NUMBLOCKS_16m_MAIN + } +}; + +#ifdef HAVE_PARTITIONS +static struct mtd_partition si_partitions[] = +{ + { + name: "BootManager", + offset: 0, + size: 0x200000, + mask_flags: MTD_WRITEABLE + }, + { + name: "file system", + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } +}; +#endif + +int __init ixm1200_init (void) +{ + int result; + memset (&mtd,0,sizeof (mtd)); + + flash_base = (unsigned long)ioremap(0x00000000, FLASH_DEVICE_SIZE*2); + + printk ("%s: Probing for 28F320x3 flash on IXM1200\n",module_name); + + if (!ixm1200_probe ()) + { + printk (KERN_WARNING "%s: Found no IXM1200 compatible flash device\n",module_name); + return (-ENXIO); + } + + mtd.name = module_name; + mtd.type = MTD_NORFLASH; + mtd.flags = MTD_CAP_NORFLASH; + mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; + mtd.erasesize = FLASH_BLOCKSIZE_MAIN; + mtd.numeraseregions = NB_OF (si_erase_regions); + mtd.eraseregions = si_erase_regions; + mtd.module = THIS_MODULE; + mtd.erase = ixm1200_erase; + mtd.read = ixm1200_read; + mtd.write = ixm1200_write; + +#ifdef IXM1200_DEBUG + printk (KERN_DEBUG + "mtd.name = %s\n" + "mtd.size = 0x%.8x (%uM)\n" + "mtd.erasesize = 0x%.8x (%uK)\n" + "mtd.numeraseregions = %d\n", + mtd.name, + mtd.size,mtd.size / (1024*1024), + mtd.erasesize,mtd.erasesize / 1024, + mtd.numeraseregions); + + if (mtd.numeraseregions) + for (result = 0; result < mtd.numeraseregions; result++) + printk (KERN_DEBUG + "\n\n" + "mtd.eraseregions[%d].offset = 0x%.8x\n" + "mtd.eraseregions[%d].erasesize = 0x%.8x (%uK)\n" + "mtd.eraseregions[%d].numblocks = %d\n", + result,mtd.eraseregions[result].offset, + result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, + result,mtd.eraseregions[result].numblocks); + +#ifdef HAVE_PARTITIONS + printk ("\npartitions = %d\n",NB_OF (si_partitions)); + + for (result = 0; result < NB_OF (si_partitions); result++) + printk (KERN_DEBUG + "\n\n" + "si_partitions[%d].name = %s\n" + "si_partitions[%d].offset = 0x%.8x\n" + "si_partitions[%d].size = 0x%.8x (%uK)\n", + result,si_partitions[result].name, + result,si_partitions[result].offset, + result,si_partitions[result].size,si_partitions[result].size / 1024); +#endif +#endif + +#ifndef HAVE_PARTITIONS + result = add_mtd_device (&mtd); +#else + result = add_mtd_partitions (&mtd,si_partitions,NB_OF (si_partitions)); +#endif + + return (result); +} + +void __exit ixm1200_exit (void) +{ +#ifndef HAVE_PARTITIONS + del_mtd_device (&mtd); +#else + del_mtd_partitions (&mtd); +#endif +} + +module_init (ixm1200_init); +module_exit (ixm1200_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nikunj A. Dadhania "); +MODULE_DESCRIPTION("MTD driver for Intel 28F320C3 on IXM1200 board"); + + diff -Nru a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c --- a/drivers/mtd/devices/lart.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/lart.c Thu Dec 4 16:24:25 2003 @@ -2,7 +2,7 @@ /* * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. * - * $Id: lart.c,v 1.2 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $ * * Author: Abraham vd Merwe * @@ -584,46 +584,41 @@ static struct mtd_info mtd; -static struct mtd_erase_region_info erase_regions[] = -{ - /* parameter blocks */ - { - offset: 0x00000000, - erasesize: FLASH_BLOCKSIZE_PARAM, - numblocks: FLASH_NUMBLOCKS_16m_PARAM - }, - /* main blocks */ - { - offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, - erasesize: FLASH_BLOCKSIZE_MAIN, - numblocks: FLASH_NUMBLOCKS_16m_MAIN - } +static struct mtd_erase_region_info erase_regions[] = { + /* parameter blocks */ + { + .offset = 0x00000000, + .erasesize = FLASH_BLOCKSIZE_PARAM, + .numblocks = FLASH_NUMBLOCKS_16m_PARAM, + }, + /* main blocks */ + { + .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, + .erasesize = FLASH_BLOCKSIZE_MAIN, + .numblocks = FLASH_NUMBLOCKS_16m_MAIN, + } }; #ifdef HAVE_PARTITIONS -static struct mtd_partition lart_partitions[] = -{ - /* blob */ - { - name: "blob", - offset: BLOB_START, - size: BLOB_LEN, - mask_flags: 0 - }, - /* kernel */ - { - name: "kernel", - offset: KERNEL_START, /* MTDPART_OFS_APPEND */ - size: KERNEL_LEN, - mask_flags: 0 - }, - /* initial ramdisk / file system */ - { - name: "file system", - offset: INITRD_START, /* MTDPART_OFS_APPEND */ - size: INITRD_LEN, /* MTDPART_SIZ_FULL */ - mask_flags: 0 - } +static struct mtd_partition lart_partitions[] = { + /* blob */ + { + .name = "blob", + .offset = BLOB_START, + .size = BLOB_LEN, + }, + /* kernel */ + { + .name = "kernel", + .offset = KERNEL_START, /* MTDPART_OFS_APPEND */ + .size = KERNEL_LEN, + }, + /* initial ramdisk / file system */ + { + .name = "file system", + .offset = INITRD_START, /* MTDPART_OFS_APPEND */ + .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ + } }; #endif @@ -646,10 +641,10 @@ mtd.erasesize = FLASH_BLOCKSIZE_MAIN; mtd.numeraseregions = NB_OF (erase_regions); mtd.eraseregions = erase_regions; - mtd.module = THIS_MODULE; mtd.erase = flash_erase; mtd.read = flash_read; mtd.write = flash_write; + mtd.owner = THIS_MODULE; #ifdef LART_DEBUG printk (KERN_DEBUG diff -Nru a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c --- a/drivers/mtd/devices/ms02-nv.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/ms02-nv.c Thu Dec 4 16:24:25 2003 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001 Maciej W. Rozycki + * Copyright (c) 2001 Maciej W. Rozycki * - * 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 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. * - * $Id: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $ + * $Id: ms02-nv.c,v 1.6 2003/08/19 09:25:36 dwmw2 Exp $ */ #include @@ -29,7 +29,7 @@ static char version[] __initdata = - "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n"; + "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n"; MODULE_AUTHOR("Maciej W. Rozycki "); MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver"); @@ -38,9 +38,9 @@ /* * Addresses we probe for an MS02-NV at. Modules may be located - * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB - * boundary within a 0MB up to 448MB range. We don't support a module - * at 0MB, though. + * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB + * boundary within a 0MiB up to 448MiB range. We don't support a module + * at 0MiB, though. */ static ulong ms02nv_addrs[] __initdata = { 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000, @@ -130,7 +130,7 @@ int ret = -ENODEV; - /* The module decodes 8MB of address space. */ + /* The module decodes 8MiB of address space. */ mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL); if (!mod_res) return -ENOMEM; @@ -222,7 +222,7 @@ mtd->flags = MTD_CAP_RAM | MTD_XIP; mtd->size = fixsize; mtd->name = (char *)ms02nv_name; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->read = ms02nv_read; mtd->write = ms02nv_write; @@ -233,7 +233,7 @@ goto err_out_csr_res; } - printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n", + printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n", mtd->index, ms02nv_name, addr, size >> 20); mp->next = root_ms02nv_mtd; @@ -293,12 +293,12 @@ switch (mips_machtype) { case MACH_DS5000_200: - csr = (volatile u32 *)KN02_CSR_ADDR; + csr = (volatile u32 *)KN02_CSR_BASE; if (*csr & KN02_CSR_BNK32M) stride = 2; break; case MACH_DS5000_2X0: - case MACH_DS5000: + case MACH_DS5900: csr = (volatile u32 *)KN03_MCR_BASE; if (*csr & KN03_MCR_BNK32M) stride = 2; diff -Nru a/drivers/mtd/devices/ms02-nv.h b/drivers/mtd/devices/ms02-nv.h --- a/drivers/mtd/devices/ms02-nv.h Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/ms02-nv.h Thu Dec 4 16:24:25 2003 @@ -1,31 +1,95 @@ /* - * Copyright (c) 2001 Maciej W. Rozycki + * Copyright (c) 2001, 2003 Maciej W. Rozycki * - * 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. + * DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for + * DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260 + * systems. + * + * 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. + * + * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $ */ #include #include +/* + * Addresses are decoded as follows: + * + * 0x000000 - 0x3fffff SRAM + * 0x400000 - 0x7fffff CSR + * + * Within the SRAM area the following ranges are forced by the system + * firmware: + * + * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot + * 0x000400 - ENDofRAM storage area, available to operating systems + * + * but we can't really use the available area right from 0x000400 as + * the first word is used by the firmware as a status flag passed + * from an operating system. If anything but the valid data magic + * ID value is found, the firmware considers the SRAM clean, i.e. + * containing no valid data, and disables the battery resulting in + * data being erased as soon as power is switched off. So the choice + * for the start address of the user-available is 0x001000 which is + * nicely page aligned. The area between 0x000404 and 0x000fff may + * be used by the driver for own needs. + * + * The diagnostic area defines two status words to be read by an + * operating system, a magic ID to distinguish a MS02-NV board from + * anything else and a status information providing results of tests + * as well as the size of SRAM available, which can be 1MiB or 2MiB + * (that's what the firmware handles; no idea if 2MiB modules ever + * existed). + * + * The firmware only handles the MS02-NV board if installed in the + * last (15th) slot, so for any other location the status information + * stored in the SRAM cannot be relied upon. But from the hardware + * point of view there is no problem using up to 14 such boards in a + * system -- only the 1st slot needs to be filled with a DRAM module. + * The MS02-NV board is ECC-protected, like other MS02 memory boards. + * + * The state of the battery as provided by the CSR is reflected on + * the two onboard LEDs. When facing the battery side of the board, + * with the LEDs at the top left and the battery at the bottom right + * (i.e. looking from the back side of the system box), their meaning + * is as follows (the system has to be powered on): + * + * left LED battery disable status: lit = enabled + * right LED battery condition status: lit = OK + */ + /* MS02-NV iomem register offsets. */ #define MS02NV_CSR 0x400000 /* control & status register */ +/* MS02-NV CSR status bits. */ +#define MS02NV_CSR_BATT_OK 0x01 /* battery OK */ +#define MS02NV_CSR_BATT_OFF 0x02 /* battery disabled */ + + /* MS02-NV memory offsets. */ #define MS02NV_DIAG 0x0003f8 /* diagnostic status */ #define MS02NV_MAGIC 0x0003fc /* MS02-NV magic ID */ -#define MS02NV_RAM 0x000400 /* general-purpose RAM start */ +#define MS02NV_VALID 0x000400 /* valid data magic ID */ +#define MS02NV_RAM 0x001000 /* user-exposed RAM start */ -/* MS02-NV diagnostic status constants. */ -#define MS02NV_DIAG_SIZE_MASK 0xf0 /* RAM size mask */ -#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* RAM size shift (left) */ +/* MS02-NV diagnostic status bits. */ +#define MS02NV_DIAG_TEST 0x01 /* SRAM test done (?) */ +#define MS02NV_DIAG_RO 0x02 /* SRAM r/o test done */ +#define MS02NV_DIAG_RW 0x04 /* SRAM r/w test done */ +#define MS02NV_DIAG_FAIL 0x08 /* SRAM test failed */ +#define MS02NV_DIAG_SIZE_MASK 0xf0 /* SRAM size mask */ +#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* SRAM size shift (left) */ /* MS02-NV general constants. */ #define MS02NV_ID 0x03021966 /* MS02-NV magic ID value */ +#define MS02NV_VALID_ID 0xbd100248 /* valid data magic ID value */ #define MS02NV_SLOT_SIZE 0x800000 /* size of the address space decoded by the module */ + typedef volatile u32 ms02nv_uint; diff -Nru a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c --- a/drivers/mtd/devices/mtdram.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/mtdram.c Thu Dec 4 16:24:25 2003 @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.29 2002/10/21 13:40:06 jocke Exp $ + * $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $ * Author: Alexander Larsson * * Copyright (c) 1999 Alexander Larsson @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -136,7 +138,7 @@ mtd->erasesize = MTDRAM_ERASE_SIZE; mtd->priv = mapped_address; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->erase = ram_erase; mtd->point = ram_point; mtd->unpoint = ram_unpoint; diff -Nru a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c --- a/drivers/mtd/devices/pmc551.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/devices/pmc551.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: pmc551.c,v 1.22 2003/01/24 13:34:30 dwmw2 Exp $ + * $Id: pmc551.c,v 1.25 2003/06/23 12:24:01 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -681,11 +681,6 @@ printk(KERN_INFO PMC551_VERSION); - if(!pci_present()) { - printk(KERN_NOTICE "pmc551: PCI not enabled.\n"); - return -ENODEV; - } - /* * PCU-bus chipset probe. */ @@ -787,10 +782,10 @@ mtd->write = pmc551_write; mtd->point = pmc551_point; mtd->unpoint = pmc551_unpoint; - mtd->module = THIS_MODULE; mtd->type = MTD_RAM; mtd->name = "PMC551 RAM board"; mtd->erasesize = 0x10000; + mtd->owner = THIS_MODULE; if (add_mtd_device(mtd)) { printk(KERN_NOTICE "pmc551: Failed to register new device\n"); diff -Nru a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c --- a/drivers/mtd/devices/slram.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/devices/slram.c Thu Dec 4 16:24:26 2003 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: slram.c,v 1.28 2003/01/24 13:35:34 dwmw2 Exp $ + $Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $ This driver provides a method to access memory not used by the kernel itself (i.e. if the kernel commandline mem=xxx is used). To actually @@ -199,7 +199,7 @@ (*curmtd)->mtdinfo->unpoint = slram_unpoint; (*curmtd)->mtdinfo->read = slram_read; (*curmtd)->mtdinfo->write = slram_write; - (*curmtd)->mtdinfo->module = THIS_MODULE; + (*curmtd)->mtdinfo->owner = THIS_MODULE; (*curmtd)->mtdinfo->type = MTD_RAM; (*curmtd)->mtdinfo->erasesize = 0x0; diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c --- a/drivers/mtd/ftl.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/ftl.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $ + * $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -55,8 +55,8 @@ contact M-Systems (http://www.m-sys.com) directly. ======================================================================*/ +#include #include -#include #include /*#define PSYCHO_DEBUG */ @@ -68,43 +68,13 @@ #include #include #include -#include +#include #include - -#if (LINUX_VERSION_CODE >= 0x20100) #include -#endif -#if (LINUX_VERSION_CODE >= 0x20303) #include -#endif +#include #include -/*====================================================================*/ -/* Stuff which really ought to be in compatmac.h */ - -#if (LINUX_VERSION_CODE < 0x20328) -#define register_disk(dev, drive, minors, ops, size) \ - do { (dev)->part[(drive)*(minors)].nr_sects = size; \ - if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \ - resetup_one_dev(dev, drive); } while (0) -#endif - -#if (LINUX_VERSION_CODE < 0x20320) -#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn -#define blk_init_queue(q, req) q = (req) -#define blk_cleanup_queue(q) q = NULL -#define request_arg_t void -#else -#define request_arg_t request_queue_t *q -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) -#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT -#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define BLK_INC_USE_COUNT do {} while(0) -#define BLK_DEC_USE_COUNT do {} while(0) -#endif /*====================================================================*/ @@ -119,19 +89,6 @@ #define FTL_MAJOR 44 #endif -/* Funky stuff for setting up a block device */ -#define MAJOR_NR FTL_MAJOR -#define DEVICE_NAME "ftl" -#define DEVICE_REQUEST do_ftl_request -#define DEVICE_ON(device) -#define DEVICE_OFF(device) - -#define DEVICE_NR(minor) ((minor)>>5) -#define REGION_NR(minor) (((minor)>>3)&3) -#define PART_NR(minor) ((minor)&7) -#define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part)) - -#include /*====================================================================*/ @@ -142,8 +99,7 @@ #define MAX_REGION 4 /* Maximum number of partitions in an FTL region */ -#define PART_BITS 3 -#define MAX_PART 8 +#define PART_BITS 4 /* Maximum number of outstanding erase requests per socket */ #define MAX_ERASE 8 @@ -154,7 +110,7 @@ /* Each memory region corresponds to a minor device */ typedef struct partition_t { - struct mtd_info *mtd; + struct mtd_blktrans_dev mbd; u_int32_t state; u_int32_t *VirtualBlockMap; u_int32_t *VirtualPageMap; @@ -179,21 +135,10 @@ region_info_t region; memory_handle_t handle; #endif - atomic_t open; } partition_t; -partition_t *myparts[MAX_MTD_DEVICES]; - -static void ftl_notify_add(struct mtd_info *mtd); -static void ftl_notify_remove(struct mtd_info *mtd); - void ftl_freepart(partition_t *part); -static struct mtd_notifier ftl_notifier = { - add: ftl_notify_add, - remove: ftl_notify_remove, -}; - /* Partition state flags */ #define FTL_FORMATTED 0x01 @@ -204,51 +149,11 @@ #define XFER_PREPARED 0x03 #define XFER_FAILED 0x04 -static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)]; -static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)]; -static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)]; - -static struct gendisk ftl_gendisk = { - major: FTL_MAJOR, - major_name: "ftl", - minor_shift: PART_BITS, - max_p: MAX_PART, -#if (LINUX_VERSION_CODE < 0x20328) - max_nr: MAX_DEV*MAX_PART, -#endif - part: ftl_hd, - sizes: ftl_sizes, -}; - /*====================================================================*/ -static int ftl_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg); -static int ftl_open(struct inode *inode, struct file *file); -static release_t ftl_close(struct inode *inode, struct file *file); -static int ftl_reread_partitions(int minor); static void ftl_erase_callback(struct erase_info *done); -#if LINUX_VERSION_CODE < 0x20326 -static struct file_operations ftl_blk_fops = { - open: ftl_open, - release: ftl_close, - ioctl: ftl_ioctl, - read: block_read, - write: block_write, - fsync: block_fsync -}; -#else -static struct block_device_operations ftl_blk_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) - owner: THIS_MODULE, -#endif - open: ftl_open, - release: ftl_close, - ioctl: ftl_ioctl, -}; -#endif /*====================================================================== @@ -264,13 +169,13 @@ loff_t offset, max_offset; int ret; part->header.FormattedSize = 0; - max_offset = (0x100000mtd->size)?0x100000:part->mtd->size; + max_offset = (0x100000mbd.mtd->size)?0x100000:part->mbd.mtd->size; /* Search first megabyte for a valid FTL header */ for (offset = 0; (offset + sizeof(header)) < max_offset; - offset += part->mtd->erasesize ? : 0x2000) { + offset += part->mbd.mtd->erasesize ? : 0x2000) { - ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, (unsigned char *)&header); if (ret) @@ -283,15 +188,15 @@ printk(KERN_NOTICE "ftl_cs: FTL header not found.\n"); return -ENOENT; } - if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 || + if (header.BlockSize != 9 || (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) || (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) { printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n"); return -1; } - if ((1 << header.EraseUnitSize) != part->mtd->erasesize) { + if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) { printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n", - 1 << header.EraseUnitSize,part->mtd->erasesize); + 1 << header.EraseUnitSize,part->mbd.mtd->erasesize); return -1; } part->header = header; @@ -326,7 +231,7 @@ for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) << part->header.EraseUnitSize); - ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, (unsigned char *)&header); if (ret) @@ -391,7 +296,7 @@ part->EUNInfo[i].Deleted = 0; offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); - ret = part->mtd->read(part->mtd, offset, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, part->BlocksPerUnit * sizeof(u_int32_t), &retval, (unsigned char *)part->bam_cache); @@ -456,7 +361,7 @@ erase->len = 1 << part->header.EraseUnitSize; erase->priv = (u_long)part; - ret = part->mtd->erase(part->mtd, erase); + ret = part->mbd.mtd->erase(part->mbd.mtd, erase); if (!ret) xfer->EraseCount++; @@ -523,7 +428,7 @@ header.LogicalEUN = cpu_to_le16(0xffff); header.EraseCount = cpu_to_le32(xfer->EraseCount); - ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen, (u_char *)&header); if (ret) { @@ -539,7 +444,7 @@ for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { - ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&ctl); if (ret) @@ -586,7 +491,7 @@ offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); - ret = part->mtd->read(part->mtd, offset, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); @@ -604,7 +509,7 @@ offset = xfer->Offset + 20; /* Bad! */ unit = cpu_to_le16(0x7fff); - ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), &retlen, (u_char *) &unit); if (ret) { @@ -624,7 +529,7 @@ break; case BLOCK_DATA: case BLOCK_REPLACEMENT: - ret = part->mtd->read(part->mtd, src, SECTOR_SIZE, + ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE, &retlen, (u_char *) buf); if (ret) { printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n"); @@ -632,7 +537,7 @@ } - ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE, + ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen, (u_char *) buf); if (ret) { printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n"); @@ -651,7 +556,7 @@ } /* Write the BAM to the transfer unit */ - ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), part->BlocksPerUnit * sizeof(int32_t), &retlen, (u_char *)part->bam_cache); if (ret) { @@ -661,7 +566,7 @@ /* All clear? Then update the LogicalEUN again */ - ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), &retlen, (u_char *)&srcunitswap); if (ret) { @@ -749,8 +654,8 @@ if (queued) { DEBUG(1, "ftl_cs: waiting for transfer " "unit to be prepared...\n"); - if (part->mtd->sync) - part->mtd->sync(part->mtd); + if (part->mbd.mtd->sync) + part->mbd.mtd->sync(part->mbd.mtd); } else { static int ne = 0; if (++ne < 5) @@ -848,7 +753,7 @@ /* Invalidate cache */ part->bam_index = 0xffff; - ret = part->mtd->read(part->mtd, + ret = part->mbd.mtd->read(part->mbd.mtd, part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); @@ -877,78 +782,6 @@ } /* find_free */ -/*====================================================================== - - This gets a memory handle for the region corresponding to the - minor device number. - -======================================================================*/ - -static int ftl_open(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - partition_t *partition; - - if (minor>>4 >= MAX_MTD_DEVICES) - return -ENODEV; - - partition = myparts[minor>>4]; - - if (!partition) - return -ENODEV; - - if (partition->state != FTL_FORMATTED) - return -ENXIO; - - if (ftl_gendisk.part[minor].nr_sects == 0) - return -ENXIO; - - BLK_INC_USE_COUNT; - - if (!get_mtd_device(partition->mtd, -1)) { - BLK_DEC_USE_COUNT; - return -ENXIO; - } - - if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { - put_mtd_device(partition->mtd); - BLK_DEC_USE_COUNT; - return -EROFS; - } - - DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor); - - atomic_inc(&partition->open); - - return 0; -} - -/*====================================================================*/ - -static release_t ftl_close(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - partition_t *part = myparts[minor >> 4]; - int i; - - DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); - - /* Wait for any pending erase operations to complete */ - if (part->mtd->sync) - part->mtd->sync(part->mtd); - - for (i = 0; i < part->header.NumTransferUnits; i++) { - if (part->XferInfo[i].state == XFER_ERASED) - prepare_xfer(part, i); - } - - atomic_dec(&part->open); - - put_mtd_device(part->mtd); - BLK_DEC_USE_COUNT; - release_return(0); -} /* ftl_close */ - /*====================================================================== @@ -983,7 +816,7 @@ else { offset = (part->EUNInfo[log_addr / bsize].Offset + (log_addr % bsize)); - ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, (u_char *) buffer); if (ret) { @@ -1022,7 +855,7 @@ le32_to_cpu(part->header.BAMOffset)); #ifdef PSYCHO_DEBUG - ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&old_addr); if (ret) { printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); @@ -1059,7 +892,7 @@ #endif part->bam_cache[blk] = le_virt_addr; } - ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&le_virt_addr); if (ret) { @@ -1119,7 +952,7 @@ part->EUNInfo[part->bam_index].Deleted++; offset = (part->EUNInfo[part->bam_index].Offset + blk * SECTOR_SIZE); - ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, + ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer); if (ret) { @@ -1151,164 +984,32 @@ return 0; } /* ftl_write */ -/*====================================================================== - - IOCTL calls for getting device parameters. - -======================================================================*/ - -static int ftl_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg) +static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { - struct hd_geometry *geo = (struct hd_geometry *)arg; - int ret = 0, minor = MINOR(inode->i_rdev); - partition_t *part= myparts[minor >> 4]; - u_long sect; - - if (!part) - return -ENODEV; /* How? */ - - switch (cmd) { - case HDIO_GETGEO: - ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo)); - if (ret) return ret; - /* Sort of arbitrary: round size down to 4K boundary */ - sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; - put_user(1, (char *)&geo->heads); - put_user(8, (char *)&geo->sectors); - put_user((sect>>3), (short *)&geo->cylinders); - put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start); - break; - case BLKGETSIZE: - ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg); - break; -#ifdef BLKGETSIZE64 - case BLKGETSIZE64: - ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg); - break; -#endif - case BLKRRPART: - ret = ftl_reread_partitions(minor); - break; -#if (LINUX_VERSION_CODE < 0x20303) - case BLKFLSBUF: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (!capable(CAP_SYS_ADMIN)) return -EACCES; -#endif - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - break; - RO_IOCTLS(inode->i_rdev, arg); -#else - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - ret = blk_ioctl(inode->i_rdev, cmd, arg); - break; -#endif - default: - ret = -EINVAL; - } - - return ret; -} /* ftl_ioctl */ + partition_t *part = (void *)dev; + u_long sect; -/*====================================================================== + /* Sort of arbitrary: round size down to 4KiB boundary */ + sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; - Handler for block device requests + geo->heads = 1; + geo->sectors = 8; + geo->cylinders = sect >> 3; -======================================================================*/ + return 0; +} -static int ftl_reread_partitions(int minor) +static int ftl_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - partition_t *part = myparts[minor >> 4]; - int i, whole; - - DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor); - if ((atomic_read(&part->open) > 1)) { - return -EBUSY; - } - whole = minor & ~(MAX_PART-1); - - i = MAX_PART - 1; - while (i-- > 0) { - if (ftl_hd[whole+i].nr_sects > 0) { - kdev_t rdev = MKDEV(FTL_MAJOR, whole+i); - - invalidate_device(rdev, 1); - } - ftl_hd[whole+i].start_sect = 0; - ftl_hd[whole+i].nr_sects = 0; - } - - scan_header(part); - - register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART, - &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); - -#ifdef PCMCIA_DEBUG - for (i = 0; i < MAX_PART; i++) { - if (ftl_hd[whole+i].nr_sects > 0) - printk(KERN_INFO " %d: start %ld size %ld\n", i, - ftl_hd[whole+i].start_sect, - ftl_hd[whole+i].nr_sects); - } -#endif - return 0; + return ftl_read((void *)dev, buf, block, 1); } -/*====================================================================== - - Handler for block device requests - -======================================================================*/ - -static void do_ftl_request(request_arg_t) +static int ftl_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - int ret, minor; - partition_t *part; - - do { - // sti(); - INIT_REQUEST; - - minor = MINOR(CURRENT->rq_dev); - - part = myparts[minor >> 4]; - if (part) { - ret = 0; - - switch (CURRENT->cmd) { - case READ: - ret = ftl_read(part, CURRENT->buffer, - CURRENT->sector+ftl_hd[minor].start_sect, - CURRENT->current_nr_sectors); - if (ret) printk("ftl_read returned %d\n", ret); - break; - - case WRITE: - ret = ftl_write(part, CURRENT->buffer, - CURRENT->sector+ftl_hd[minor].start_sect, - CURRENT->current_nr_sectors); - if (ret) printk("ftl_write returned %d\n", ret); - break; - - default: - panic("ftl_cs: unknown block command!\n"); - - } - } else { - ret = 1; - printk("NULL part in ftl_request\n"); - } - - if (!ret) { - CURRENT->sector += CURRENT->current_nr_sectors; - } - - end_request((ret == 0) ? 1 : 0); - } while (1); -} /* do_ftl_request */ + return ftl_write((void *)dev, buf, block, 1); +} /*====================================================================*/ @@ -1337,19 +1038,9 @@ } /* ftl_freepart */ -static void ftl_notify_add(struct mtd_info *mtd) +static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { partition_t *partition; - int device; - - for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++) - ; - - if (device == MAX_MTD_DEVICES) { - printk(KERN_NOTICE "Maximum number of FTL partitions reached\n" - "Not scanning <%s>\n", mtd->name); - return; - } partition = kmalloc(sizeof(partition_t), GFP_KERNEL); @@ -1361,92 +1052,55 @@ memset(partition, 0, sizeof(partition_t)); - partition->mtd = mtd; + partition->mbd.mtd = mtd; if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) { partition->state = FTL_FORMATTED; - atomic_set(&partition->open, 0); - myparts[device] = partition; - ftl_reread_partitions(device << 4); #ifdef PCMCIA_DEBUG - printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n", + printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", le32_to_cpu(partition->header.FormattedSize) >> 10); #endif + partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9; + partition->mbd.blksize = SECTOR_SIZE; + partition->mbd.tr = tr; + partition->mbd.devnum = -1; + if (add_mtd_blktrans_dev((void *)partition)) + kfree(partition); + } else kfree(partition); } -static void ftl_notify_remove(struct mtd_info *mtd) +static void ftl_remove_dev(struct mtd_blktrans_dev *dev) { - int i,j; - - /* Q: What happens if you try to remove a device which has - * a currently-open FTL partition on it? - * - * A: You don't. The ftl_open routine is responsible for - * increasing the use count of the driver module which - * it uses. - */ - - /* That's the theory, anyway :) */ - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (myparts[i] && myparts[i]->mtd == mtd) { - - if (myparts[i]->state == FTL_FORMATTED) - ftl_freepart(myparts[i]); - - myparts[i]->state = 0; - for (j=0; j<16; j++) { - ftl_gendisk.part[j].nr_sects=0; - ftl_gendisk.part[j].start_sect=0; - } - kfree(myparts[i]); - myparts[i] = NULL; - } + del_mtd_blktrans_dev(dev); + kfree(dev); } +struct mtd_blktrans_ops ftl_tr = { + .name = "ftl", + .major = FTL_MAJOR, + .part_bits = PART_BITS, + .readsect = ftl_readsect, + .writesect = ftl_writesect, + .getgeo = ftl_getgeo, + .add_mtd = ftl_add_mtd, + .remove_dev = ftl_remove_dev, + .owner = THIS_MODULE, +}; + int init_ftl(void) { - int i; + DEBUG(0, "$Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n"); - memset(myparts, 0, sizeof(myparts)); - - DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n"); - - if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { - printk(KERN_NOTICE "ftl_cs: unable to grab major " - "device number!\n"); - return -EAGAIN; - } - - for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++) - ftl_blocksizes[i] = 1024; - for (i = 0; i < MAX_DEV*MAX_PART; i++) { - ftl_hd[i].nr_sects = 0; - ftl_hd[i].start_sect = 0; - } - blksize_size[FTL_MAJOR] = ftl_blocksizes; - ftl_gendisk.major = FTL_MAJOR; - blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request); - add_gendisk(&ftl_gendisk); - - register_mtd_user(&ftl_notifier); - - return 0; + return register_mtd_blktrans(&ftl_tr); } static void __exit cleanup_ftl(void) { - unregister_mtd_user(&ftl_notifier); - - unregister_blkdev(FTL_MAJOR, "ftl"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR)); - blksize_size[FTL_MAJOR] = NULL; - - del_gendisk(&ftl_gendisk); + deregister_mtd_blktrans(&ftl_tr); } module_init(init_ftl); diff -Nru a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in --- a/drivers/mtd/maps/Config.in Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/Config.in Thu Dec 4 16:24:26 2003 @@ -1,17 +1,14 @@ # drivers/mtd/maps/Config.in -# $Id: Config.in,v 1.43 2003/01/24 14:26:38 dwmw2 Exp $ +# $Id: Config.in,v 1.62 2003/11/11 19:05:18 jsun Exp $ mainmenu_option next_comment comment 'Mapping drivers for chip access' -dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE -if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then - hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 - hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 - int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2 -fi +bool ' Support for non-linear mappings of flash chips' CONFIG_MTD_COMPLEX_MAPPINGS + +bool ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then dep_tristate ' Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_MTD_CFI @@ -21,40 +18,67 @@ dep_tristate ' CFI Flash device mapped on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS + dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000 fi - dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC - dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC - dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC + dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS + dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS dep_tristate ' Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE dep_tristate ' ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE - dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE + dep_tristate ' ROM connected to Intel Hub Controller 2/3/4/5' CONFIG_MTD_ICHXROM $CONFIG_MTD_JEDECPROBE $CONFIG_MTD_COMPLEX_MAPPINGS dep_tristate ' CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS dep_tristate ' BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE fi -if [ "$CONFIG_PPC" = "y" ]; then - dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL - dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI - dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI - dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI - dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI - dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI -fi - -if [ "$CONFIG_MIPS" = "y" ]; then - dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 - dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 - dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100 - if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \ - -o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then - bool ' Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT - bool ' Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER +if [ "$CONFIG_PPC32" = "y" ]; then + if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "y" ]; then + dep_tristate ' Flash device on SBC8240' CONFIG_MTD_SBC8240 $CONFIG_MTD_JEDECPROBE + fi + if [ "$CONFIG_8xx" = "y" ]; then + if [ "$CONFIG_TQM8xxL" = "y" ]; then + dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI + fi + if [ "$CONFIG_RPXLITE" = "y" -o "$CONFIG_RPXCLASSIC" = "y" ]; then + dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI + fi + if [ "$CONFIG_MBX" = "y" ]; then + dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI + fi + if [ "$CONFIG_DBOX2" = "y" ]; then + dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI + fi + dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI + fi + if [ "$CONFIG_4xx" = "y" ]; then + if [ "$CONFIG_40x" = "y" ]; then + if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then + dep_tristate ' CFI Flash device mapped on IBM Redwood' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI + fi + dep_tristate ' CFI Flash device mapped on IBM Beech' CONFIG_MTD_BEECH $CONFIG_MTD_CFI $CONFIG_BEECH + dep_tristate ' CFI Flash device mapped on IBM Arctic' CONFIG_MTD_ARCTIC $CONFIG_MTD_CFI $CONFIG_ARCTIC2 + fi + if [ "$CONFIG_440" = "y" ]; then + dep_tristate ' Flash devices mapped on IBM Ebony' CONFIG_MTD_EBONY $CONFIG_MTD_CFI $CONFIG_EBONY + fi + fi +fi + +if [ "$CONFIG_MIPS" = "y" -o "$CONFIG_MIPS64" = "y" ]; then + if [ "$CONFIG_MIPS_PB1000" = "y" -o "$CONFIG_MIPS_PB1100" = "y" -o "$CONFIG_MIPS_PB1500" = "y" ]; then + tristate ' Pb1x00 MTD support' CONFIG_MTD_PB1XXX + if [ "$CONFIG_MIPS_PB1500" = "y" -o "$CONFIG_MIPS_PB1100" = "m" ]; then + bool ' Pb1x00 boot flash device' CONFIG_MTD_PB1500_BOOT + bool ' Pb1x00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER + fi + fi + tristate ' Db1x00 MTD support' CONFIG_MTD_DB1X00 + if [ "$CONFIG_MTD_DB1X00" = "y" -o "$CONFIG_MTD_DB1X00" = "m" ]; then + bool ' Db1x00 boot flash device' CONFIG_MTD_DB1X00_BOOT + bool ' Db1x00 user flash device (2nd bank)' CONFIG_MTD_DB1X00_USER fi dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then @@ -63,7 +87,7 @@ int ' Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2 fi dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT - dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT + dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_LASAT fi if [ "$CONFIG_SUPERH" = "y" ]; then @@ -75,21 +99,25 @@ fi if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712 dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE + dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_COMPLEX_MAPPINGS dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 - dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_FORTUNET - dep_tristate ' CFI Flash device mapped on Epxa' CONFIG_MTD_EPXA $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT + dep_tristate ' CFI Flash device mapped on the XScale Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK + dep_tristate ' CFI Flash device mapped on XScale IXP425 systems' CONFIG_MTD_IXP425 $CONFIG_MTD_CFI $CONFIG_MTD_COMPLEX_MAPPINGS + dep_tristate ' CFI Flash device mapped on XScale IXP2000 systems' CONFIG_MTD_IXP2000 $CONFIG_MTD_CFI $CONFIG_MTD_COMPLEX_MAPPINGS + dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT + dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 - dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_ARCH_EDB7212 $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on Hynix evaluation boards' CONFIG_MTD_H720X $CONFIG_MTD_CFI dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA + dep_tristate ' NOR Flash device on TOTO board' CONFIG_MTD_NOR_TOTO $CONFIG_MTD $CONFIG_OMAP_TOTO fi if [ "$CONFIG_ALPHA" = "y" ]; then - dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE + dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE $CONFIG_MTD_COMPLEX_MAPPINGS fi if [ "$CONFIG_UCLINUX" = "y" ]; then @@ -97,7 +125,7 @@ fi # This needs CFI or JEDEC, depending on the cards found. -dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI -dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA +dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI $CONFIG_MTD_COMPLEX_MAPPINGS +dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA $CONFIG_MTD_COMPLEX_MAPPINGS endmenu diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/Makefile Thu Dec 4 16:24:25 2003 @@ -1,9 +1,17 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $ +# $Id: Makefile.common,v 1.7 2003/10/27 19:49:23 thayne Exp $ +ifeq ($(PATCHLEVEL),4) O_TARGET := mapslink.o +export-objs := map_funcs.o +endif + + +ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) +obj-$(CONFIG_MTD) += map_funcs.o +endif # Chip mappings obj-$(CONFIG_MTD_CDB89712) += cdb89712.o @@ -13,31 +21,22 @@ obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o -obj-$(CONFIG_MTD_EPXA) += epxa-flash.o +obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o -obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o +obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o -obj-$(CONFIG_MTD_NORA) += nora.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o -ifneq ($(CONFIG_MTD_PHYSMAP),n) - ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8) - obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o - else - obj-$(CONFIG_MTD_PHYSMAP) += physmap.o - endif -endif +obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PNC2000) += pnc2000.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o -ifeq ($(CONFIG_ASSABET_NEPONSET),y) - obj-$(CONFIG_MTD_SA1100) += neponset-flash.o -endif obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o obj-$(CONFIG_MTD_NETSC520) += netsc520.o @@ -48,9 +47,8 @@ obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o -obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o -obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o -obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o +obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o +obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o obj-$(CONFIG_MTD_LASAT) += lasat.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o obj-$(CONFIG_MTD_EDB7312) += edb7312.o @@ -60,5 +58,14 @@ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o +obj-$(CONFIG_MTD_EBONY) += ebony.o +obj-$(CONFIG_MTD_BEECH) += beech-mtd.o +obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o +obj-$(CONFIG_MTD_H720X) += h720x-flash.o +obj-$(CONFIG_MTD_SBC8240) += sbc8240.o +obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o +obj-$(CONFIG_MTD_MPC1211) += mpc1211.o +obj-$(CONFIG_MTD_IXP425) += ixp425.o +obj-$(CONFIG_MTD_IXP2000) += ixp2000.o -include $(TOPDIR)/Rules.make +-include $(TOPDIR)/Rules.make diff -Nru a/drivers/mtd/maps/adi_evb.c b/drivers/mtd/maps/adi_evb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/adi_evb.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,166 @@ +/* + * Mapping for the ADI 80200EVB evaluation board + * + * Author: Deepak Saxena + * Copyright: (C) 2001 MontaVista Software Inc. + * + * Based on iq80310 map written by Nicolas Pitre + * + * 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 + +#define WINDOW_ADDR 0 +#define BUSWIDTH 1 + +#define WINDOW_SIZE 4 * 1024 * 1024 + +static struct mtd_info *mymtd; + +static __u8 adi_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 adi_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 adi_read32(struct map_info *map, unsigned long ofs) +{ + return *(__u32 *)(map->map_priv_1 + ofs); +} + +static void adi_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void adi_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void adi_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void adi_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +static void adi_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +static struct map_info adi_map = { + name: "ADI Flash", + buswidth: BUSWIDTH, + read8: adi_read8, + read16: adi_read16, + read32: adi_read32, + copy_from: adi_copy_from, + write8: adi_write8, + write16: adi_write16, + write32: adi_write32, + copy_to: adi_copy_to +}; + +static struct mtd_partition adi_partitions[2] = { + { + name: "Firmware", + size: 0x00080000, + offset: 0, + mask_flags: MTD_WRITEABLE /* force read-only */ + }, { + name: "User Access", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; +static struct mtd_partition *parsed_parts; +static struct resource *mtd_resource; + +static int __init init_adi_evb(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + + mtd_resource = + request_mem_region(WINDOW_ADDR, WINDOW_SIZE, "ADI Flash"); + + if(!mtd_resource) + { + printk(KERN_ERR "ADI Flash: Could not request mem region\n"); + return -ENOMEM; + } + + adi_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); + if (!adi_map.map_priv_1) { + printk("ADI Flash: Failed to ioremap\n"); + return -EIO; + } + + adi_map.size = WINDOW_SIZE; + + mymtd = do_map_probe("cfi_probe", &adi_map); + if (!mymtd) { + iounmap((void *)adi_map.map_priv_1); + return -ENXIO; + } + mymtd->module = THIS_MODULE; + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + parts = adi_partitions; + nb_parts = NB_OF(adi_partitions); + } + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit cleanup_adi_evb(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (adi_map.map_priv_1) + iounmap((void *)adi_map.map_priv_1); + if(mtd_resource) + release_mem_region(WINDOW_ADDR, WINDOW_SIZE); +} + +module_init(init_adi_evb); +module_exit(cleanup_adi_evb); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena"); +MODULE_DESCRIPTION("MTD map driver for ADI 80200EVB evaluation board"); diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- a/drivers/mtd/maps/amd76xrom.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/amd76xrom.c Thu Dec 4 16:24:26 2003 @@ -2,12 +2,13 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.1 2002/10/18 22:45:48 eric Exp $ + * $Id: amd76xrom.c,v 1.9 2003/10/23 23:10:59 thayne Exp $ */ #include #include #include +#include #include #include #include @@ -16,77 +17,59 @@ #include +#define xstr(s) str(s) +#define str(s) #s +#define MOD_NAME xstr(KBUILD_BASENAME) + +#define MTD_DEV_NAME_LENGTH 16 + struct amd76xrom_map_info { struct map_info map; struct mtd_info *mtd; unsigned long window_addr; u32 window_start, window_size; struct pci_dev *pdev; + struct resource window_rsrc; + struct resource rom_rsrc; + char mtd_name[MTD_DEV_NAME_LENGTH]; }; -static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} -static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} +static struct amd76xrom_map_info amd76xrom_map = { + .map = { + .name = MOD_NAME, + .size = 0, + .buswidth = 1, + } + /* remaining fields of structure are initialized to 0 */ +}; -static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} -static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr) +static void amd76xrom_cleanup(struct amd76xrom_map_info *info) { - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} + u8 byte; -static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} + /* Disable writes through the rom window */ + pci_read_config_byte(info->pdev, 0x40, &byte); + pci_write_config_byte(info->pdev, 0x40, byte & ~1); -static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); + if (info->mtd) { + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = NULL; + info->map.virt = 0; + } + if (info->rom_rsrc.parent) + release_resource(&info->rom_rsrc); + if (info->window_rsrc.parent) + release_resource(&info->window_rsrc); + + if (info->window_addr) { + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + } } -static struct amd76xrom_map_info amd76xrom_map = { - map: { - name: "AMD76X rom", - size: 0, - buswidth: 1, - read8: amd76xrom_read8, - read16: amd76xrom_read16, - read32: amd76xrom_read32, - copy_from: amd76xrom_copy_from, - write8: amd76xrom_write8, - write16: amd76xrom_write16, - write32: amd76xrom_write32, - copy_to: amd76xrom_copy_to, - /* The standard rom socket is for single power supply chips - * that don't have an extra vpp. - */ - }, - mtd: 0, - window_addr: 0, -}; static int __devinit amd76xrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -97,6 +80,10 @@ u8 segen_bits; }; static struct rom_window rom_window[] = { + /* + * Need the 5MiB window for chips that have block lock/unlock + * registers located below 4MiB window. + */ { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, { 0xffc00000, 4*1024*1024, (1<<7), }, { 0xffff0000, 64*1024, 0 }, @@ -112,73 +99,128 @@ int i; u32 rom_size; + info->pdev = pdev; window = &rom_window[0]; -#if 0 - while(window->size) { - if (request_mem_region(window->start, window->size, "amd76xrom")) { - break; + + while (window->size) { + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to a fragment of the window being + * "reseved" by the BIOS. In the case that the + * request_mem_region() fails then once the rom size is + * discovered we will try to reserve the unreserved fragment. + */ + info->window_rsrc.name = MOD_NAME; + info->window_rsrc.start = window->start; + info->window_rsrc.end = window->start + window->size - 1; + info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &info->window_rsrc)) { + info->window_rsrc.parent = NULL; + printk(KERN_ERR MOD_NAME + " %s(): Unable to register resource" + " 0x%.08lx-0x%.08lx - kernel bug?\n", + __func__, + info->window_rsrc.start, info->window_rsrc.end); } - window++; - } - if (!window->size) { - printk(KERN_ERR "amd76xrom: cannot reserve rom window\n"); - goto err_out_none; - } -#endif - - /* Enable the selected rom window */ - pci_read_config_byte(pdev, 0x43, &byte); - pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); - - /* Enable writes through the rom window */ - pci_read_config_byte(pdev, 0x40, &byte); - pci_write_config_byte(pdev, 0x40, byte | 1); - - /* FIXME handle registers 0x80 - 0x8C the bios region locks */ - - printk(KERN_NOTICE "amd76xrom window : %x at %x\n", - window->size, window->start); - /* For write accesses caches are useless */ - info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); - - if (!info->window_addr) { - printk(KERN_ERR "Failed to ioremap\n"); - goto err_out_free_mmio_region; - } - info->mtd = 0; - for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { - char **chip_type; - if (rom_size > window->size) { + + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", + window->size, window->start); + /* For write accesses caches are useless */ + info->window_addr = + (unsigned long)ioremap_nocache(window->start, + window->size); + + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); continue; } - info->map.map_priv_1 = - info->window_addr + window->size - rom_size; - info->map.size = rom_size; - chip_type = rom_probe_types; - for(; !info->mtd && *chip_type; chip_type++) { - info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map); - } - if (info->mtd) { - break; + + info->mtd = NULL; + + for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { + char **chip_type; + if (rom_size > window->size) { + continue; + } + info->map.phys = window->start + window->size - rom_size; + info->map.virt = + info->window_addr + window->size - rom_size; + info->map.size = rom_size; + simple_map_init(&info->map); + chip_type = rom_probe_types; + for(; !info->mtd && *chip_type; chip_type++) { + info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map); + } + if (info->mtd) goto found_mtd; } + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte & ~1); + + window++; } - if (!info->mtd) { - goto err_out_iounmap; - } - printk(KERN_NOTICE "amd76xrom chip at offset: %x\n", + goto failed; + + found_mtd: + printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n", window->size - rom_size); - - info->mtd->module = THIS_MODULE; + + info->mtd->owner = THIS_MODULE; + + if (!info->window_rsrc.parent) { + /* failed to reserve entire window - try fragments */ + info->window_rsrc.name = MOD_NAME; + info->window_rsrc.start = window->start; + info->window_rsrc.end = window->start + window->size - rom_size - 1; + info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &info->window_rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve window resource fragment\n"); + goto failed; + } + } + add_mtd_device(info->mtd); info->window_start = window->start; info->window_size = window->size; + + if (info->window_rsrc.parent) { + /* + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. + */ + snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, + "mtd%d", info->mtd->index); + + info->rom_rsrc.name = info->mtd_name; + info->rom_rsrc.start = window->start + window->size - rom_size; + info->rom_rsrc.end = window->start + window->size - 1; + info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + info->rom_rsrc.parent = NULL; + } + } + return 0; -err_out_iounmap: - iounmap((void *)(info->window_addr)); -err_out_free_mmio_region: - release_mem_region(window->start, window->size); -err_out_none: + failed: + amd76xrom_cleanup(info); return -ENODEV; } @@ -186,21 +228,8 @@ static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) { struct amd76xrom_map_info *info = &amd76xrom_map; - u8 byte; - del_mtd_device(info->mtd); - map_destroy(info->mtd); - info->mtd = 0; - info->map.map_priv_1 = 0; - - iounmap((void *)(info->window_addr)); - info->window_addr = 0; - - /* Disable writes through the rom window */ - pci_read_config_byte(pdev, 0x40, &byte); - pci_write_config_byte(pdev, 0x40, byte & ~1); - - release_mem_region(info->window_start, info->window_size); + amd76xrom_cleanup(info); } static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = { @@ -208,6 +237,7 @@ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ { 0, } }; @@ -215,10 +245,10 @@ #if 0 static struct pci_driver amd76xrom_driver = { - name: "amd76xrom", - id_table: amd76xrom_pci_tbl, - probe: amd76xrom_init_one, - remove: amd76xrom_remove_one, + .name = MOD_NAME, + .id_table = amd76xrom_pci_tbl, + .probe = amd76xrom_init_one, + .remove = amd76xrom_remove_one, }; #endif diff -Nru a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/arctic-mtd.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,135 @@ +/* + * $Id: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $ + * + * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for + * IBM 405LP Arctic boards. + * + * 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 + * + * Copyright (C) 2002, International Business Machines Corporation + * All Rights Reserved. + * + * Bishop Brock + * IBM Research, Austin Center for Low-Power Computing + * bcbrock@us.ibm.com + * March 2002 + * + * modified for Arctic by, + * David Gibson + * IBM OzLabs, Canberra, Australia + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* + * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB) + * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB) + * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP) + * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB) + */ + +#define FFS1_SIZE 0x01000000 /* 16MiB */ +#define KERNEL_SIZE 0x00500000 /* 5.12MiB */ +#define FFS2_SIZE 0x00a60000 /* 10.624MiB */ +#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */ + + +#define NAME "Arctic Linux Flash" +#define PADDR SUBZERO_BOOTFLASH_PADDR +#define BUSWIDTH 2 +#define SIZE SUBZERO_BOOTFLASH_SIZE +#define PARTITIONS 4 + +/* Flash memories on these boards are memory resources, accessed big-endian. */ + +{ + /* do nothing for now */ +} + +static struct map_info arctic_mtd_map = { + .name = NAME, + .size = SIZE, + .buswidth = BUSWIDTH, + .phys = PADDR, +}; + +static struct mtd_info *arctic_mtd; + +static struct mtd_partition arctic_partitions[PARTITIONS] = { + { .name = "Filesystem", + .size = FFS1_SIZE, + .offset = 0,}, + { .name = "Kernel", + .size = KERNEL_SIZE, + .offset = FFS1_SIZE,}, + { .name = "Filesystem", + .size = FFS2_SIZE, + .offset = FFS1_SIZE + KERNEL_SIZE,}, + { .name = "Firmware", + .size = FIRMWARE_SIZE, + .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,}, +}; + +static int __init +init_arctic_mtd(void) +{ + printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); + + arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + + if (!arctic_mtd_map.virt) { + printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); + return -EIO; + } + simple_map_init(&arctic_mtd_map); + + printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); + arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map); + + if (!arctic_mtd) + return -ENXIO; + + arctic_mtd->owner = THIS_MODULE; + + return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS); +} + +static void __exit +cleanup_arctic_mtd(void) +{ + if (arctic_mtd) { + del_mtd_partitions(arctic_mtd); + map_destroy(arctic_mtd); + iounmap((void *) arctic_mtd_map.virt); + } +} + +module_init(init_arctic_mtd); +module_exit(cleanup_arctic_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Gibson "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards"); diff -Nru a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c --- a/drivers/mtd/maps/autcpu12-nvram.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/autcpu12-nvram.c Thu Dec 4 16:24:25 2003 @@ -2,7 +2,7 @@ * NV-RAM memory access on autcpu12 * (C) 2002 Thomas Gleixner (gleixner@autronix.de) * - * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ + * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 Exp $ * * 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 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -32,81 +33,28 @@ #include #include -__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); - from++; - to++; - len--; - } -} static struct mtd_info *sram_mtd; struct map_info autcpu12_sram_map = { - name: "SRAM", - size: 32768, - buswidth: 8, - read8: autcpu12_read8, - read16: autcpu12_read16, - read32: autcpu12_read32, - copy_from: autcpu12_copy_from, - write8: autcpu12_write8, - write16: autcpu12_write16, - write32: autcpu12_write32, - copy_to: autcpu12_copy_to + .name = "SRAM", + .size = 32768, + .buswidth = 4, + .phys = 0x12000000, }; static int __init init_autcpu12_sram (void) { int err, save0, save1; - autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); - if (!autcpu12_sram_map.map_priv_1) { + autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K); + if (!autcpu12_sram_map.virt) { printk("Failed to ioremap autcpu12 NV-RAM space\n"); err = -EIO; goto out; } - + simple_map_init(&autcpu_sram_map); + /* * Check for 32K/128K * read ofs 0 @@ -115,20 +63,20 @@ * Read and check result on ofs 0x0 * Restore contents */ - save0 = autcpu12_read32(&autcpu12_sram_map,0); - save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); - autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); + save0 = map_read32(&autcpu12_sram_map,0); + save1 = map_read32(&autcpu12_sram_map,0x10000); + map_write32(&autcpu12_sram_map,~save0,0x10000); /* if we find this pattern on 0x0, we have 32K size * restore contents and exit */ - if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { - autcpu12_write32(&autcpu12_sram_map,save0,0x0); + if ( map_read32(&autcpu12_sram_map,0) != save0) { + map_write32(&autcpu12_sram_map,save0,0x0); goto map; } /* We have a 128K found, restore 0x10000 and set size * to 128K */ - autcpu12_write32(&autcpu12_sram_map,save1,0x10000); + ma[_write32(&autcpu12_sram_map,save1,0x10000); autcpu12_sram_map.size = SZ_128K; map: @@ -139,7 +87,7 @@ goto out_ioremap; } - sram_mtd->module = THIS_MODULE; + sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; if (add_mtd_device(sram_mtd)) { @@ -148,7 +96,7 @@ goto out_probe; } - printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); + printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); return 0; @@ -157,7 +105,7 @@ sram_mtd = 0; out_ioremap: - iounmap((void *)autcpu12_sram_map.map_priv_1); + iounmap((void *)autcpu12_sram_map.virt); out: return err; } @@ -167,7 +115,7 @@ if (sram_mtd) { del_mtd_device(sram_mtd); map_destroy(sram_mtd); - iounmap((void *)autcpu12_sram_map.map_priv_1); + iounmap((void *)autcpu12_sram_map.virt); } } diff -Nru a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/beech-mtd.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,112 @@ +/* + * $Id: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ + * + * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for + * IBM 405LP Beech boards. + * + * 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 + * + * Copyright (C) 2002, International Business Machines Corporation + * All Rights Reserved. + * + * Bishop Brock + * IBM Research, Austin Center for Low-Power Computing + * bcbrock@us.ibm.com + * March 2002 + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define NAME "Beech Linux Flash" +#define PADDR BEECH_BIGFLASH_PADDR +#define SIZE BEECH_BIGFLASH_SIZE +#define BUSWIDTH 1 + +/* Flash memories on these boards are memory resources, accessed big-endian. */ + + +static struct map_info beech_mtd_map = { + .name = NAME, + .size = SIZE, + .buswidth = BUSWIDTH, + .phys = PADDR +}; + +static struct mtd_info *beech_mtd; + +static struct mtd_partition beech_partitions[2] = { + { + .name = "Linux Kernel", + .size = BEECH_KERNEL_SIZE, + .offset = BEECH_KERNEL_OFFSET + }, { + .name = "Free Area", + .size = BEECH_FREE_AREA_SIZE, + .offset = BEECH_FREE_AREA_OFFSET + } +}; + +static int __init +init_beech_mtd(void) +{ + printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); + + beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + + if (!beech_mtd_map.virt) { + printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); + return -EIO; + } + + simple_map_init(&beech_mtd_map); + + printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); + beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map); + + if (!beech_mtd) + return -ENXIO; + + beech_mtd->owner = THIS_MODULE; + + return add_mtd_partitions(beech_mtd, beech_partitions, 2); +} + +static void __exit +cleanup_beech_mtd(void) +{ + if (beech_mtd) { + del_mtd_partitions(beech_mtd); + map_destroy(beech_mtd); + iounmap((void *) beech_mtd_map.virt); + } +} + +module_init(init_beech_mtd); +module_exit(cleanup_beech_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bishop Brock "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards"); diff -Nru a/drivers/mtd/maps/brh.c b/drivers/mtd/maps/brh.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/brh.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,282 @@ +/* + * Mapping for the ADI BRH board + * + * Author: Deepak Saxena + * Copyright: (C) 2001 MontaVista Software Inc. + * + * Based on iq80310 map written by Nicolas Pitre + * + * 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 NUM_BANKS 3 +#define BUSWIDTH 1 + +#define WINDOW_ADDR 0 +#define WINDOW_SIZE 16 * 1024 * 1024 + +static __u8 brh_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 brh_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 brh_read32(struct map_info *map, unsigned long ofs) +{ + return *(__u32 *)(map->map_priv_1 + ofs); +} + +static void brh_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void brh_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void brh_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void brh_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +static void brh_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +static struct map_info brh_map[] = +{ + { + name: "ADI Flash Bank 0", + buswidth: BUSWIDTH, + read8: brh_read8, + read16: brh_read16, + read32: brh_read32, + copy_from: brh_copy_from, + write8: brh_write8, + write16: brh_write16, + write32: brh_write32, + copy_to: brh_copy_to, + size: WINDOW_SIZE + }, + { + name: "ADI Flash Bank 1", + buswidth: BUSWIDTH, + read8: brh_read8, + read16: brh_read16, + read32: brh_read32, + copy_from: brh_copy_from, + write8: brh_write8, + write16: brh_write16, + write32: brh_write32, + copy_to: brh_copy_to, + size: WINDOW_SIZE + }, + { + name: "ADI Flash Bank 2", + buswidth: BUSWIDTH, + read8: brh_read8, + read16: brh_read16, + read32: brh_read32, + copy_from: brh_copy_from, + write8: brh_write8, + write16: brh_write16, + write32: brh_write32, + copy_to: brh_copy_to, + size: WINDOW_SIZE + } +}; + +static struct mtd_partition brh_main_partitions[2] = { + { + name: "Firmware", + size: 0x000a0000, + offset: 0, + mask_flags: MTD_WRITEABLE /* force read-only */ + }, { + name: "User Access", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } +}; + +static struct mtd_partition brh_user_partitions[] = { + { + name: "User Access", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *brh_mtd[NUM_BANKS]; +static struct mtd_partition *parsed_parts; +static struct mtd_info *brh_concat; + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); + + +static void brh_destroy_mtd(void) +{ + int i = 0; + + if(brh_concat) mtd_concat_destroy(brh_concat); + + for(i = 0; i < NUM_BANKS; i++) + { + if(brh_map[i].map_priv_1) + iounmap((void*)brh_map[i].map_priv_1); + if(brh_map[i].map_priv_2) + release_resource((struct resource*)brh_map[i].map_priv_2); + if(brh_mtd[i]) + map_destroy(brh_mtd[i]); + } +} + +static int __init init_brh(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + char *part_type = "static"; + int i = 0; + int found_banks = 0; + int err_out = 0; + + for(i = 0; i < NUM_BANKS; i++) + { + unsigned long addr = WINDOW_ADDR + i * WINDOW_SIZE; + struct resource *res; + + res = request_mem_region(addr, WINDOW_SIZE, brh_map[i].name); + brh_map[found_banks].map_priv_2 = (unsigned long)res; + + if(!res) + { + printk(KERN_ERR "Could not request region for %s\n", + brh_map[i].name); + err_out = 1; + break; + } + + brh_map[i].map_priv_1 = + (unsigned long)__ioremap(addr, WINDOW_SIZE, 0); + + if(!brh_map[i].map_priv_1) + { + printk(KERN_ERR "Could not ioremap %s\n", + brh_map[i].name); + err_out = 1; + break; + } + + brh_map[i].map_priv_2 = (unsigned long)res; + + brh_mtd[found_banks] = do_map_probe("cfi_probe", &brh_map[i]); + if(brh_mtd[found_banks]) + { + brh_mtd[found_banks]->module = THIS_MODULE; + found_banks++; + } + else if(i != 0) + { + iounmap((void*)brh_map[i].map_priv_1); + release_resource((struct resource*)brh_map[i].map_priv_2); + } + else + { + printk(KERN_ERR + "BRH MTD: No boot flash found, aborting!\n"); + err_out = 1; + } + } + + + if(err_out) + { + brh_destroy_mtd(); + return -EIO; + } + + if(found_banks == 0) + return -NODEV; + + brh_concat = mtd_concat_create(brh_mtd, found_banks, "ADI Flash"); + if(!brh_concat) + { + brh_destroy_mtd(); + printk(KERN_ERR "Could not concatanate BRH Flash Banks\n"); + printk(KERN_ERR "Using static mappings\n"); + + add_mtd_partitions(brh_mtd[0], brh_main_partitions, 2); + + if(brh_mtd[1]) + add_mtd_partitions(brh_mtd[1], brh_user_partitions, 1); + + if(brh_mtd[2]) + add_mtd_partitions(brh_mtd[2], brh_user_partitions, 1); + + return 0; + } + + if (parsed_nr_parts == 0) { + int ret = parse_redboot_partitions(brh_concat, &parsed_parts); + + if (ret > 0) { + part_type = "RedBoot"; + parsed_nr_parts = ret; + } + } + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + parts = brh_main_partitions; + nb_parts = NB_OF(brh_main_partitions); + } + + add_mtd_partitions(brh_concat, parts, nb_parts); + + return 0; +} + +static void __exit cleanup_brh(void) +{ + brh_destroy_mtd(); +} + +module_init(init_brh); +module_exit(cleanup_brh); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena"); +MODULE_DESCRIPTION("MTD map driver for ADI 80200EVB evaluation board"); diff -Nru a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c --- a/drivers/mtd/maps/cdb89712.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/cdb89712.c Thu Dec 4 16:24:25 2003 @@ -1,13 +1,14 @@ /* * Flash on Cirrus CDB89712 * - * $Id: cdb89712.c,v 1.3 2001/10/02 15:14:43 rmk Exp $ + * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ */ #include #include #include #include +#include #include #include #include @@ -16,77 +17,21 @@ -__u8 cdb89712_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 cdb89712_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 cdb89712_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - // printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to); - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); - from++; - to++; - len--; - } -} - static struct mtd_info *flash_mtd; struct map_info cdb89712_flash_map = { - name: "flash", - size: FLASH_SIZE, - buswidth: FLASH_WIDTH, - read8: cdb89712_read8, - read16: cdb89712_read16, - read32: cdb89712_read32, - copy_from: cdb89712_copy_from, - write8: cdb89712_write8, - write16: cdb89712_write16, - write32: cdb89712_write32, - copy_to: cdb89712_copy_to + .name = "flash", + .size = FLASH_SIZE, + .buswidth = FLASH_WIDTH, + .phys = FLASH_START, }; struct resource cdb89712_flash_resource = { - name: "Flash", - start: FLASH_START, - end: FLASH_START + FLASH_SIZE - 1, - flags: IORESOURCE_IO | IORESOURCE_BUSY, + .name = "Flash", + .start = FLASH_START, + .end = FLASH_START + FLASH_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_flash (void) @@ -99,13 +44,13 @@ goto out; } - cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); - if (!cdb89712_flash_map.map_priv_1) { + cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!cdb89712_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_flash_map); flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map); if (!flash_mtd) { flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map); @@ -118,7 +63,7 @@ goto out_ioremap; } - flash_mtd->module = THIS_MODULE; + flash_mtd->owner = THIS_MODULE; if (add_mtd_device(flash_mtd)) { printk("FLASH device addition failed\n"); @@ -132,7 +77,7 @@ map_destroy(flash_mtd); flash_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_flash_map.map_priv_1); + iounmap((void *)cdb89712_flash_map.virt); out_resource: release_resource (&cdb89712_flash_resource); out: @@ -146,24 +91,17 @@ static struct mtd_info *sram_mtd; struct map_info cdb89712_sram_map = { - name: "SRAM", - size: SRAM_SIZE, - buswidth: SRAM_WIDTH, - read8: cdb89712_read8, - read16: cdb89712_read16, - read32: cdb89712_read32, - copy_from: cdb89712_copy_from, - write8: cdb89712_write8, - write16: cdb89712_write16, - write32: cdb89712_write32, - copy_to: cdb89712_copy_to + .name = "SRAM", + .size = SRAM_SIZE, + .buswidth = SRAM_WIDTH, + .phys = SRAM_START, }; struct resource cdb89712_sram_resource = { - name: "SRAM", - start: SRAM_START, - end: SRAM_START + SRAM_SIZE - 1, - flags: IORESOURCE_IO | IORESOURCE_BUSY, + .name = "SRAM", + .start = SRAM_START, + .end = SRAM_START + SRAM_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_sram (void) @@ -176,13 +114,13 @@ goto out; } - cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); - if (!cdb89712_sram_map.map_priv_1) { + cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); + if (!cdb89712_sram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_sram_map); sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map); if (!sram_mtd) { printk("SRAM probe failed\n"); @@ -190,7 +128,7 @@ goto out_ioremap; } - sram_mtd->module = THIS_MODULE; + sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; if (add_mtd_device(sram_mtd)) { @@ -205,7 +143,7 @@ map_destroy(sram_mtd); sram_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_sram_map.map_priv_1); + iounmap((void *)cdb89712_sram_map.virt); out_resource: release_resource (&cdb89712_sram_resource); out: @@ -221,20 +159,17 @@ static struct mtd_info *bootrom_mtd; struct map_info cdb89712_bootrom_map = { - name: "BootROM", - size: BOOTROM_SIZE, - buswidth: BOOTROM_WIDTH, - read8: cdb89712_read8, - read16: cdb89712_read16, - read32: cdb89712_read32, - copy_from: cdb89712_copy_from, + .name = "BootROM", + .size = BOOTROM_SIZE, + .buswidth = BOOTROM_WIDTH, + .phys = BOOTROM_START, }; struct resource cdb89712_bootrom_resource = { - name: "BootROM", - start: BOOTROM_START, - end: BOOTROM_START + BOOTROM_SIZE - 1, - flags: IORESOURCE_IO | IORESOURCE_BUSY, + .name = "BootROM", + .start = BOOTROM_START, + .end = BOOTROM_START + BOOTROM_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_bootrom (void) @@ -247,13 +182,13 @@ goto out; } - cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); - if (!cdb89712_bootrom_map.map_priv_1) { + cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); + if (!cdb89712_bootrom_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_bootrom_map); bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map); if (!bootrom_mtd) { printk("BootROM probe failed\n"); @@ -261,7 +196,7 @@ goto out_ioremap; } - bootrom_mtd->module = THIS_MODULE; + bootrom_mtd->owner = THIS_MODULE; bootrom_mtd->erasesize = 0x10000; if (add_mtd_device(bootrom_mtd)) { @@ -276,7 +211,7 @@ map_destroy(bootrom_mtd); bootrom_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_bootrom_map.map_priv_1); + iounmap((void *)cdb89712_bootrom_map.virt); out_resource: release_resource (&cdb89712_bootrom_resource); out: @@ -306,21 +241,21 @@ if (sram_mtd) { del_mtd_device(sram_mtd); map_destroy(sram_mtd); - iounmap((void *)cdb89712_sram_map.map_priv_1); + iounmap((void *)cdb89712_sram_map.virt); release_resource (&cdb89712_sram_resource); } if (flash_mtd) { del_mtd_device(flash_mtd); map_destroy(flash_mtd); - iounmap((void *)cdb89712_flash_map.map_priv_1); + iounmap((void *)cdb89712_flash_map.virt); release_resource (&cdb89712_flash_resource); } if (bootrom_mtd) { del_mtd_device(bootrom_mtd); map_destroy(bootrom_mtd); - iounmap((void *)cdb89712_bootrom_map.map_priv_1); + iounmap((void *)cdb89712_bootrom_map.virt); release_resource (&cdb89712_bootrom_resource); } } diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c --- a/drivers/mtd/maps/ceiva.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/ceiva.c Thu Dec 4 16:24:26 2003 @@ -11,7 +11,7 @@ * * (C) 2000 Nicolas Pitre * - * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ */ #include @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -31,62 +32,10 @@ #include /* - * This isnt complete yet, so... + * This isn't complete yet, so... */ #define CONFIG_MTD_CEIVA_STATICMAP -static __u8 clps_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 clps_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 clps_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void clps_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void clps_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void clps_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - -static struct map_info clps_map __initdata = { - name: "clps flash", - read8: clps_read8, - read16: clps_read16, - read32: clps_read32, - copy_from: clps_copy_from, - write8: clps_write8, - write16: clps_write16, - write32: clps_write32, - copy_to: clps_copy_to, -}; - #ifdef CONFIG_MTD_CEIVA_STATICMAP /* * See include/linux/mtd/partitions.h for definition of the mtd_partition @@ -176,7 +125,7 @@ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); if (!maps) return -ENOMEM; - + memset(maps, 0, sizeof(struct map_info) * nr); /* * Claim and then map the memory regions. */ @@ -191,7 +140,9 @@ } clps[i].map = maps + i; - memcpy(clps[i].map, &clps_map, sizeof(struct map_info)); + + clps[i].map->name = "clps flash"; + clps[i].map->phys = clps[i].base; clps[i].vbase = ioremap(clps[i].base, clps[i].size); if (!clps[i].vbase) { @@ -199,16 +150,18 @@ break; } - clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase; + clps[i].map->virt = (unsigned long)clps[i].vbase; clps[i].map->buswidth = clps[i].width; clps[i].map->size = clps[i].size; + simple_map_init(&clps[i].map); + clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); if (clps[i].mtd == NULL) { ret = -ENXIO; break; } - clps[i].mtd->module = THIS_MODULE; + clps[i].mtd->owner = THIS_MODULE; subdev[i] = clps[i].mtd; printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " @@ -318,10 +271,8 @@ return nr; } -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); - static struct mtd_partition *parsed_parts; +static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; static void __init clps_locate_partitions(struct mtd_info *mtd) { @@ -331,20 +282,11 @@ /* * Partition selection stuff. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps"); + nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); if (nr_parts > 0) { part_type = "command line"; break; } -#endif -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(mtd, &parsed_parts); - if (nr_parts > 0) { - part_type = "RedBoot"; - break; - } -#endif #ifdef CONFIG_MTD_CEIVA_STATICMAP nr_parts = clps_static_partitions(&parsed_parts); if (nr_parts > 0) { diff -Nru a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c --- a/drivers/mtd/maps/cfi_flagadm.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/cfi_flagadm.c Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson * - * $Id: cfi_flagadm.c,v 1.7 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 Exp $ * * 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 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -55,83 +56,33 @@ #define FLASH_PARTITION3_ADDR 0x00240000 #define FLASH_PARTITION3_SIZE 0x001C0000 -__u8 flagadm_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 flagadm_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 flagadm_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} struct map_info flagadm_map = { - name: "FlagaDM flash device", - size: FLASH_SIZE, - buswidth: 2, - read8: flagadm_read8, - read16: flagadm_read16, - read32: flagadm_read32, - copy_from: flagadm_copy_from, - write8: flagadm_write8, - write16: flagadm_write16, - write32: flagadm_write32, - copy_to: flagadm_copy_to + .name = "FlagaDM flash device", + .size = FLASH_SIZE, + .buswidth = 2, }; struct mtd_partition flagadm_parts[] = { { - name : "Bootloader", - offset : FLASH_PARTITION0_ADDR, - size : FLASH_PARTITION0_SIZE + .name = "Bootloader", + .offset = FLASH_PARTITION0_ADDR, + .size = FLASH_PARTITION0_SIZE }, { - name : "Kernel image", - offset : FLASH_PARTITION1_ADDR, - size : FLASH_PARTITION1_SIZE + .name = "Kernel image", + .offset = FLASH_PARTITION1_ADDR, + .size = FLASH_PARTITION1_SIZE }, { - name : "Initial ramdisk image", - offset : FLASH_PARTITION2_ADDR, - size : FLASH_PARTITION2_SIZE + .name = "Initial ramdisk image", + .offset = FLASH_PARTITION2_ADDR, + .size = FLASH_PARTITION2_SIZE }, { - name : "Persistant storage", - offset : FLASH_PARTITION3_ADDR, - size : FLASH_PARTITION3_SIZE + .name = "Persistant storage", + .offset = FLASH_PARTITION3_ADDR, + .size = FLASH_PARTITION3_SIZE } }; @@ -144,22 +95,26 @@ printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", FLASH_SIZE, FLASH_PHYS_ADDR); - flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR, + flagadm_map.phys = FLASH_PHYS_ADDR; + flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); - if (!flagadm_map.map_priv_1) { + if (!flagadm_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + + simple_map_init(&flagadm_map); + mymtd = do_map_probe("cfi_probe", &flagadm_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT); printk(KERN_NOTICE "FlagaDM flash device initialized\n"); return 0; } - iounmap((void *)flagadm_map.map_priv_1); + iounmap((void *)flagadm_map.virt); return -ENXIO; } @@ -169,9 +124,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (flagadm_map.map_priv_1) { - iounmap((void *)flagadm_map.map_priv_1); - flagadm_map.map_priv_1 = 0; + if (flagadm_map.virt) { + iounmap((void *)flagadm_map.virt); + flagadm_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c --- a/drivers/mtd/maps/cstm_mips_ixx.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/cstm_mips_ixx.c Thu Dec 4 16:24:26 2003 @@ -1,5 +1,5 @@ /* - * $Id: cstm_mips_ixx.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $ * * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. * Config with both CFI and JEDEC device support. @@ -33,55 +33,13 @@ #include #include #include +#include #include #include #include #include #include - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) #include -#endif - -__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) #define CC_GCR 0xB4013818 @@ -97,56 +55,47 @@ #define CC_GPAICR 0xB4013804 #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ +#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) { - if (vpp) { -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - __u16 data; - __u8 data1; - static u8 first = 1; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff0f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08; - if (first) { - first = 0; - /* need to have this delay for first - enabling vpp after powerup */ - udelay(40); + static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED; + static int vpp_count = 0; + unsigned long flags; + + spin_lock_irqsave(&vpp_lock, flags); + + if (vpp) { + if (!vpp_count++) { + __u16 data; + __u8 data1; + static u8 first = 1; + + // Set GPIO port B pin3 to high + data = *(__u16 *)(CC_GPBCR); + data = (data & 0xff0f) | 0x0040; + *(__u16 *)CC_GPBCR = data; + *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08; + if (first) { + first = 0; + /* need to have this delay for first + enabling vpp after powerup */ + udelay(40); + } + } + } else { + if (!--vpp_count) { + __u16 data; + + // Set GPIO port B pin3 to high + data = *(__u16 *)(CC_GPBCR); + data = (data & 0xff3f) | 0x0040; + *(__u16 *)CC_GPBCR = data; + *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; + } } -#endif /* CONFIG_MIPS_ITE8172 */ - } - else { -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - __u16 data; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff3f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; -#endif /* CONFIG_MIPS_ITE8172 */ - } + spin_unlock_irqrestore(&vpp_lock, flags); } - -const struct map_info basic_cstm_mips_ixx_map = { - NULL, - 0, - 0, - cstm_mips_ixx_read8, - cstm_mips_ixx_read16, - cstm_mips_ixx_read32, - cstm_mips_ixx_copy_from, - cstm_mips_ixx_write8, - cstm_mips_ixx_write16, - cstm_mips_ixx_write32, - cstm_mips_ixx_copy_to, - cstm_mips_ixx_set_vpp, - 0, - 0 -}; +#endif /* board and partition description */ @@ -175,9 +124,9 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { { // 28F128J3A in 2x16 configuration { - name: "main partition ", - size: 0x02000000, // 128 x 2 x 128k byte sectors - offset: 0, + .name = "main partition ", + .size = 0x02000000, // 128 x 2 x 128k byte sectors + .offset = 0, }, }, }; @@ -197,9 +146,9 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { { { - name: "main partition", - size: CONFIG_MTD_CSTM_MIPS_IXX_LEN, - offset: 0, + .name = "main partition", + .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, + .offset = 0, }, }, }; @@ -216,17 +165,24 @@ /* Initialize mapping */ for (i=0;imodule = THIS_MODULE; + mymtd->owner = THIS_MODULE; cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd; add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions); @@ -266,9 +222,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (cstm_mips_ixx_map[i].map_priv_1) { - iounmap((void *)cstm_mips_ixx_map[i].map_priv_1); - cstm_mips_ixx_map[i].map_priv_1 = 0; + if (cstm_mips_ixx_map[i].virt) { + iounmap((void *)cstm_mips_ixx_map[i].virt); + cstm_mips_ixx_map[i].virt = 0; } } } diff -Nru a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/db1x00-flash.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,217 @@ +/* + * Flash memory access on Alchemy Db1xxx boards + * + * (C) 2003 Pete Popov + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static unsigned long window_addr; +static unsigned long window_size; +static unsigned long flash_size; + +static BCSR * const bcsr = (BCSR *)0xAE000000; +static unsigned char flash_buswidth = 4; + +/* + * The Db1x boards support different flash densities. We setup + * the mtd_partition structures below for default of 64Mbit + * flash densities, and override the partitions sizes, if + * necessary, after we check the board status register. + */ + +#ifdef DB1X00_BOTH_BANKS +/* both banks will be used. Combine the first bank and the first + * part of the second bank together into a single jffs/jffs2 + * partition. + */ +static struct mtd_partition db1x00_partitions[] = { + { + .name = "User FS", + .size = 0x1c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = (0x300000-0x40000), /* last 256KB is env */ + .offset = MTDPART_OFS_APPEND, + } +}; +#elif defined(DB1X00_BOOT_ONLY) +static struct mtd_partition db1x00_partitions[] = { + { + .name = "User FS", + .size = 0x00c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = (0x300000-0x40000), /* last 256KB is env */ + .offset = MTDPART_OFS_APPEND, + } +}; +#elif defined(DB1X00_USER_ONLY) +static struct mtd_partition db1x00_partitions[] = { + { + .name = "User FS", + .size = 0x0e00000, + .offset = 0x0000000 + },{ + .name = "raw kernel", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; +#else +#error MTD_DB1X00 define combo error /* should never happen */ +#endif +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +#define NAME "Db1x00 Linux Flash" + +static struct map_info db1xxx_mtd_map = { + .name = NAME, +}; + +static struct mtd_partition *parsed_parts; +static struct mtd_info *db1xxx_mtd; + +/* + * Probe the flash density and setup window address and size + * based on user CONFIG options. There are times when we don't + * want the MTD driver to be probing the boot or user flash, + * so having the option to enable only one bank is important. + */ +int setup_flash_params(void) +{ + switch ((bcsr->status >> 14) & 0x3) { + case 0: /* 64Mbit devices */ + flash_size = 0x800000; /* 8MB per part */ +#if defined(DB1X00_BOTH_BANKS) + window_addr = 0x1E000000; + window_size = 0x2000000; +#elif defined(DB1X00_BOOT_ONLY) + window_addr = 0x1F000000; + window_size = 0x1000000; +#else /* USER ONLY */ + window_addr = 0x1E000000; + window_size = 0x1000000; +#endif + break; + case 1: + /* 128 Mbit devices */ + flash_size = 0x1000000; /* 16MB per part */ +#if defined(DB1X00_BOTH_BANKS) + window_addr = 0x1C000000; + window_size = 0x4000000; + /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */ + db1x00_partitions[0].size = 0x3C00000; +#elif defined(DB1X00_BOOT_ONLY) + window_addr = 0x1E000000; + window_size = 0x2000000; + /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */ + db1x00_partitions[0].size = 0x1C00000; +#else /* USER ONLY */ + window_addr = 0x1C000000; + window_size = 0x2000000; + /* USERFS from 0x1C00 0000 to 0x1DE00000 */ + db1x00_partitions[0].size = 0x1DE0000; +#endif + break; + case 2: + /* 256 Mbit devices */ + flash_size = 0x4000000; /* 64MB per part */ +#if defined(DB1X00_BOTH_BANKS) + return 1; +#elif defined(DB1X00_BOOT_ONLY) + /* Boot ROM flash bank only; no user bank */ + window_addr = 0x1C000000; + window_size = 0x4000000; + /* USERFS from 0x1C00 0000 to 0x1FC00000 */ + db1x00_partitions[0].size = 0x3C00000; +#else /* USER ONLY */ + return 1; +#endif + break; + default: + return 1; + } + db1xxx_mtd_map.size = window_size; + db1xxx_mtd_map.buswidth = flash_buswidth; + db1xxx_mtd_map.phys = window_addr; + db1xxx_mtd_map.buswidth = flash_buswidth; + return 0; +} + +int __init db1x00_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + + if (setup_flash_params()) + return -ENXIO; + + /* + * Static partition definition selection + */ + parts = db1x00_partitions; + nb_parts = NB_OF(db1x00_partitions); + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", + db1xxx_mtd_map.buswidth*8); + db1xxx_mtd_map.virt = (unsigned long)ioremap(window_addr, window_size); + db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map); + if (!db1xxx_mtd) return -ENXIO; + db1xxx_mtd->owner = THIS_MODULE; + + add_mtd_partitions(db1xxx_mtd, parts, nb_parts); + return 0; +} + +static void __exit db1x00_mtd_cleanup(void) +{ + if (db1xxx_mtd) { + del_mtd_partitions(db1xxx_mtd); + map_destroy(db1xxx_mtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(db1x00_mtd_init); +module_exit(db1x00_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Db1x00 mtd map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c --- a/drivers/mtd/maps/dbox2-flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/dbox2-flash.c Thu Dec 4 16:24:25 2003 @@ -1,12 +1,13 @@ /* - * $Id: dbox2-flash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $ * - * Nokia / Sagem D-Box 2 flash driver + * D-Box 2 flash driver */ #include #include #include +#include #include #include #include @@ -16,22 +17,44 @@ /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[]= {{name: "BR bootloader", // raw - size: 128 * 1024, - offset: 0, - mask_flags: MTD_WRITEABLE}, - {name: "PPC bootloader", // flfs - size: 128 * 1024, - offset: MTDPART_OFS_APPEND, - mask_flags: 0}, - {name: "Kernel", // idxfs - size: 768 * 1024, - offset: MTDPART_OFS_APPEND, - mask_flags: 0}, - {name: "System", // jffs - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - mask_flags: 0}}; +static struct mtd_partition partition_info[]= { + { + .name = "BR bootloader", + .size = 128 * 1024, + .offset = 0, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "flfs (ppcboot)", + .size = 128 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "root (cramfs)", + .size = 7040 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "var (jffs2)", + .size = 896 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "flash without bootloader", + .size = MTDPART_SIZ_FULL, + .offset = 128 * 1024, + .mask_flags = 0 + }, + { + .name = "complete flash", + .size = MTDPART_SIZ_FULL, + .offset = 0, + .mask_flags = MTD_WRITEABLE + } +}; #define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0])) @@ -40,72 +63,24 @@ static struct mtd_info *mymtd; -__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} struct map_info dbox2_flash_map = { - name: "D-Box 2 flash memory", - size: WINDOW_SIZE, - buswidth: 4, - read8: dbox2_flash_read8, - read16: dbox2_flash_read16, - read32: dbox2_flash_read32, - copy_from: dbox2_flash_copy_from, - write8: dbox2_flash_write8, - write16: dbox2_flash_write16, - write32: dbox2_flash_write32, - copy_to: dbox2_flash_copy_to + .name = "D-Box 2 flash memory", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = WINDOW_ADDR, }; int __init init_dbox2_flash(void) { printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); - dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!dbox2_flash_map.map_priv_1) { + if (!dbox2_flash_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&dbox2_flash_map); // Probe for dual Intel 28F320 or dual AMD mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); @@ -117,7 +92,7 @@ } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); @@ -125,7 +100,7 @@ return 0; } - iounmap((void *)dbox2_flash_map.map_priv_1); + iounmap((void *)dbox2_flash_map.virt); return -ENXIO; } @@ -135,9 +110,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (dbox2_flash_map.map_priv_1) { - iounmap((void *)dbox2_flash_map.map_priv_1); - dbox2_flash_map.map_priv_1 = 0; + if (dbox2_flash_map.virt) { + iounmap((void *)dbox2_flash_map.virt); + dbox2_flash_map.virt = 0; } } @@ -146,5 +121,5 @@ MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kári Davíðsson "); -MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board"); +MODULE_AUTHOR("Kári Davíðsson , Bastian Blank , Alexander Wild "); +MODULE_DESCRIPTION("MTD map driver for D-Box 2 board"); diff -Nru a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c --- a/drivers/mtd/maps/dc21285.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/dc21285.c Thu Dec 4 16:24:25 2003 @@ -5,12 +5,13 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $ + * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $ */ #include #include #include #include +#include #include #include @@ -92,26 +93,42 @@ } struct map_info dc21285_map = { - name: "DC21285 flash", - size: 16*1024*1024, - read8: dc21285_read8, - read16: dc21285_read16, - read32: dc21285_read32, - copy_from: dc21285_copy_from, - write8: dc21285_write8, - write16: dc21285_write16, - write32: dc21285_write32, - copy_to: dc21285_copy_to + .name = "DC21285 flash", + .phys = NO_XIP, + .size = 16*1024*1024, + .read8 = dc21285_read8, + .read16 = dc21285_read16, + .read32 = dc21285_read32, + .copy_from = dc21285_copy_from, + .write8 = dc21285_write8, + .write16 = dc21285_write16, + .write32 = dc21285_write32, + .copy_to = dc21285_copy_to }; /* Partition stuff */ static struct mtd_partition *dc21285_parts; - -extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); - +#ifdef CONFIG_MTD_PARTITIONS +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; +#endif + int __init init_dc21285(void) { + + /* + * Flash timing is determined with bits 19-16 of the + * CSR_SA110_CNTL. The value is the number of wait cycles, or + * 0 for 16 cycles (the default). Cycles are 20 ns. + * Here we use 7 for 140 ns flash chips. + */ + /* access time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); + /* burst time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); + /* tristate time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); + /* Determine buswidth */ switch (*CSR_SA110_CNTL & (3<<14)) { case SA110_CNTL_ROMWIDTH_8: @@ -141,33 +158,18 @@ if (mymtd) { int nrparts = 0; - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* partition fixup */ -#ifdef CONFIG_MTD_REDBOOT_PARTS - nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); -#endif +#ifdef CONFIG_MTD_PARTITIONS + nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0); if (nrparts > 0) { add_mtd_partitions(mymtd, dc21285_parts, nrparts); - } else if (nrparts == 0) { - printk(KERN_NOTICE "RedBoot partition table failed\n"); - add_mtd_device(mymtd); + return 0; } - - /* - * Flash timing is determined with bits 19-16 of the - * CSR_SA110_CNTL. The value is the number of wait cycles, or - * 0 for 16 cycles (the default). Cycles are 20 ns. - * Here we use 7 for 140 ns flash chips. - */ - /* access time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); - /* burst time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); - /* tristate time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); - +#endif + add_mtd_device(mymtd); return 0; } @@ -177,17 +179,16 @@ static void __exit cleanup_dc21285(void) { - if (mymtd) { - del_mtd_device(mymtd); - map_destroy(mymtd); - mymtd = NULL; - } - if (dc21285_map.map_priv_1) { - iounmap((void *)dc21285_map.map_priv_1); - dc21285_map.map_priv_1 = 0; - } - if(dc21285_parts) +#ifdef CONFIG_MTD_PARTITIONS + if (dc21285_parts) { + del_mtd_partitions(mymtd); kfree(dc21285_parts); + } else +#endif + del_mtd_device(mymtd); + + map_destroy(mymtd); + iounmap((void *)dc21285_map.map_priv_1); } module_init(init_dc21285); diff -Nru a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c --- a/drivers/mtd/maps/dilnetpc.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/dilnetpc.c Thu Dec 4 16:24:25 2003 @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $ + * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $ * * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems * featuring the AMD Elan SC410 processor. There are two variants of this @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #include /* -** The DIL/NetPC keeps it's BIOS in two distinct flash blocks. +** The DIL/NetPC keeps its BIOS in two distinct flash blocks. ** Destroying any of these blocks transforms the DNPC into ** a paperweight (albeit not a very useful one, considering ** it only weighs a few grams). @@ -189,45 +190,6 @@ } -static __u8 dnpc_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 dnpc_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 dnpc_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} /* ************************************************************ @@ -285,22 +247,14 @@ #define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ #define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ -#define WINDOW_ADDR FLASH_BASE +#define WINDOW_ADDR FLASH_BASE static struct map_info dnpc_map = { - name: "ADNP Flash Bank", - size: ADNP_WINDOW_SIZE, - buswidth: 1, - read8: dnpc_read8, - read16: dnpc_read16, - read32: dnpc_read32, - copy_from: dnpc_copy_from, - write8: dnpc_write8, - write16: dnpc_write16, - write32: dnpc_write32, - copy_to: dnpc_copy_to, - set_vpp: adnp_set_vpp, - map_priv_2: WINDOW_ADDR + .name = "ADNP Flash Bank", + .size = ADNP_WINDOW_SIZE, + .buswidth = 1, + .set_vpp = adnp_set_vpp, + .phys = WINDOW_ADDR }; /* @@ -316,29 +270,29 @@ static struct mtd_partition partition_info[]= { { - name: "ADNP boot", - offset: 0, - size: 0xf0000, + .name = "ADNP boot", + .offset = 0, + .size = 0xf0000, }, { - name: "ADNP system BIOS", - offset: MTDPART_OFS_NXTBLK, - size: 0x10000, + .name = "ADNP system BIOS", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x10000, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED - mask_flags: MTD_WRITEABLE, + .mask_flags = MTD_WRITEABLE, #endif }, { - name: "ADNP file system", - offset: MTDPART_OFS_NXTBLK, - size: 0x2f0000, + .name = "ADNP file system", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x2f0000, }, { - name: "ADNP system BIOS entry", - offset: MTDPART_OFS_NXTBLK, - size: MTDPART_SIZ_FULL, + .name = "ADNP system BIOS entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED - mask_flags: MTD_WRITEABLE, + .mask_flags = MTD_WRITEABLE, #endif }, }; @@ -369,21 +323,21 @@ static struct mtd_partition higlvl_partition_info[]= { { - name: "ADNP boot block", - offset: 0, - size: CONFIG_MTD_DILNETPC_BOOTSIZE, + .name = "ADNP boot block", + .offset = 0, + .size = CONFIG_MTD_DILNETPC_BOOTSIZE, }, { - name: "ADNP file system space", - offset: MTDPART_OFS_NXTBLK, - size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + .name = "ADNP file system space", + .offset = MTDPART_OFS_NXTBLK, + .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, }, { - name: "ADNP system BIOS + BIOS Entry", - offset: MTDPART_OFS_NXTBLK, - size: MTDPART_SIZ_FULL, + .name = "ADNP system BIOS + BIOS Entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED - mask_flags: MTD_WRITEABLE, + .mask_flags = MTD_WRITEABLE, #endif }, }; @@ -447,18 +401,19 @@ } printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", - is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2); + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); - dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size); + dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size); - dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size); + dnpc_map_flash(dnpc_map.phys, dnpc_map.size); - if (!dnpc_map.map_priv_1) { + if (!dnpc_map.virt) { printk("Failed to ioremap_nocache\n"); return -EIO; } + simple_map_init(&dnpc_map); - printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1); + printk("FLASH virtual address: 0x%lx\n", dnpc_map.virt); mymtd = do_map_probe("jedec_probe", &dnpc_map); @@ -475,11 +430,11 @@ mymtd->erasesize = 0x10000; if (!mymtd) { - iounmap((void *)dnpc_map.map_priv_1); + iounmap((void *)dnpc_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() @@ -525,10 +480,10 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (dnpc_map.map_priv_1) { - iounmap((void *)dnpc_map.map_priv_1); + if (dnpc_map.virt) { + iounmap((void *)dnpc_map.virt); dnpc_unmap_flash(); - dnpc_map.map_priv_1 = 0; + dnpc_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ebony.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,164 @@ +/* + * $Id: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $ + * + * Mapping for Ebony user flash + * + * Matt Porter + * + * Copyright 2002 MontaVista Software Inc. + * + * 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 +#include +#include +#include +#include + +static struct mtd_info *flash; + +static struct map_info ebony_small_map = { + .name = "Ebony small flash", + .size = EBONY_SMALL_FLASH_SIZE, + .buswidth = 1, +}; + +static struct map_info ebony_large_map = { + .name = "Ebony large flash", + .size = EBONY_LARGE_FLASH_SIZE, + .buswidth = 1, +}; + +static struct mtd_partition ebony_small_partitions[] = { + { + .name = "OpenBIOS", + .offset = 0x0, + .size = 0x80000, + } +}; + +static struct mtd_partition ebony_large_partitions[] = { + { + .name = "fs", + .offset = 0, + .size = 0x380000, + }, + { + .name = "firmware", + .offset = 0x380000, + .size = 0x80000, + } +}; + +int __init init_ebony(void) +{ + u8 fpga0_reg; + unsigned long fpga0_adr; + unsigned long long small_flash_base, large_flash_base; + + fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16); + if (!fpga0_adr) + return -ENOMEM; + + fpga0_reg = readb(fpga0_adr); + iounmap64(fpga0_adr); + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH2; + else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH1; + else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_LOW2; + else + small_flash_base = EBONY_SMALL_FLASH_LOW1; + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_ONBRD_FLASH_EN(fpga0_reg)) + large_flash_base = EBONY_LARGE_FLASH_LOW; + else + large_flash_base = EBONY_LARGE_FLASH_HIGH; + + ebony_small_map.phys = small_flash_base; + ebony_small_map.virt = + (unsigned long)ioremap64(small_flash_base, + ebony_small_map.size); + + if (!ebony_small_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ebony_small_map); + + flash = do_map_probe("map_rom", &ebony_small_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_small_partitions, + ARRAY_SIZE(ebony_small_partitions)); + } else { + printk("map probe failed for flash\n"); + return -ENXIO; + } + + ebony_large_map.phys = large_flash_base; + ebony_large_map.virt = + (unsigned long)ioremap64(large_flash_base, + ebony_large_map.size); + + if (!ebony_large_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ebony_large_map); + + flash = do_map_probe("cfi_probe", &ebony_large_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_large_partitions, + ARRAY_SIZE(ebony_large_partitions)); + } else { + printk("map probe failed for flash\n"); + return -ENXIO; + } + + return 0; +} + +static void __exit cleanup_ebony(void) +{ + if (flash) { + del_mtd_partitions(flash); + map_destroy(flash); + } + + if (ebony_small_map.virt) { + iounmap((void *)ebony_small_map.virt); + ebony_small_map.virt = 0; + } + + if (ebony_large_map.virt) { + iounmap((void *)ebony_large_map.virt); + ebony_large_map.virt = 0; + } +} + +module_init(init_ebony); +module_exit(cleanup_ebony); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matt Porter "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards"); diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c --- a/drivers/mtd/maps/edb7312.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/edb7312.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $ + * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ * * Handle mapping of the NOR flash on Cogent EDB7312 boards * @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -35,61 +36,11 @@ static struct mtd_info *mymtd; -__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} - struct map_info edb7312nor_map = { - name: "NOR flash on EDB7312", - size: WINDOW_SIZE, - buswidth: BUSWIDTH, - read8: edb7312nor_read8, - read16: edb7312nor_read16, - read32: edb7312nor_read32, - copy_from: edb7312nor_copy_from, - write8: edb7312nor_write8, - write16: edb7312nor_write16, - write32: edb7312nor_write32, - copy_to: edb7312nor_copy_to + .name = "NOR flash on EDB7312", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR, }; #ifdef CONFIG_MTD_PARTITIONS @@ -99,30 +50,24 @@ */ static struct mtd_partition static_partitions[3] = { - { - name: "ARMboot", - size: 0x40000, - offset: 0 - }, - { - name: "Kernel", - size: 0x200000, - offset: 0x40000 - }, - { - name: "RootFS", - size: 0xDC0000, - offset: 0x240000 - }, + { + .name = "ARMboot", + .size = 0x40000, + .offset = 0 + }, + { + .name = "Kernel", + .size = 0x200000, + .offset = 0x40000 + }, + { + .name = "RootFS", + .size = 0xDC0000, + .offset = 0x240000 + }, }; -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) - -#ifdef CONFIG_MTD_CMDLINE_PARTS -int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); -#endif +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif @@ -137,13 +82,15 @@ printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.map_priv_1 = (unsigned long) + edb7312nor_map.virt = (unsigned long) ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!edb7312nor_map.map_priv_1) { + if (!edb7312nor_map.virt) { printk(MSG_PREFIX "failed to ioremap\n"); return -EIO; } + + simple_map_init(&edb7312nor_map); mymtd = 0; type = rom_probe_types; @@ -151,18 +98,17 @@ mymtd = do_map_probe(*type, &edb7312nor_map); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID); + mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); if (mtd_parts_nb > 0) - part_type = "command line"; -#endif + part_type = "detected"; + if (mtd_parts_nb == 0) { mtd_parts = static_partitions; - mtd_parts_nb = NB_OF(static_partitions); + mtd_parts_nb = ARRAY_SIZE(static_partitions); part_type = "static"; } #endif @@ -178,7 +124,7 @@ return 0; } - iounmap((void *)edb7312nor_map.map_priv_1); + iounmap((void *)edb7312nor_map.virt); return -ENXIO; } @@ -188,9 +134,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (edb7312nor_map.map_priv_1) { - iounmap((void *)edb7312nor_map.map_priv_1); - edb7312nor_map.map_priv_1 = 0; + if (edb7312nor_map.virt) { + iounmap((void *)edb7312nor_map.virt); + edb7312nor_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c --- a/drivers/mtd/maps/elan-104nc.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/elan-104nc.c Thu Dec 4 16:24:25 2003 @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.13 2002/02/13 15:30:20 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.18 2003/06/23 07:37:02 dwmw2 Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. @@ -40,6 +40,7 @@ #include #include +#include #include #define WINDOW_START 0xb0000 @@ -59,14 +60,14 @@ * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ - { name: "ELAN-104NC flash boot partition", - offset: 0, - size: 640*1024 }, - { name: "ELAN-104NC flash partition 1", - offset: 640*1024, - size: 896*1024 }, - { name: "ELAN-104NC flash partition 2", - offset: (640+896)*1024 } + { .name = "ELAN-104NC flash boot partition", + .offset = 0, + .size = 640*1024 }, + { .name = "ELAN-104NC flash partition 1", + .offset = 640*1024, + .size = 896*1024 }, + { .name = "ELAN-104NC flash partition 2", + .offset = (640+896)*1024 } }; #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) @@ -195,19 +196,20 @@ } static struct map_info elan_104nc_map = { - name: "ELAN-104NC flash", - size: 8*1024*1024, /* this must be set to a maximum possible amount + .name = "ELAN-104NC flash", + .phys = NO_XIP, + .size = 8*1024*1024, /* this must be set to a maximum possible amount of flash so the cfi probe routines find all the chips */ - buswidth: 2, - read8: elan_104nc_read8, - read16: elan_104nc_read16, - read32: elan_104nc_read32, - copy_from: elan_104nc_copy_from, - write8: elan_104nc_write8, - write16: elan_104nc_write16, - write32: elan_104nc_write32, - copy_to: elan_104nc_copy_to + .buswidth = 2, + .read8 = elan_104nc_read8, + .read16 = elan_104nc_read16, + .read32 = elan_104nc_read32, + .copy_from = elan_104nc_copy_from, + .write8 = elan_104nc_write8, + .write16 = elan_104nc_write16, + .write32 = elan_104nc_write32, + .copy_to = elan_104nc_copy_to }; /* MTD device for all of the flash. */ @@ -221,20 +223,13 @@ } iounmap((void *)iomapadr); - release_region(PAGE_IO,PAGE_IO_SIZE); } int __init init_elan_104nc(void) { - /* Urg! We use I/O port 0x22 without request_region()ing it */ - /* - if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { - printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", - elan_104nc_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); - return -EAGAIN; - } - */ + /* Urg! We use I/O port 0x22 without request_region()ing it, + because it's already allocated to the PIC. */ + iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", @@ -242,10 +237,6 @@ return -EIO; } - /* - request_region( PAGE_IO, PAGE_IO_SIZE, "ELAN-104NC flash" ); - */ - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", elan_104nc_map.name, PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, @@ -260,7 +251,7 @@ return -ENXIO; } - all_mtd->module=THIS_MODULE; + all_mtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS ); diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c --- a/drivers/mtd/maps/epxa10db-flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/epxa10db-flash.c Thu Dec 4 16:24:25 2003 @@ -5,7 +5,7 @@ * Copyright (C) 2001 Altera Corporation * Copyright (C) 2001 Red Hat, Inc. * - * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ + * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 Exp $ * * 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 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -43,87 +44,38 @@ static struct mtd_info *mymtd; -extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); -static __u8 epxa_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 epxa_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static __u32 epxa_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - - static struct map_info epxa_map = { - name: "EPXA flash", - size: FLASH_SIZE, - buswidth: 2, - read8: epxa_read8, - read16: epxa_read16, - read32: epxa_read32, - copy_from: epxa_copy_from, - write8: epxa_write8, - write16: epxa_write16, - write32: epxa_write32, - copy_to: epxa_copy_to + .name = "EPXA flash", + .size = FLASH_SIZE, + .buswidth = 2, + .phys = FLASH_START, }; +static const char *probes[] = { "RedBoot", "afs", NULL }; static int __init epxa_mtd_init(void) { int i; - printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); - epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); - if (!epxa_map.map_priv_1) { + printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); + + epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!epxa_map.virt) { printk("Failed to ioremap %s flash\n",BOARD_NAME); return -EIO; } + simple_map_init(&epxa_map); mymtd = do_map_probe("cfi_probe", &epxa_map); if (!mymtd) { - iounmap((void *)epxa_map.map_priv_1); + iounmap((void *)epxa_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* Unlock the flash device. */ if(mymtd->unlock){ @@ -135,23 +87,14 @@ } } -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(mymtd, &parts); - - if (nr_parts > 0) { - add_mtd_partitions(mymtd, parts, nr_parts); - return 0; - } -#endif -#ifdef CONFIG_MTD_AFS_PARTS - nr_parts = parse_afs_partitions(mymtd, &parts); +#ifdef CONFIG_MTD_PARTITIONS + nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0); if (nr_parts > 0) { add_mtd_partitions(mymtd, parts, nr_parts); return 0; } #endif - /* No recognised partitioning schemes found - use defaults */ nr_parts = epxa_default_partitions(mymtd, &parts); if (nr_parts > 0) { @@ -173,9 +116,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (epxa_map.map_priv_1) { - iounmap((void *)epxa_map.map_priv_1); - epxa_map.map_priv_1 = 0; + if (epxa_map.virt) { + iounmap((void *)epxa_map.virt); + epxa_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c --- a/drivers/mtd/maps/fortunet.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/fortunet.c Thu Dec 4 16:24:26 2003 @@ -1,11 +1,12 @@ /* fortunet.c memory map * - * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $ */ #include #include #include +#include #include #include #include @@ -23,7 +24,7 @@ struct map_region { - int window_addr_phyical; + int window_addr_physical; int altbuswidth; struct map_info map_info; struct mtd_info *mymtd; @@ -37,57 +38,10 @@ static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0}; -__u8 fortunet_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -__u16 fortunet_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -__u32 fortunet_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} struct map_info default_map = { - size: DEF_WINDOW_SIZE, - buswidth: 4, - read8: fortunet_read8, - read16: fortunet_read16, - read32: fortunet_read32, - copy_from: fortunet_copy_from, - write8: fortunet_write8, - write16: fortunet_write16, - write32: fortunet_write32, - copy_to: fortunet_copy_to + .size = DEF_WINDOW_SIZE, + .buswidth = 4, }; static char * __init get_string_option(char *dest,int dest_size,char *sor) @@ -147,7 +101,7 @@ get_options (get_string_option(string,sizeof(string),line),6,params); if(params[0]<1) { - printk(MTD_FORTUNET_PK "Bad paramters for MTD Region " + printk(MTD_FORTUNET_PK "Bad parameters for MTD Region " " name,region-number[,base,size,buswidth,altbuswidth]\n"); return 1; } @@ -161,14 +115,14 @@ memcpy(&map_regions[params[1]].map_info, &default_map,sizeof(map_regions[params[1]].map_info)); map_regions_set[params[1]] = 1; - map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY; + map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY; map_regions[params[1]].altbuswidth = 2; map_regions[params[1]].mymtd = NULL; map_regions[params[1]].map_info.name = map_regions[params[1]].map_name; strcpy(map_regions[params[1]].map_info.name,string); if(params[0]>1) { - map_regions[params[1]].window_addr_phyical = params[2]; + map_regions[params[1]].window_addr_physical = params[2]; } if(params[0]>2) { @@ -185,14 +139,14 @@ return 1; } -static int __init MTD_New_Partion(char *line) +static int __init MTD_New_Partition(char *line) { char string[MAX_NAME_SIZE]; int params[4]; get_options (get_string_option(string,sizeof(string),line),4,params); if(params[0]<3) { - printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion " + printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition " " name,region-number,size,offset\n"); return 1; } @@ -204,7 +158,7 @@ } if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS) { - printk(MTD_FORTUNET_PK "Out of space for partion in this region\n"); + printk(MTD_FORTUNET_PK "Out of space for partition in this region\n"); return 1; } map_regions[params[1]].parts[map_regions_parts[params[1]]].name = @@ -220,7 +174,10 @@ } __setup("MTD_Region=", MTD_New_Region); -__setup("MTD_Partion=", MTD_New_Partion); +__setup("MTD_Partition=", MTD_New_Partition); + +/* Backwards-spelling-compatibility */ +__setup("MTD_Partion=", MTD_New_Partition); int __init init_fortunet(void) { @@ -229,13 +186,13 @@ { if(map_regions_parts[ix]&&(!map_regions_set[ix])) { - printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n", + printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n", ix); memset(&map_regions[ix],0,sizeof(map_regions[ix])); memcpy(&map_regions[ix].map_info,&default_map, sizeof(map_regions[ix].map_info)); map_regions_set[ix] = 1; - map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY; + map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY; map_regions[ix].altbuswidth = 2; map_regions[ix].mymtd = NULL; map_regions[ix].map_info.name = map_regions[ix].map_name; @@ -244,30 +201,35 @@ if(map_regions_set[ix]) { iy++; - printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly " + printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically " " address %x size %x\n", map_regions[ix].map_info.name, - map_regions[ix].window_addr_phyical, + map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); - map_regions[ix].map_info.map_priv_1 = + + map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, + + map_regions[ix].map_info.virt = (int)ioremap_nocache( - map_regions[ix].window_addr_phyical, + map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); - if(!map_regions[ix].map_info.map_priv_1) + if(!map_regions[ix].map_info.virt) { printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n", map_regions[ix].map_info.name); return -ENXIO; } - printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n", + simple_map_init(&map_regions[ix].map_info); + + printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n", map_regions[ix].map_info.name, - map_regions[ix].map_info.map_priv_1); + map_regions[ix].map_info.virt); map_regions[ix].mymtd = do_map_probe("cfi_probe", &map_regions[ix].map_info); if((!map_regions[ix].mymtd)&&( map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth)) { - printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth " + printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth " "for %s flash.\n", map_regions[ix].map_info.name); map_regions[ix].map_info.buswidth = @@ -275,7 +237,7 @@ map_regions[ix].mymtd = do_map_probe("cfi_probe", &map_regions[ix].map_info); } - map_regions[ix].mymtd->module = THIS_MODULE; + map_regions[ix].mymtd->owner = THIS_MODULE; add_mtd_partitions(map_regions[ix].mymtd, map_regions[ix].parts,map_regions_parts[ix]); } @@ -297,7 +259,7 @@ del_mtd_partitions( map_regions[ix].mymtd ); map_destroy( map_regions[ix].mymtd ); } - iounmap((void *)map_regions[ix].map_info.map_priv_1); + iounmap((void *)map_regions[ix].map_info.virt); } } } diff -Nru a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/h720x-flash.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,142 @@ +/* + * Flash memory access on Hynix GMS30C7201/HMS30C7202 based + * evaluation boards + * + * (C) 2002 Jungjun Kim + * 2003 Thomas Gleixner +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct mtd_info *mymtd; + +static struct map_info h720x_map = { + .name = "H720X", + .buswidth = 4, + .size = FLASH_SIZE, + .phys = FLASH_PHYS, +}; + +static struct mtd_partition h720x_partitions[] = { + { + .name = "ArMon", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Env", + .size = 0x00040000, + .offset = 0x00080000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Kernel", + .size = 0x00180000, + .offset = 0x000c0000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Ramdisk", + .size = 0x00400000, + .offset = 0x00240000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "jffs2", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND + } +}; + +#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0])) + +static int nr_mtd_parts; +static struct mtd_partition *mtd_parts; +static const char *probes[] = { "cmdlinepart", NULL }; + +/* + * Initialize FLASH support + */ +int __init h720x_mtd_init(void) +{ + + char *part_type = NULL; + + h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE); + + if (!h720x_map.virt) { + printk(KERN_ERR "H720x-MTD: ioremap failed\n"); + return -EIO; + } + + simple_map_init(&h720x_map); + + // Probe for flash buswidth 4 + printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n"); + mymtd = do_map_probe("cfi_probe", &h720x_map); + if (!mymtd) { + printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n"); + // Probe for buswidth 2 + h720x_map.buswidth = 2; + mymtd = do_map_probe("cfi_probe", &h720x_map); + } + + if (mymtd) { + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); + if (nr_mtd_parts > 0) + part_type = "command line"; +#endif + if (nr_mtd_parts <= 0) { + mtd_parts = h720x_partitions; + nr_mtd_parts = NUM_PARTITIONS; + part_type = "builtin"; + } + printk(KERN_INFO "Using %s partition table\n", part_type); + add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts); + return 0; + } + + iounmap((void *)h720x_map.virt); + return -ENXIO; +} + +/* + * Cleanup + */ +static void __exit h720x_mtd_cleanup(void) +{ + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + + /* Free partition info, if commandline partition was used */ + if (mtd_parts && (mtd_parts != h720x_partitions)) + kfree (mtd_parts); + + if (h720x_map.virt) { + iounmap((void *)h720x_map.virt); + h720x_map.virt = 0; + } +} + + +module_init(h720x_mtd_init); +module_exit(h720x_mtd_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards"); diff -Nru a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ichxrom.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,380 @@ +/* + * ichxrom.c + * + * Normal mappings of chips in physical memory + * $Id: ichxrom.c,v 1.1 2003/10/27 19:49:23 thayne Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define xstr(s) str(s) +#define str(s) #s +#define MOD_NAME xstr(KBUILD_BASENAME) + +#define MTD_DEV_NAME_LENGTH 16 + +#define RESERVE_MEM_REGION 0 + +#define ICHX_FWH_REGION_START 0xFF000000UL +#define ICHX_FWH_REGION_SIZE 0x01000000UL +#define BIOS_CNTL 0x4e +#define FWH_DEC_EN1 0xE3 +#define FWH_DEC_EN2 0xF0 +#define FWH_SEL1 0xE8 +#define FWH_SEL2 0xEE + +struct ichxrom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; + struct pci_dev *pdev; + struct resource window_rsrc; + struct resource rom_rsrc; + char mtd_name[MTD_DEV_NAME_LENGTH]; +}; + +static inline unsigned long addr(struct map_info *map, unsigned long ofs) +{ + unsigned long offset; + offset = ((8*1024*1024) - map->size) + ofs; + if (offset >= (4*1024*1024)) { + offset += 0x400000; + } + return map->map_priv_1 + 0x400000 + offset; +} + +static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) +{ + return addr - map->map_priv_1 + ICHX_FWH_REGION_START; +} + +static __u8 ichxrom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(addr(map, ofs)); +} + +static __u16 ichxrom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(addr(map, ofs)); +} + +static __u32 ichxrom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(addr(map, ofs)); +} + +static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, addr(map, from), len); +} + +static void ichxrom_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + __raw_writeb(d, addr(map,ofs)); + mb(); +} + +static void ichxrom_write16(struct map_info *map, __u16 d, unsigned long ofs) +{ + __raw_writew(d, addr(map, ofs)); + mb(); +} + +static void ichxrom_write32(struct map_info *map, __u32 d, unsigned long ofs) +{ + __raw_writel(d, addr(map, ofs)); + mb(); +} + +static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(addr(map, to), from, len); +} + +static struct ichxrom_map_info ichxrom_map = { + .map = { + .name = MOD_NAME, + .phys = NO_XIP, + .size = 0, + .buswidth = 1, + .read8 = ichxrom_read8, + .read16 = ichxrom_read16, + .read32 = ichxrom_read32, + .copy_from = ichxrom_copy_from, + .write8 = ichxrom_write8, + .write16 = ichxrom_write16, + .write32 = ichxrom_write32, + .copy_to = ichxrom_copy_to, + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in-place programming + * needs to use a different method. + */ + }, + /* remaining fields of structure are initialized to 0 */ +}; + +enum fwh_lock_state { + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +static void ichxrom_cleanup(struct ichxrom_map_info *info) +{ + u16 word; + + /* Disable writes through the rom window */ + pci_read_config_word(info->pdev, BIOS_CNTL, &word); + pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1); + + if (info->mtd) { + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = NULL; + info->map.virt = 0; + } + if (info->rom_rsrc.parent) + release_resource(&info->rom_rsrc); + if (info->window_rsrc.parent) + release_resource(&info->window_rsrc); + + if (info->window_addr) { + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + } +} + + +static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, + enum fwh_lock_state state) +{ + struct map_info *map = mtd->priv; + unsigned long start = ofs; + unsigned long end = start + len -1; + + /* FIXME do I need to guard against concurrency here? */ + /* round down to 64K boundaries */ + start = start & ~0xFFFF; + end = end & ~0xFFFF; + while (start <= end) { + unsigned long ctrl_addr; + ctrl_addr = addr(map, start) - 0x400000 + 2; + writeb(state, ctrl_addr); + start = start + 0x10000; + } + return 0; +} + +static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); +} + +static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ichxrom_set_lock_state(mtd, ofs, len, 0); +} + +static int __devinit ichxrom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u16 word; + struct ichxrom_map_info *info = &ichxrom_map; + unsigned long map_size; + + /* For now I just handle the ichx and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MB but it is very painful. Also since + * you can only really attach a FWH to an ICHX there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MB window isn't enough + * but don't currently handle that case either. + */ + + info->pdev = pdev; + + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to the window being "reseved" by the BIOS. + */ + info->window_rsrc.name = MOD_NAME; + info->window_rsrc.start = ICHX_FWH_REGION_START; + info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1; + info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &info->window_rsrc)) { + info->window_rsrc.parent = NULL; + printk(KERN_ERR MOD_NAME + " %s(): Unable to register resource" + " 0x%.08lx-0x%.08lx - kernel bug?\n", + __func__, + info->window_rsrc.start, info->window_rsrc.end); + } + + /* Enable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + if (!(word & 1) && (word & (1<<1))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n"); + goto failed; + } + pci_write_config_word(pdev, BIOS_CNTL, word | 1); + + + /* Map the firmware hub into my address space. */ + /* Does this use too much virtual address space? */ + info->window_addr = (unsigned long)ioremap( + ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto failed; + } + + /* For now assume the firmware has setup all relevant firmware + * windows. We don't have enough information to handle this case + * intelligently. + */ + + /* FIXME select the firmware hub and enable a window to it. */ + + info->mtd = 0; + info->map.map_priv_1 = info->window_addr; + + map_size = ICHX_FWH_REGION_SIZE; + while(!info->mtd && (map_size > 0)) { + info->map.size = map_size; + info->mtd = do_map_probe("jedec_probe", &ichxrom_map.map); + map_size -= 512*1024; + } + if (!info->mtd) { + goto failed; + } + /* I know I can only be a firmware hub here so put + * in the special lock and unlock routines. + */ + info->mtd->lock = ichxrom_lock; + info->mtd->unlock = ichxrom_unlock; + + info->mtd->owner = THIS_MODULE; + add_mtd_device(info->mtd); + + if (info->window_rsrc.parent) { + /* + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. + */ + snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, + "mtd%d", info->mtd->index); + + info->rom_rsrc.name = info->mtd_name; + info->rom_rsrc.start = ICHX_FWH_REGION_START + + ICHX_FWH_REGION_SIZE - map_size; + info->rom_rsrc.end = ICHX_FWH_REGION_START + + ICHX_FWH_REGION_SIZE; + info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + info->rom_rsrc.parent = NULL; + } + } + + return 0; + + failed: + ichxrom_cleanup(info); + return -ENODEV; +} + + +static void __devexit ichxrom_remove_one (struct pci_dev *pdev) +{ + struct ichxrom_map_info *info = &ichxrom_map; + u16 word; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + pci_write_config_word(pdev, BIOS_CNTL, word & ~1); + +#if RESERVE_MEM_REGION + release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); +#endif +} + +static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl); + +#if 0 +static struct pci_driver ichxrom_driver = { + .name = MOD_NAME, + .id_table = ichxrom_pci_tbl, + .probe = ichxrom_init_one, + .remove = ichxrom_remove_one, +}; +#endif + +static struct pci_dev *mydev; +int __init init_ichxrom(void) +{ + struct pci_dev *pdev; + struct pci_device_id *id; + pdev = 0; + for(id = ichxrom_pci_tbl; id->vendor; id++) { + pdev = pci_find_device(id->vendor, id->device, 0); + if (pdev) { + break; + } + } + if (pdev) { + mydev = pdev; + return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&ichxrom_driver); +#endif +} + +static void __exit cleanup_ichxrom(void) +{ + ichxrom_remove_one(mydev); +} + +module_init(init_ichxrom); +module_exit(cleanup_ichxrom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge"); diff -Nru a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c --- a/drivers/mtd/maps/impa7.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/impa7.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $ + * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $ * * Handle mapping of the NOR flash on implementa A7 boards * @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -37,75 +38,17 @@ static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 }; -__u8 impa7_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 impa7_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 impa7_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void impa7_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} static struct map_info impa7_map[NUM_FLASHBANKS] = { { - name: "impA7 NOR Flash Bank #0", - size: WINDOW_SIZE0, - buswidth: BUSWIDTH, - read8: impa7_read8, - read16: impa7_read16, - read32: impa7_read32, - copy_from: impa7_copy_from, - write8: impa7_write8, - write16: impa7_write16, - write32: impa7_write32, - copy_to: impa7_copy_to + .name = "impA7 NOR Flash Bank #0", + .size = WINDOW_SIZE0, + .buswidth = BUSWIDTH, }, { - name: "impA7 NOR Flash Bank #1", - size: WINDOW_SIZE1, - buswidth: BUSWIDTH, - read8: impa7_read8, - read16: impa7_read16, - read32: impa7_read32, - copy_from: impa7_copy_from, - write8: impa7_write8, - write16: impa7_write16, - write32: impa7_write32, - copy_to: impa7_copy_to + .name = "impA7 NOR Flash Bank #1", + .size = WINDOW_SIZE1, + .buswidth = BUSWIDTH, }, }; @@ -116,25 +59,19 @@ */ static struct mtd_partition static_partitions[] = { - { - name: "FileSystem", - size: 0x800000, - offset: 0x00000000 - }, + { + .name = "FileSystem", + .size = 0x800000, + .offset = 0x00000000 + }, }; -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) +static int mtd_parts_nb[NUM_FLASHBANKS]; +static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; -#ifdef CONFIG_MTD_CMDLINE_PARTS -int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); #endif -#endif - -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; +static const char *probes[] = { "cmdlinepart", NULL }; int __init init_impa7(void) { @@ -146,20 +83,21 @@ { WINDOW_ADDR0, WINDOW_SIZE0 }, { WINDOW_ADDR1, WINDOW_SIZE1 }, }; - char mtdid[10]; int devicesfound = 0; for(i=0; imodule = THIS_MODULE; - add_mtd_device(impa7_mtd[i]); + if (impa7_mtd[i]) { + impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - sprintf(mtdid, MTDID, i); - mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], - &mtd_parts, - mtdid); - if (mtd_parts_nb > 0) - part_type = "command line"; -#endif - if (mtd_parts_nb <= 0) - { - mtd_parts = static_partitions; - mtd_parts_nb = NB_OF(static_partitions); + mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], + probes, + &mtd_parts[i], + 0); + if (mtd_parts_nb[i] > 0) { + part_type = "command line"; + } else { + mtd_parts[i] = static_partitions; + mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); part_type = "static"; } - if (mtd_parts_nb <= 0) - { - printk(KERN_NOTICE MSG_PREFIX - "no partition info available\n"); - } - else - { - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - add_mtd_partitions(impa7_mtd[i], - mtd_parts, mtd_parts_nb); - } + + printk(KERN_NOTICE MSG_PREFIX + "using %s partition definition\n", + part_type); + add_mtd_partitions(impa7_mtd[i], + mtd_parts[i], mtd_parts_nb[i]); +#else + add_mtd_device(impa7_mtd[i]); + #endif } else - iounmap((void *)impa7_map[i].map_priv_1); + iounmap((void *)impa7_map[i].virt); } return devicesfound == 0 ? -ENXIO : 0; } @@ -211,17 +140,16 @@ static void __exit cleanup_impa7(void) { int i; - for (i=0; i +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +// board specific stuff - sorry, it should be in arch/arm/mach-*. +#ifdef CONFIG_ARCH_INTEGRATOR + +#define FLASH_BASE INTEGRATOR_FLASH_BASE +#define FLASH_SIZE INTEGRATOR_FLASH_SIZE + +#define FLASH_PART_SIZE 0x400000 + +#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) +#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) +#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET) +#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET) + +/* + * Initialise the flash access systems: + * - Disable VPP + * - Assert WP + * - Set write enable bit in EBI reg + */ +static void armflash_flash_init(void) +{ + unsigned int tmp; + + __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); + + tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; + __raw_writel(tmp, EBI_CSR1); + + if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { + __raw_writel(0xa05f, EBI_LOCK); + __raw_writel(tmp, EBI_CSR1); + __raw_writel(0, EBI_LOCK); + } +} + +/* + * Shutdown the flash access systems: + * - Disable VPP + * - Assert WP + * - Clear write enable bit in EBI reg + */ +static void armflash_flash_exit(void) +{ + unsigned int tmp; + + __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); + + /* + * Clear the write enable bit in system controller EBI register. + */ + tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; + __raw_writel(tmp, EBI_CSR1); + + if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { + __raw_writel(0xa05f, EBI_LOCK); + __raw_writel(tmp, EBI_CSR1); + __raw_writel(0, EBI_LOCK); + } +} + +static void armflash_flash_wp(int on) +{ + unsigned int reg; + + if (on) + reg = SC_CTRLC; + else + reg = SC_CTRLS; + + __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg); +} + +static void armflash_set_vpp(struct map_info *map, int on) +{ + unsigned int reg; + + if (on) + reg = SC_CTRLS; + else + reg = SC_CTRLC; + + __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); +} +#endif + +#ifdef CONFIG_ARCH_P720T + +#define FLASH_BASE (0x04000000) +#define FLASH_SIZE (64*1024*1024) + +#define FLASH_PART_SIZE (4*1024*1024) +#define FLASH_BLOCK_SIZE (128*1024) + +static void armflash_flash_init(void) +{ +} + +static void armflash_flash_exit(void) +{ +} + +static void armflash_flash_wp(int on) +{ +} + +static void armflash_set_vpp(struct map_info *map, int on) +{ +} +#endif + + +static struct map_info armflash_map = +{ + .name = "AFS", + .set_vpp = armflash_set_vpp, + .phys = FLASH_BASE, +}; + +static struct mtd_info *mtd; +static struct mtd_partition *parts; +static const char *probes[] = { "RedBoot", "afs", NULL }; + +static int __init armflash_cfi_init(void *base, u_int size) +{ + int ret; + + armflash_flash_init(); + armflash_flash_wp(1); + + /* + * look for CFI based flash parts fitted to this board + */ + armflash_map.size = size; + armflash_map.buswidth = 4; + armflash_map.virt = (unsigned long) base; + + simple_map_init(&armflash_map); + + /* + * Also, the CFI layer automatically works out what size + * of chips we have, and does the necessary identification + * for us automatically. + */ + mtd = do_map_probe("cfi_probe", &armflash_map); + if (!mtd) + return -ENXIO; + + mtd->owner = THIS_MODULE; + + ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0); + if (ret > 0) { + ret = add_mtd_partitions(mtd, parts, ret); + if (ret) + printk(KERN_ERR "mtd partition registration " + "failed: %d\n", ret); + } + + /* + * If we got an error, free all resources. + */ + if (ret < 0) { + del_mtd_partitions(mtd); + map_destroy(mtd); + } + + return ret; +} + +static void armflash_cfi_exit(void) +{ + if (mtd) { + del_mtd_partitions(mtd); + map_destroy(mtd); + } + if (parts) + kfree(parts); +} + +static int __init armflash_init(void) +{ + int err = -EBUSY; + void *base; + + if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL) + goto out; + + base = ioremap(FLASH_BASE, FLASH_SIZE); + err = -ENOMEM; + if (base == NULL) + goto release; + + err = armflash_cfi_init(base, FLASH_SIZE); + if (err) { + iounmap(base); +release: + release_mem_region(FLASH_BASE, FLASH_SIZE); + } +out: + return err; +} + +static void __exit armflash_exit(void) +{ + armflash_cfi_exit(); + iounmap((void *)armflash_map.virt); + release_mem_region(FLASH_BASE, FLASH_SIZE); + armflash_flash_exit(); +} + +module_init(armflash_init); +module_exit(armflash_exit); + +MODULE_AUTHOR("ARM Ltd"); +MODULE_DESCRIPTION("ARM Integrator CFI map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c --- a/drivers/mtd/maps/integrator-flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/integrator-flash.c Thu Dec 4 16:24:25 2003 @@ -1,8 +1,9 @@ /*====================================================================== - drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning + drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver Copyright (C) 2000 ARM Limited + Copyright (C) 2003 Deep Blue Solutions Ltd. 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 @@ -21,7 +22,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ + $Id: integrator-flash.c,v 1.14 2003/10/11 10:00:31 rmk Exp $ ======================================================================*/ @@ -31,268 +32,181 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include -extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **); - -// board specific stuff - sorry, it should be in arch/arm/mach-*. -#ifdef CONFIG_ARCH_INTEGRATOR - -#define FLASH_BASE INTEGRATOR_FLASH_BASE -#define FLASH_SIZE INTEGRATOR_FLASH_SIZE - -#define FLASH_PART_SIZE 0x400000 - -#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) -#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) -#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET) -#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET) - -/* - * Initialise the flash access systems: - * - Disable VPP - * - Assert WP - * - Set write enable bit in EBI reg - */ -static void armflash_flash_init(void) -{ - unsigned int tmp; - - __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); - - tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; - __raw_writel(tmp, EBI_CSR1); - - if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { - __raw_writel(0xa05f, EBI_LOCK); - __raw_writel(tmp, EBI_CSR1); - __raw_writel(0, EBI_LOCK); - } -} - -/* - * Shutdown the flash access systems: - * - Disable VPP - * - Assert WP - * - Clear write enable bit in EBI reg - */ -static void armflash_flash_exit(void) -{ - unsigned int tmp; - - __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); - - /* - * Clear the write enable bit in system controller EBI register. - */ - tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; - __raw_writel(tmp, EBI_CSR1); - - if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { - __raw_writel(0xa05f, EBI_LOCK); - __raw_writel(tmp, EBI_CSR1); - __raw_writel(0, EBI_LOCK); - } -} - -static void armflash_flash_wp(int on) -{ - unsigned int reg; - - if (on) - reg = SC_CTRLC; - else - reg = SC_CTRLS; - - __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg); -} - -static void armflash_set_vpp(struct map_info *map, int on) -{ - unsigned int reg; - - if (on) - reg = SC_CTRLS; - else - reg = SC_CTRLC; - - __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); -} -#endif - #ifdef CONFIG_ARCH_P720T - #define FLASH_BASE (0x04000000) #define FLASH_SIZE (64*1024*1024) - -#define FLASH_PART_SIZE (4*1024*1024) -#define FLASH_BLOCK_SIZE (128*1024) - -static void armflash_flash_init(void) -{ -} - -static void armflash_flash_exit(void) -{ -} - -static void armflash_flash_wp(int on) -{ -} - -static void armflash_set_vpp(struct map_info *map, int on) -{ -} #endif -static __u8 armflash_read8(struct map_info *map, unsigned long ofs) -{ - return readb(ofs + map->map_priv_2); -} - -static __u16 armflash_read16(struct map_info *map, unsigned long ofs) -{ - return readw(ofs + map->map_priv_2); -} - -static __u32 armflash_read32(struct map_info *map, unsigned long ofs) -{ - return readl(ofs + map->map_priv_2); -} +struct armflash_info { + struct flash_platform_data *plat; + struct resource *res; + struct mtd_partition *parts; + struct mtd_info *mtd; + struct map_info map; +}; -static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +static void armflash_set_vpp(struct map_info *map, int on) { - memcpy(to, (void *) (from + map->map_priv_2), len); -} + struct armflash_info *info = container_of(map, struct armflash_info, map); -static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, adr + map->map_priv_2); + if (info->plat && info->plat->set_vpp) + info->plat->set_vpp(on); } -static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, adr + map->map_priv_2); -} +static const char *probes[] = { "RedBoot", "afs", NULL }; -static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr) +static int armflash_probe(struct device *_dev) { - writel(d, adr + map->map_priv_2); -} + struct platform_device *dev = to_platform_device(_dev); + struct flash_platform_data *plat = dev->dev.platform_data; + struct resource *res = dev->resource; + unsigned int size = res->end - res->start + 1; + struct armflash_info *info; + int err; + void *base; -static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *) (to + map->map_priv_2), from, len); -} + info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL); + if (!info) { + err = -ENOMEM; + goto out; + } -static struct map_info armflash_map = -{ - name: "AFS", - read8: armflash_read8, - read16: armflash_read16, - read32: armflash_read32, - copy_from: armflash_copy_from, - write8: armflash_write8, - write16: armflash_write16, - write32: armflash_write32, - copy_to: armflash_copy_to, - set_vpp: armflash_set_vpp, -}; + memset(info, 0, sizeof(struct armflash_info)); -static struct mtd_info *mtd; -static struct mtd_partition *parts; + info->plat = plat; + if (plat && plat->init) { + err = plat->init(); + if (err) + goto no_resource; + } -static int __init armflash_cfi_init(void *base, u_int size) -{ - int ret; + info->res = request_mem_region(res->start, size, "armflash"); + if (!info->res) { + err = -EBUSY; + goto no_resource; + } - armflash_flash_init(); - armflash_flash_wp(1); + base = ioremap(res->start, size); + if (!base) { + err = -ENOMEM; + goto no_mem; + } /* * look for CFI based flash parts fitted to this board */ - armflash_map.size = size; - armflash_map.buswidth = 4; - armflash_map.map_priv_2 = (unsigned long) base; + info->map.size = size; + info->map.buswidth = plat->width; + info->map.phys = res->start; + info->map.virt = (unsigned long) base; + info->map.name = dev->dev.bus_id; + info->map.set_vpp = armflash_set_vpp; + + simple_map_init(&info->map); /* * Also, the CFI layer automatically works out what size * of chips we have, and does the necessary identification * for us automatically. */ - mtd = do_map_probe("cfi_probe", &armflash_map); - if (!mtd) - return -ENXIO; - - mtd->module = THIS_MODULE; - - ret = parse_afs_partitions(mtd, &parts); - if (ret > 0) { - ret = add_mtd_partitions(mtd, parts, ret); - if (ret) - printk(KERN_ERR "mtd partition registration " - "failed: %d\n", ret); + info->mtd = do_map_probe(plat->map_name, &info->map); + if (!info->mtd) { + err = -ENXIO; + goto no_device; } + info->mtd->owner = THIS_MODULE; + + err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->parts, err); + if (err) + printk(KERN_ERR + "mtd partition registration failed: %d\n", err); + } + + if (err == 0) + dev_set_drvdata(&dev->dev, info); + /* * If we got an error, free all resources. */ - if (ret < 0) { - del_mtd_partitions(mtd); - map_destroy(mtd); - } - - return ret; -} + if (err < 0) { + if (info->mtd) { + del_mtd_partitions(info->mtd); + map_destroy(info->mtd); + } + if (info->parts) + kfree(info->parts); -static void armflash_cfi_exit(void) -{ - if (mtd) { - del_mtd_partitions(mtd); - map_destroy(mtd); + no_device: + iounmap(base); + no_mem: + release_mem_region(res->start, size); + no_resource: + if (plat && plat->exit) + plat->exit(); + kfree(info); } - if (parts) - kfree(parts); + out: + return err; } -static int __init armflash_init(void) +static int armflash_remove(struct device *_dev) { - int err = -EBUSY; - void *base; + struct platform_device *dev = to_platform_device(_dev); + struct armflash_info *info = dev_get_drvdata(&dev->dev); - if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL) - goto out; + dev_set_drvdata(&dev->dev, NULL); - base = ioremap(FLASH_BASE, FLASH_SIZE); - err = -ENOMEM; - if (base == NULL) - goto release; + if (info) { + if (info->mtd) { + del_mtd_partitions(info->mtd); + map_destroy(info->mtd); + } + if (info->parts) + kfree(info->parts); - err = armflash_cfi_init(base, FLASH_SIZE); - if (err) { - iounmap(base); -release: - release_mem_region(FLASH_BASE, FLASH_SIZE); + iounmap((void *)info->map.virt); + release_resource(info->res); + kfree(info->res); + + if (info->plat && info->plat->exit) + info->plat->exit(); + + kfree(info); } -out: - return err; + + return 0; +} + +static struct device_driver armflash_driver = { + .name = "armflash", + .bus = &platform_bus_type, + .probe = armflash_probe, + .remove = armflash_remove, +}; + +static int __init armflash_init(void) +{ + return driver_register(&armflash_driver); } static void __exit armflash_exit(void) { - armflash_cfi_exit(); - iounmap((void *)armflash_map.map_priv_2); - release_mem_region(FLASH_BASE, FLASH_SIZE); - armflash_flash_exit(); + driver_unregister(&armflash_driver); } module_init(armflash_init); diff -Nru a/drivers/mtd/maps/iop3xx.c b/drivers/mtd/maps/iop3xx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/iop3xx.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,182 @@ +/* + * $Id: iop3xx.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ + * + * Mapping for the Intel IOP3xx based platforms + * + * Author: Nicolas Pitre + * Copyright: (C) 2001-2003 MontaVista Software Inc. + * + * 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 + + +#define WINDOW_SIZE 8*1024*1024 +#ifdef CONFIG_ARCH_IQ31244 + #define BUSWIDTH 2 // RevC board has 16bit flash bus +#else + #define BUSWIDTH 1 +#endif + +static struct mtd_info *mymtd; + +static __u8 iop3xx_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 iop3xx_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 iop3xx_read32(struct map_info *map, unsigned long ofs) +{ + return *(__u32 *)(map->map_priv_1 + ofs); +} + +static void iop3xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void iop3xx_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void iop3xx_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void iop3xx_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +static void iop3xx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +static struct map_info iop3xx_map = { + name: "IOP3xx Flash", + size: WINDOW_SIZE, + buswidth: BUSWIDTH, + read8: iop3xx_read8, + read16: iop3xx_read16, + read32: iop3xx_read32, + copy_from: iop3xx_copy_from, + write8: iop3xx_write8, + write16: iop3xx_write16, + write32: iop3xx_write32, + copy_to: iop3xx_copy_to +}; + +static struct mtd_partition iop3xx_partitions[4] = { + { + name: "Firmware", + size: 0x00080000, + offset: 0, + mask_flags: MTD_WRITEABLE /* force read-only */ + },{ + name: "Kernel", + size: 0x000a0000, + offset: 0x00080000, + },{ + name: "Filesystem", + size: 0x00600000, + offset: 0x00120000 + },{ + name: "RedBoot", + size: 0x000e0000, + offset: 0x00720000, + mask_flags: MTD_WRITEABLE + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; +static struct mtd_partition *parsed_parts; + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +static int __init init_iop3xx(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + char *part_type = "static"; + unsigned long window_addr; + + if(iop_is_310()) + window_addr = 0x0; + else if(iop_is_321()) + window_addr = 0xf0000000; + + iop3xx_map.map_priv_1 = (unsigned long)ioremap(window_addr, WINDOW_SIZE); + if (!iop3xx_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("cfi_probe", &iop3xx_map); + if (!mymtd) { + iounmap((void *)iop3xx_map.map_priv_1); + return -ENXIO; + } + mymtd->module = THIS_MODULE; + +#ifdef CONFIG_MTD_REDBOOT_PARTS + if (parsed_nr_parts == 0) { + int ret = parse_redboot_partitions(mymtd, &parsed_parts); + + if (ret > 0) { + part_type = "RedBoot"; + parsed_nr_parts = ret; + } + } +#endif + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + parts = iop3xx_partitions; + nb_parts = NB_OF(iop3xx_partitions); + } + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit cleanup_iop3xx(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (iop3xx_map.map_priv_1) + iounmap((void *)iop3xx_map.map_priv_1); +} + +module_init(init_iop3xx); +module_exit(cleanup_iop3xx); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre "); +MODULE_DESCRIPTION("MTD map driver for Intel IOP3xx based boards"); + diff -Nru a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c --- a/drivers/mtd/maps/iq80310.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/iq80310.c Thu Dec 4 16:24:26 2003 @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ + * $Id: iq80310.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,127 +28,72 @@ static struct mtd_info *mymtd; -static __u8 iq80310_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -static __u16 iq80310_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -static __u32 iq80310_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - static struct map_info iq80310_map = { - name: "IQ80310 flash", - size: WINDOW_SIZE, - buswidth: BUSWIDTH, - read8: iq80310_read8, - read16: iq80310_read16, - read32: iq80310_read32, - copy_from: iq80310_copy_from, - write8: iq80310_write8, - write16: iq80310_write16, - write32: iq80310_write32, - copy_to: iq80310_copy_to + .name = "IQ80310 flash", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR }; static struct mtd_partition iq80310_partitions[4] = { { - name: "Firmware", - size: 0x00080000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ + .name = "Firmware", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ },{ - name: "Kernel", - size: 0x000a0000, - offset: 0x00080000, + .name = "Kernel", + .size = 0x000a0000, + .offset = 0x00080000, },{ - name: "Filesystem", - size: 0x00600000, - offset: 0x00120000 + .name = "Filesystem", + .size = 0x00600000, + .offset = 0x00120000 },{ - name: "RedBoot", - size: 0x000e0000, - offset: 0x00720000, - mask_flags: MTD_WRITEABLE + .name = "RedBoot", + .size = 0x000e0000, + .offset = 0x00720000, + .mask_flags = MTD_WRITEABLE } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - static struct mtd_info *mymtd; static struct mtd_partition *parsed_parts; - -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_iq80310(void) { struct mtd_partition *parts; int nb_parts = 0; int parsed_nr_parts = 0; - char *part_type = "static"; + int ret; - iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!iq80310_map.map_priv_1) { + iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + if (!iq80310_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&iq80310_map); + mymtd = do_map_probe("cfi_probe", &iq80310_map); if (!mymtd) { - iounmap((void *)iq80310_map.map_priv_1); + iounmap((void *)iq80310_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_REDBOOT_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_redboot_partitions(mymtd, &parsed_parts); - - if (ret > 0) { - part_type = "RedBoot"; - parsed_nr_parts = ret; - } - } -#endif + ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); + + if (ret > 0) + parsed_nr_parts = ret; if (parsed_nr_parts > 0) { parts = parsed_parts; nb_parts = parsed_nr_parts; } else { parts = iq80310_partitions; - nb_parts = NB_OF(iq80310_partitions); + nb_parts = ARRAY_SIZE(iq80310_partitions); } - printk(KERN_NOTICE "Using %s partition definition\n", part_type); add_mtd_partitions(mymtd, parts, nb_parts); return 0; } @@ -159,8 +106,8 @@ if (parsed_parts) kfree(parsed_parts); } - if (iq80310_map.map_priv_1) - iounmap((void *)iq80310_map.map_priv_1); + if (iq80310_map.virt) + iounmap((void *)iq80310_map.virt); } module_init(init_iq80310); diff -Nru a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ixp2000.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,300 @@ +/* + * + * drivers/mtd/maps/ixp2000.c + * + * Mapping for the Intel XScale IXP2000 based systems + * + * Copyright (C) 2002 Intel Corp. + * + * Original Author: Naeem M Afzal + * + * Maintainer: Deepak Saxena + * + * 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. + * + * Changelog: + * 28-Mar-2003: Andrzej Mialkowski + * - Added optional flash banking code (IXDP2401/IXDP2801 for now) + * - Fixed IXP2400 errata 44 implementation, added CPU version detection + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WINDOW_ADDR 0xc4000000 +#define BUSWIDTH 1 + +static inline unsigned long flash_bank_setup(struct map_info *map, + unsigned long ofs) +{ + if (map->map_priv_2 != 0) { + /* Call banking routine */ + return ((unsigned long (*)(unsigned long)) + map->map_priv_2) (ofs); + } + /* There is no banking on this system */ + return ofs; +} + +#ifdef __ARMEB__ +/* + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * and XORed with 0x10 on 16 bit accesses. See the spec update, erratta 44. + */ +static int errata44_workaround = 0; + +static inline unsigned long address_fix8_write(unsigned long addr) +{ + if (errata44_workaround) { + return (addr ^ 3); + } + return addr; +} +#else + +#define address_fix8_write(x) (x) +#endif + +static __u8 ixp2000_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *) (map->map_priv_1 + flash_bank_setup(map, ofs)); +} + +/* + * We can't use the standard memcpy due to the broken SlowPort + * address translation on rev A0 and A1 silicon. Once B0 silicon + * is available and I can prove that the errata is fixed, I'll take + * this out. + */ +static void ixp2000_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + from = flash_bank_setup(map, from); + while(len--) + *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); +} + +static void ixp2000_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + *(__u8 *) (address_fix8_write(map->map_priv_1 + + flash_bank_setup(map, ofs))) = d; +} + +static void ixp2000_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + to = flash_bank_setup(map, to); + while(len--) { + unsigned long tmp = address_fix8_write(map->map_priv_1 + to++); + *(__u8 *)(tmp) = *(__u8 *)(from++); + } +} + +static struct map_info ixp2000_map = { + .name = "IXP2000 flash", + .buswidth = BUSWIDTH, + .read8 = ixp2000_read8, + .copy_from = ixp2000_copy_from, + .write8 = ixp2000_write8, + .copy_to = ixp2000_copy_to +}; + +#ifdef CONFIG_ARCH_IXDP2400 +static struct mtd_partition ixp2000_partitions[4] = { + { + .name = "RedBoot", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + },{ + .name = "System Log", + .size = 0x00020000, + .offset = 0x00fa0000, + },{ + .name = "linux", + .size = 0x100000, + .offset = 0x00100000, + },{ + .name = "ramdisk", + .size = 0x400000, + .offset = 0x00200000, + } +}; +#elif defined(CONFIG_ARCH_IXDP2401) || defined(CONFIG_ARCH_IXDP2801) +/* + * Both platforms are not using static partitions, protect only RedBoot area + */ +static struct mtd_partition ixp2000_partitions[2] = { + { + .name:"RedBoot", + .size:0x00200000, + .offset:0, + .mask_flags:MTD_WRITEABLE /* force read-only */ + }, { + .name:"free", + .offset:0x00200000, + } +}; +#elif defined(CONFIG_ARCH_IXDP2800) +static struct mtd_partition ixp2000_partitions[] = { + { + .name = "vBOOT", + .size = 0x00100000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "vWARE FFS", + .size = 0x00700000, + .offset = 0x00100000, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "vWARE free", + .size = 0x00400000, + .offset = 0x00800000, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "free", + .size = 0x00400000, + .offset = 0x00c00000, + } +}; +#else +#error No Architecture defined for MTD partition +#endif + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; +static struct mtd_partition *parsed_parts; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int __init init_ixp2000(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + char *part_type = "Static"; + + /* + * Setup read mode for FLASH + */ + *IXP2000_SLOWPORT_FRM = 1; + +#ifdef __ARMEB__ + /* + * Enable errata 44 workaround for NPUs with broken slowport + */ + + errata44_workaround = npu_has_broken_slowport(); + printk(KERN_NOTICE "IXP2000 flash: Errata 44 workaround %s\n", + errata44_workaround ? "enabled" : "disabled"); +#endif + /* + * map_priv_2 stores banking routine address if banking is used + * map_priv_1 stores virtual adress of flash window + * size stores size of flash address space size (including banking) + */ + +#if defined (CONFIG_ARCH_IXDP2401) + if (machine_is_ixdp2401()) { + /* IXDP2401 uses set of set of 32MB banks */ + ixp2000_map.map_priv_1 = + (unsigned long) ioremap(WINDOW_ADDR, + IXDP2401_FLASH_WINDOW_SIZE); + ixp2000_map.map_priv_2 = + (unsigned long) ixdp2401_set_flash_bank; + ixp2000_map.size = + IXDP2401_FLASH_WINDOW_SIZE * + ixdp2401_get_flash_banks(); + } +#endif + +#if defined (CONFIG_ARCH_IXDP2801) + if (machine_is_ixdp2801()) { + /* IXDP2801 uses set of set of 32MB banks */ + ixp2000_map.map_priv_1 = + (unsigned long) ioremap(WINDOW_ADDR, + IXDP2801_FLASH_WINDOW_SIZE); + ixp2000_map.map_priv_2 = + (unsigned long) ixdp2801_set_flash_bank; + ixp2000_map.size = + IXDP2801_FLASH_WINDOW_SIZE * + ixdp2801_get_flash_banks(); + } +#endif + +#if defined (CONFIG_ARCH_IXDP2400) || defined (CONFIG_ARCH_IXDP2800) + if (machine_is_ixdp2400() || machine_is_ixdp2800()) { + /* IXDP2400 uses only 16MB from CS0 */ + ixp2000_map.map_priv_1 = + (unsigned long) ioremap(WINDOW_ADDR, 0x1000000); + ixp2000_map.map_priv_2 = 0; + ixp2000_map.size = 0x1000000; + } +#endif + + if (!ixp2000_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + + mymtd = do_map_probe("cfi_probe", &ixp2000_map); + if (!mymtd) { + iounmap((void *)ixp2000_map.map_priv_1); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + mymtd->priv = &ixp2000_map; + + parsed_nr_parts = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + if(machine_is_ixdp2401() || machine_is_ixdp2801()) { + /* + * Update free space size according to + * detected chips (??) + */ + ixp2000_partitions[1].size = + mymtd->size - ixp2000_partitions[1].offset; + } + parts = ixp2000_partitions; + nb_parts = NB_OF(ixp2000_partitions); + } + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit cleanup_ixp2000(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (ixp2000_map.map_priv_1) { + iounmap((void *)ixp2000_map.map_priv_1); + } +} + +module_init(init_ixp2000); +module_exit(cleanup_ixp2000); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena"); diff -Nru a/drivers/mtd/maps/ixp425.c b/drivers/mtd/maps/ixp425.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ixp425.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,220 @@ +/* + * $Id: ixp425.c,v 1.1 2003/11/26 21:26:09 dsaxena Exp $ + * + * drivers/mtd/maps/ixp425.c + * + * MTD Map file for IXP425 based systems. Please do not make per-board + * map driver as the code will be 90% identical. For now just add + * if(machine_is_XXX()) checks to the code. I'll clean this stuff to + * use platform_data in the the future so we can get rid of that too. + * + * Original Author: Intel Corporation + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002 Intel Corporation + * Copyright (C) 2003 MontaVista Software, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WINDOW_ADDR 0x50000000 +#define BUSWIDTH 2 + +#ifndef __ARMEB__ +#define BYTE0(h) ((h) & 0xFF) +#define BYTE1(h) (((h) >> 8) & 0xFF) +#else +#define BYTE0(h) (((h) >> 8) & 0xFF) +#define BYTE1(h) ((h) & 0xFF) +#endif + +static __u16 +ixp425_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *) (map->map_priv_1 + ofs); +} + +/* + * The IXP425 expansion bus only allows 16-bit wide acceses + * when attached to a 16-bit wide device (such as the 28F128J3A), + * so we can't just memcpy_fromio(). + */ +static void +ixp425_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + int i; + u8 *dest = (u8 *) to; + u16 *src = (u16 *) (map->map_priv_1 + from); + u16 data; + + for (i = 0; i < (len / 2); i++) { + data = src[i]; + dest[i * 2] = BYTE0(data); + dest[i * 2 + 1] = BYTE1(data); + } + + if (len & 1) + dest[len - 1] = BYTE0(src[i]); +} + +static void +ixp425_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *) (map->map_priv_1 + adr) = d; +} + +static struct map_info ixp425_map = { + .name = "IXP425 Flash", + .buswidth = BUSWIDTH, + .read16 = ixp425_read16, + .copy_from = ixp425_copy_from, + .write16 = ixp425_write16, +}; + +/* + * Put flash back in read mode so RedBoot can boot properly. + */ +int ixp425_mtd_reboot(struct notifier_block *n, unsigned long code, void *p) +{ + if (code != SYS_RESTART) + return NOTIFY_DONE; + + ixp425_write16(&ixp425_map, 0xff, 0x55 * 0x2); + return NOTIFY_DONE; +} + +static struct notifier_block ixp425_mtd_notifier = { + notifier_call:ixp425_mtd_reboot, + next:NULL, + priority:0 +}; + +static struct mtd_partition *parsed_parts; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static struct mtd_partition ixp425_partitions[] = { + { + .name = "image", + .offset = 0x00040000, + .size = 0x00400000, + }, { + .name = "user", + .offset = 0x00440000, + .size = MTDPART_SIZ_FULL + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *ixp425_mtd; +static struct resource *mtd_resource; + +static void +ixp425_exit(void) +{ + if (ixp425_mtd) { + del_mtd_partitions(ixp425_mtd); + map_destroy(ixp425_mtd); + } + if (ixp425_map.map_priv_1) + iounmap((void *) ixp425_map.map_priv_1); + if (mtd_resource) + release_mem_region(WINDOW_ADDR, ixp425_map.size); + + if (parsed_parts) + kfree(parsed_parts); + + unregister_reboot_notifier(&ixp425_mtd_notifier); + + /* Disable flash write */ + *IXP425_EXP_CS0 &= ~IXP425_FLASH_WRITABLE; + + if(machine_is_adi_coyote()) + *IXP425_EXP_CS1 &= ~IXP425_FLASH_WRITABLE; +} + +static int __init +ixp425_init(void) +{ + int res = -1, npart; + + /* Enable flash write */ + *IXP425_EXP_CS0 |= IXP425_FLASH_WRITABLE; + + /* + * Coyote requires CS1 write to be enabled and has 32MB flash. + * This will move to the platform init code in 2.6 + */ + if(machine_is_adi_coyote()) { + *IXP425_EXP_CS1 |= IXP425_FLASH_WRITABLE; + ixp425_map.size = 0x02000000; + } else + ixp425_map.size = 0x01000000; + + ixp425_map.map_priv_1 = 0; + mtd_resource = + request_mem_region(WINDOW_ADDR, ixp425_map.size, "IXP425 Flash"); + if (!mtd_resource) { + printk(KERN_ERR + "ixp425 flash: Could not request mem region.\n"); + res = -ENOMEM; + goto Error; + } + + ixp425_map.map_priv_1 = + (unsigned long) ioremap(WINDOW_ADDR, ixp425_map.size); + if (!ixp425_map.map_priv_1) { + printk("ixp425 Flash: Failed to map IO region. (ioremap)\n"); + res = -EIO; + goto Error; + } + + ixp425_mtd = do_map_probe("cfi_probe", &ixp425_map); + if (!ixp425_mtd) { + res = -ENXIO; + goto Error; + } + ixp425_mtd->owner = THIS_MODULE; + + /* Try to parse RedBoot partitions */ + npart = parse_mtd_partitions(ixp425_mtd, probes, &parsed_parts, 0); + if (npart > 0) + res = add_mtd_partitions(ixp425_mtd, parsed_parts, npart); + else { + printk("IXP425 Flash: Using static MTD partitions.\n"); + res = add_mtd_partitions(ixp425_mtd, ixp425_partitions, + NB_OF(ixp425_partitions)); + } + + if (res) + goto Error; + + register_reboot_notifier(&ixp425_mtd_notifier); + + return res; + +Error: + ixp425_exit(); + return res; +} + +module_init(ixp425_init); +module_exit(ixp425_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD map driver for ixp425 evaluation board"); +MODULE_AUTHOR("Deepak Saxena"); diff -Nru a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c --- a/drivers/mtd/maps/l440gx.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/l440gx.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $ + * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $ * * BIOS Flash chip on Intel 440GX board. * @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -27,48 +28,6 @@ static struct mtd_info *mymtd; -__u8 l440gx_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 l440gx_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 l440gx_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} /* Is this really the vpp port? */ void l440gx_set_vpp(struct map_info *map, int vpp) @@ -85,22 +44,15 @@ } struct map_info l440gx_map = { - name: "L440GX BIOS", - size: WINDOW_SIZE, - buswidth: BUSWIDTH, - read8: l440gx_read8, - read16: l440gx_read16, - read32: l440gx_read32, - copy_from: l440gx_copy_from, - write8: l440gx_write8, - write16: l440gx_write16, - write32: l440gx_write32, - copy_to: l440gx_copy_to, + .name = "L440GX BIOS", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR, #if 0 /* FIXME verify that this is the * appripriate code for vpp enable/disable */ - set_vpp: l440gx_set_vpp + .set_vpp = l440gx_set_vpp #endif }; @@ -113,7 +65,6 @@ dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); @@ -122,15 +73,14 @@ return -ENODEV; } + l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); - l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); - - if (!l440gx_map.map_priv_1) { + if (!l440gx_map.virt) { printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); return -ENOMEM; } - - printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1); + simple_map_init(&l440gx_map); + printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); /* Setup the pm iobase resource * This code should move into some kind of generic bridge @@ -153,7 +103,7 @@ /* Allocate the resource region */ if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { printk(KERN_WARNING "Could not allocate pm iobase resource\n"); - iounmap((void *)l440gx_map.map_priv_1); + iounmap((void *)l440gx_map.virt); return -ENXIO; } } @@ -181,13 +131,13 @@ mymtd = do_map_probe("map_rom", &l440gx_map); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_device(mymtd); return 0; } - iounmap((void *)l440gx_map.map_priv_1); + iounmap((void *)l440gx_map.virt); return -ENXIO; } @@ -196,7 +146,7 @@ del_mtd_device(mymtd); map_destroy(mymtd); - iounmap((void *)l440gx_map.map_priv_1); + iounmap((void *)l440gx_map.virt); } module_init(init_l440gx); diff -Nru a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c --- a/drivers/mtd/maps/lasat.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/lasat.c Thu Dec 4 16:24:26 2003 @@ -1,111 +1,73 @@ /* - * Flash device on lasat 100 and 200 boards + * Flash device on Lasat 100 and 200 boards * - * Presumably (C) 2002 Brian Murphy or whoever he - * works for. + * (C) 2002 Brian Murphy * * 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. * - * $Id: lasat.c,v 1.1 2003/01/24 14:26:38 dwmw2 Exp $ + * $Id: lasat.c,v 1.6 2003/09/02 16:36:40 brm Exp $ * */ #include #include #include +#include #include #include #include #include #include #include -#include -static struct mtd_info *mymtd; +static struct mtd_info *lasat_mtd; -static __u8 sp_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 sp_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static __u32 sp_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -static void sp_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void sp_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void sp_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} +static struct mtd_partition partition_info[LASAT_MTD_LAST]; +static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"}; -static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +static void lasat_set_vpp(struct map_info *map, int vpp) { - memcpy_toio(map->map_priv_1 + to, from, len); + if (vpp) + *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; + else + *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit); } -static struct map_info sp_map = { - .name = "SP flash", +static struct map_info lasat_map = { + .name = "LASAT flash", .buswidth = 4, - .read8 = sp_read8, - .read16 = sp_read16, - .read32 = sp_read32, - .copy_from = sp_copy_from, - .write8 = sp_write8, - .write16 = sp_write16, - .write32 = sp_write32, - .copy_to = sp_copy_to + .set_vpp = lasat_set_vpp }; -static struct mtd_partition partition_info[LASAT_MTD_LAST]; -static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"}; - -static int __init init_sp(void) +static int __init init_lasat(void) { int i; - /* this does not play well with the old flash code which - * protects and uprotects the flash when necessary */ - printk(KERN_NOTICE "Unprotecting flash\n"); - *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; + /* since we use AMD chips and set_vpp is not implimented + * for these (yet) we still have to permanently enable flash write */ + printk(KERN_NOTICE "Unprotecting flash\n"); + ENABLE_VPP((&lasat_map)); + + lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); + lasat_map.virt = (unsigned long)ioremap_nocache( + lasat_map.phys, lasat_board_info.li_flash_size); + lasat_map.size = lasat_board_info.li_flash_size; - sp_map.map_priv_1 = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); - sp_map.size = lasat_board_info.li_flash_size; - - printk(KERN_NOTICE "sp flash device: %lx at %lx\n", - sp_map.size, sp_map.map_priv_1); + simple_map_init(&lasat_map); for (i=0; i < LASAT_MTD_LAST; i++) partition_info[i].name = lasat_mtd_partnames[i]; - mymtd = do_map_probe("cfi_probe", &sp_map); - if (mymtd) { + lasat_mtd = do_map_probe("cfi_probe", &lasat_map); + + if (!lasat_mtd) + lasat_mtd = do_map_probe("jedec_probe", &lasat_map); + + if (lasat_mtd) { u32 size, offset = 0; - mymtd->module = THIS_MODULE; + lasat_mtd->owner = THIS_MODULE; for (i=0; i < LASAT_MTD_LAST; i++) { size = lasat_flash_partition_size(i); @@ -114,26 +76,26 @@ offset += size; } - add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST ); + add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST ); return 0; } return -ENXIO; } -static void __exit cleanup_sp(void) +static void __exit cleanup_lasat(void) { - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); + if (lasat_mtd) { + del_mtd_partitions(lasat_mtd); + map_destroy(lasat_mtd); } - if (sp_map.map_priv_1) { - sp_map.map_priv_1 = 0; + if (lasat_map.virt) { + lasat_map.virt = 0; } } -module_init(init_sp); -module_exit(cleanup_sp); +module_init(init_lasat); +module_exit(cleanup_lasat); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Brian Murphy "); diff -Nru a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/lubbock-flash.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,151 @@ +/* + * $Id: lubbock-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ + * + * Map driver for the Lubbock developer platform. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 + + +#define ROM_ADDR 0x00000000 +#define FLASH_ADDR 0x04000000 + +#define WINDOW_SIZE 64*1024*1024 + +static struct map_info lubbock_maps[2] = { { + .size = WINDOW_SIZE, + .phys = 0x00000000, +}, { + .size = WINDOW_SIZE, + .phys = 0x04000000, +} }; + +static struct mtd_partition lubbock_partitions[] = { + { + .name = "Bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "Kernel", + .size = 0x00100000, + .offset = 0x00040000, + },{ + .name = "Filesystem", + .size = MTDPART_SIZ_FULL, + .offset = 0x00140000 + } +}; + +static struct mtd_info *mymtds[2]; +static struct mtd_partition *parsed_parts[2]; +static int nr_parsed_parts[2]; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int __init init_lubbock(void) +{ + int flashboot = (CONF_SWITCHES & 1); + int ret = 0, i; + + lubbock_maps[0].buswidth = lubbock_maps[1].buswidth = + (BOOT_DEF & 1) ? 2 : 4; + + /* Compensate for the nROMBT switch which swaps the flash banks */ + printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n", + flashboot?"Flash":"ROM", flashboot); + + lubbock_maps[flashboot^1].name = "Lubbock Application Flash"; + lubbock_maps[flashboot].name = "Lubbock Boot ROM"; + + for (i = 0; i < 2; i++) { + lubbock_maps[i].virt = (unsigned long)__ioremap(lubbock_maps[i].phys, WINDOW_SIZE, 0); + if (!lubbock_maps[i].virt) { + printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); + if (!ret) + ret = -ENOMEM; + continue; + } + simple_map_init(&lubbock_maps[i]); + + printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n", + lubbock_maps[i].name, lubbock_maps[i].phys, + lubbock_maps[i].buswidth * 8); + + mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); + + if (!mymtds[i]) { + iounmap((void *)lubbock_maps[i].virt); + if (!ret) + ret = -EIO; + continue; + } + mymtds[i]->owner = THIS_MODULE; + + int ret = parse_mtd_partitions(mymtds[i], probes, + &parsed_parts[i], 0); + + if (ret > 0) + nr_parsed_parts[i] = ret; + } + + if (!mymtds[0] && !mymtds[1]) + return ret; + + for (i = 0; i < 2; i++) { + if (!mymtds[i]) { + printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); + } else if (nr_parsed_parts[i]) { + add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); + } else if (!i) { + printk("Using static partitions on %s\n", lubbock_maps[i].name); + add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions)); + } else { + printk("Registering %s as whole device\n", lubbock_maps[i].name); + add_mtd_device(mymtds[i]); + } + } + return 0; +} + +static void __exit cleanup_lubbock(void) +{ + int i; + for (i = 0; i < 2; i++) { + if (!mymtds[i]) + continue; + + if (nr_parsed_parts[i] || !i) + del_mtd_partitions(mymtds[i]); + else + del_mtd_device(mymtds[i]); + + map_destroy(mymtds[i]); + iounmap((void *)lubbock_maps[i].virt); + + if (parsed_parts[i]) + kfree(parsed_parts[i]); + } +} + +module_init(init_lubbock); +module_exit(cleanup_lubbock); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre "); +MODULE_DESCRIPTION("MTD map driver for Intel Lubbock"); diff -Nru a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/map_funcs.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,96 @@ +/* + * $Id: map_funcs.c,v 1.3 2003/11/14 19:50:04 thayne Exp $ + * + * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS + * is enabled. + */ + +#include +#include +#include +#include +#include +#include + +#include + +static u8 simple_map_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->virt + ofs); +} + +static u16 simple_map_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->virt + ofs); +} + +static u32 simple_map_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->virt + ofs); +} + +static u64 simple_map_read64(struct map_info *map, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); + return 0; +#else + return __raw_readll(map->virt + ofs); +#endif +} + +static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs) +{ + __raw_writeb(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs) +{ + __raw_writew(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs) +{ + __raw_writel(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); +#else + __raw_writell(datum, map->virt + ofs); + mb(); +#endif /* CFI_B8 */ +} + +static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->virt + from, len); +} + +static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->virt + to, from, len); +} + +void simple_map_init(struct map_info *map) +{ + map->read8 = simple_map_read8; + map->read16 = simple_map_read16; + map->read32 = simple_map_read32; + map->read64 = simple_map_read64; + map->write8 = simple_map_write8; + map->write16 = simple_map_write16; + map->write32 = simple_map_write32; + map->write64 = simple_map_write64; + map->copy_from = simple_map_copy_from; + map->copy_to = simple_map_copy_to; +} + +EXPORT_SYMBOL(simple_map_init); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c --- a/drivers/mtd/maps/mbx860.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/mbx860.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $ + * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $ * * Handle mapping of the flash on MBX860 boards * @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -36,91 +37,46 @@ * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ - { name: "MBX flash BOOT partition", - offset: 0, - size: BOOT_PARTITION_SIZE_KiB*1024 }, - { name: "MBX flash DATA partition", - offset: BOOT_PARTITION_SIZE_KiB*1024, - size: (KERNEL_PARTITION_SIZE_KiB)*1024 }, - { name: "MBX flash APPLICATION partition", - offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } + { .name = "MBX flash BOOT partition", + .offset = 0, + .size = BOOT_PARTITION_SIZE_KiB*1024 }, + { .name = "MBX flash DATA partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, + .size = (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { .name = "MBX flash APPLICATION partition", + .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } }; static struct mtd_info *mymtd; -__u8 mbx_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -__u16 mbx_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -__u32 mbx_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -void mbx_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -void mbx_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -void mbx_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - struct map_info mbx_map = { - name: "MBX flash", - size: WINDOW_SIZE, - buswidth: 4, - read8: mbx_read8, - read16: mbx_read16, - read32: mbx_read32, - copy_from: mbx_copy_from, - write8: mbx_write8, - write16: mbx_write16, - write32: mbx_write32, - copy_to: mbx_copy_to + .name = "MBX flash", + .size = WINDOW_SIZE, + .phys = WINDOW_ADDR, + .buswidth = 4, }; int __init init_mbx(void) { - printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); - mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); - if (!mbx_map.map_priv_1) { + if (!mbx_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&mbx_map); + mymtd = do_map_probe("jedec_probe", &mbx_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_device(mymtd); add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); return 0; } - iounmap((void *)mbx_map.map_priv_1); + iounmap((void *)mbx_map.virt); return -ENXIO; } @@ -130,9 +86,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (mbx_map.map_priv_1) { - iounmap((void *)mbx_map.map_priv_1); - mbx_map.map_priv_1 = 0; + if (mbx_map.virt) { + iounmap((void *)mbx_map.virt); + mbx_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/mpc1211.c b/drivers/mtd/maps/mpc1211.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/mpc1211.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,79 @@ +/* + * Flash on MPC-1211 + * + * (C) 2002 Interface, Saito.K & Jeanne + * + * GPL'd + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mtd_info *flash_mtd; +static struct mtd_partition *parsed_parts; + +struct map_info mpc1211_flash_map = { + .name = "MPC-1211 FLASH", + .size = 0x80000, + .buswidth = 1, +}; + +static struct mtd_partition mpc1211_partitions[] = { + { + .name = "IPL & ETH-BOOT", + .offset = 0x00000000, + .size = 0x10000, + }, + { + .name = "Flash FS", + .offset = 0x00010000, + .size = MTDPART_SIZ_FULL, + } +}; + +static int __init init_mpc1211_maps(void) +{ + int nr_parts; + + mpc1211_flash_map.phys = 0; + mpc1211_flash_map.virt = P2SEGADDR(0); + + simple_map_init(&mpc1211_flash_map); + + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); + flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map); + if (!flash_mtd) { + printk(KERN_NOTICE "Flash chips not detected at either possible location.\n"); + return -ENXIO; + } + printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff); + flash_mtd->module = THIS_MODULE; + + parsed_parts = mpc1211_partitions; + nr_parts = ARRAY_SIZE(mpc1211_partitions); + + add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); + return 0; +} + +static void __exit cleanup_mpc1211_maps(void) +{ + if (parsed_parts) + del_mtd_partitions(flash_mtd); + else + del_mtd_device(flash_mtd); + map_destroy(flash_mtd); +} + +module_init(init_mpc1211_maps); +module_exit(cleanup_mpc1211_maps); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Saito.K & Jeanne "); +MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface"); diff -Nru a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c --- a/drivers/mtd/maps/netsc520.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/netsc520.c Thu Dec 4 16:24:25 2003 @@ -3,7 +3,7 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 Exp $ * * 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 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -50,95 +51,41 @@ ** recoverable afterwards. */ -static __u8 netsc520_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 netsc520_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 netsc520_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ { - name: "NetSc520 boot kernel", - offset: 0, - size: 0xc0000 + .name = "NetSc520 boot kernel", + .offset = 0, + .size = 0xc0000 }, { - name: "NetSc520 Low BIOS", - offset: 0xc0000, - size: 0x40000 + .name = "NetSc520 Low BIOS", + .offset = 0xc0000, + .size = 0x40000 }, { - name: "NetSc520 file system", - offset: 0x100000, - size: 0xe80000 + .name = "NetSc520 file system", + .offset = 0x100000, + .size = 0xe80000 }, { - name: "NetSc520 High BIOS", - offset: 0xf80000, - size: 0x80000 + .name = "NetSc520 High BIOS", + .offset = 0xf80000, + .size = 0x80000 }, }; #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) -/* - * If no idea what is going on here. This is taken from the FlashFX stuff. - */ -#define ROMCS 1 - - #define WINDOW_SIZE 0x00100000 #define WINDOW_ADDR 0x00200000 static struct map_info netsc520_map = { - name: "netsc520 Flash Bank", - size: WINDOW_SIZE, - buswidth: 4, - read8: netsc520_read8, - read16: netsc520_read16, - read32: netsc520_read32, - copy_from: netsc520_copy_from, - write8: netsc520_write8, - write16: netsc520_write16, - write32: netsc520_write32, - copy_to: netsc520_copy_to, - map_priv_2: WINDOW_ADDR + .name = "netsc520 Flash Bank", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = WINDOW_ADDR, }; #define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info)) @@ -147,13 +94,16 @@ static int __init init_netsc520(void) { - printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2); - netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size); + printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys); + netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size); - if (!netsc520_map.map_priv_1) { + if (!netsc520_map.virt) { printk("Failed to ioremap_nocache\n"); return -EIO; } + + simple_map_init(&netsc520_map); + mymtd = do_map_probe("cfi_probe", &netsc520_map); if(!mymtd) mymtd = do_map_probe("map_ram", &netsc520_map); @@ -161,11 +111,11 @@ mymtd = do_map_probe("map_rom", &netsc520_map); if (!mymtd) { - iounmap((void *)netsc520_map.map_priv_1); + iounmap((void *)netsc520_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); return 0; } @@ -176,9 +126,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (netsc520_map.map_priv_1) { - iounmap((void *)netsc520_map.map_priv_1); - netsc520_map.map_priv_1 = 0; + if (netsc520_map.virt) { + iounmap((void *)netsc520_map.virt); + netsc520_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c --- a/drivers/mtd/maps/nettel.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/nettel.c Thu Dec 4 16:24:25 2003 @@ -6,7 +6,7 @@ * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) * - * $Id: nettel.c,v 1.1 2002/08/08 06:30:13 gerg Exp $ + * $Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $ */ /****************************************************************************/ @@ -59,128 +59,72 @@ /****************************************************************************/ -static __u8 nettel_read8(struct map_info *map, unsigned long ofs) -{ - return(readb(map->map_priv_1 + ofs)); -} - -static __u16 nettel_read16(struct map_info *map, unsigned long ofs) -{ - return(readw(map->map_priv_1 + ofs)); -} - -static __u32 nettel_read32(struct map_info *map, unsigned long ofs) -{ - return(readl(map->map_priv_1 + ofs)); -} - -static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} - /****************************************************************************/ #ifdef CONFIG_MTD_CFI_INTELEXT static struct map_info nettel_intel_map = { - name: "SnapGear Intel", - size: 0, - buswidth: INTEL_BUSWIDTH, - read8: nettel_read8, - read16: nettel_read16, - read32: nettel_read32, - copy_from: nettel_copy_from, - write8: nettel_write8, - write16: nettel_write16, - write32: nettel_write32, - copy_to: nettel_copy_to + .name = "SnapGear Intel", + .size = 0, + .buswidth = INTEL_BUSWIDTH, }; static struct mtd_partition nettel_intel_partitions[] = { { - name: "SnapGear kernel", - offset: 0, - size: 0x000e0000 + .name = "SnapGear kernel", + .offset = 0, + .size = 0x000e0000 }, { - name: "SnapGear filesystem", - offset: 0x00100000, + .name = "SnapGear filesystem", + .offset = 0x00100000, }, { - name: "SnapGear config", - offset: 0x000e0000, - size: 0x00020000 + .name = "SnapGear config", + .offset = 0x000e0000, + .size = 0x00020000 }, { - name: "SnapGear Intel", - offset: 0 + .name = "SnapGear Intel", + .offset = 0 }, { - name: "SnapGear BIOS Config", - offset: 0x007e0000, - size: 0x00020000 + .name = "SnapGear BIOS Config", + .offset = 0x007e0000, + .size = 0x00020000 }, { - name: "SnapGear BIOS", - offset: 0x007e0000, - size: 0x00020000 + .name = "SnapGear BIOS", + .offset = 0x007e0000, + .size = 0x00020000 }, }; #endif static struct map_info nettel_amd_map = { - name: "SnapGear AMD", - size: AMD_WINDOW_MAXSIZE, - buswidth: AMD_BUSWIDTH, - read8: nettel_read8, - read16: nettel_read16, - read32: nettel_read32, - copy_from: nettel_copy_from, - write8: nettel_write8, - write16: nettel_write16, - write32: nettel_write32, - copy_to: nettel_copy_to + .name = "SnapGear AMD", + .size = AMD_WINDOW_MAXSIZE, + .buswidth = AMD_BUSWIDTH, }; static struct mtd_partition nettel_amd_partitions[] = { { - name: "SnapGear BIOS config", - offset: 0x000e0000, - size: 0x00010000 + .name = "SnapGear BIOS config", + .offset = 0x000e0000, + .size = 0x00010000 }, { - name: "SnapGear BIOS", - offset: 0x000f0000, - size: 0x00010000 + .name = "SnapGear BIOS", + .offset = 0x000f0000, + .size = 0x00010000 }, { - name: "SnapGear AMD", - offset: 0 + .name = "SnapGear AMD", + .offset = 0 }, { - name: "SnapGear high BIOS", - offset: 0x001f0000, - size: 0x00010000 + .name = "SnapGear high BIOS", + .offset = 0x001f0000, + .size = 0x00010000 } }; @@ -328,18 +272,20 @@ *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize); __asm__ ("wbinvd"); - nettel_amd_map.map_priv_1 = (unsigned long) + nettel_amd_map.phys = amdaddr; + nettel_amd_map.virt = (unsigned long) ioremap_nocache(amdaddr, maxsize); - if (!nettel_amd_map.map_priv_1) { + if (!nettel_amd_map.virt) { printk("SNAPGEAR: failed to ioremap() BOOTCS\n"); return(-EIO); } + simple_map_init(&nettel_amd_map); if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", amd_mtd->size>>10); - amd_mtd->module = THIS_MODULE; + amd_mtd->owner = THIS_MODULE; /* The high BIOS partition is only present for 2MB units */ num_amd_partitions = NUM_AMD_PARTITIONS; @@ -387,8 +333,8 @@ /* Destroy useless AMD MTD mapping */ amd_mtd = NULL; - iounmap((void *) nettel_amd_map.map_priv_1); - nettel_amd_map.map_priv_1 = (unsigned long) NULL; + iounmap((void *) nettel_amd_map.virt); + nettel_amd_map.virt = (unsigned long) NULL; #else /* Only AMD flash supported */ return(-ENXIO); @@ -411,16 +357,18 @@ /* Probe for the the size of the first Intel flash */ nettel_intel_map.size = maxsize; - nettel_intel_map.map_priv_1 = (unsigned long) + nettel_intel_map.phys = intel0addr; + nettel_intel_map.virt = (unsigned long) ioremap_nocache(intel0addr, maxsize); - if (!nettel_intel_map.map_priv_1) { + if (!nettel_intel_map.virt) { printk("SNAPGEAR: failed to ioremap() ROMCS1\n"); return(-EIO); } + simple_map_init(&nettel_intel_map); intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); if (! intel_mtd) { - iounmap((void *) nettel_intel_map.map_priv_1); + iounmap((void *) nettel_intel_map.virt); return(-ENXIO); } @@ -441,19 +389,19 @@ /* Delete the old map and probe again to do both chips */ map_destroy(intel_mtd); intel_mtd = NULL; - iounmap((void *) nettel_intel_map.map_priv_1); + iounmap((void *) nettel_intel_map.virt); nettel_intel_map.size = maxsize; - nettel_intel_map.map_priv_1 = (unsigned long) + nettel_intel_map.virt = (unsigned long) ioremap_nocache(intel0addr, maxsize); - if (!nettel_intel_map.map_priv_1) { + if (!nettel_intel_map.virt) { printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n"); return(-EIO); } intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); if (! intel_mtd) { - iounmap((void *) nettel_intel_map.map_priv_1); + iounmap((void *) nettel_intel_map.virt); return(-ENXIO); } @@ -468,7 +416,7 @@ printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", (intel_mtd->size >> 10)); - intel_mtd->module = THIS_MODULE; + intel_mtd->owner = THIS_MODULE; #ifndef CONFIG_BLK_DEV_INITRD ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); @@ -523,18 +471,18 @@ del_mtd_partitions(amd_mtd); map_destroy(amd_mtd); } - if (nettel_amd_map.map_priv_1) { - iounmap((void *)nettel_amd_map.map_priv_1); - nettel_amd_map.map_priv_1 = 0; + if (nettel_amd_map.virt) { + iounmap((void *)nettel_amd_map.virt); + nettel_amd_map.virt = 0; } #ifdef CONFIG_MTD_CFI_INTELEXT if (intel_mtd) { del_mtd_partitions(intel_mtd); map_destroy(intel_mtd); } - if (nettel_intel_map.map_priv_1) { - iounmap((void *)nettel_intel_map.map_priv_1); - nettel_intel_map.map_priv_1 = 0; + if (nettel_intel_map.virt) { + iounmap((void *)nettel_intel_map.virt); + nettel_intel_map.virt = 0; } #endif } diff -Nru a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c --- a/drivers/mtd/maps/ocelot.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/ocelot.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $ * * Flash on Momenco Ocelot */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -20,47 +21,23 @@ #define NVRAM_WINDOW_SIZE 0x00007FF0 #define NVRAM_BUSWIDTH 1 -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); - static unsigned int cacheflush = 0; static struct mtd_info *flash_mtd; static struct mtd_info *nvram_mtd; -__u8 ocelot_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - cacheflush = 1; - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - if (cacheflush) { - dma_cache_inv(map->map_priv_2, map->size); - cacheflush = 0; - } - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - memcpy_fromio(to, map->map_priv_1 + from, len); -} + struct map_info *map = (struct map_info *)mtd->priv; + size_t done = 0; -void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ /* If we use memcpy, it does word-wide writes. Even though we told the GT64120A that it's an 8-bit wide region, word-wide writes don't work. We end up just writing the first byte of the four to all four bytes. So we have this loop instead */ + *retlen = len; while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); + __raw_writeb(*(unsigned char *) from, map->virt + to); from++; to++; len--; @@ -70,24 +47,21 @@ static struct mtd_partition *parsed_parts; struct map_info ocelot_flash_map = { - name: "Ocelot boot flash", - size: FLASH_WINDOW_SIZE, - buswidth: FLASH_BUSWIDTH, - read8: ocelot_read8, - copy_from: ocelot_copy_from_cache, - write8: ocelot_write8, + .name = "Ocelot boot flash", + .size = FLASH_WINDOW_SIZE, + .buswidth = FLASH_BUSWIDTH, + .phys = FLASH_WINDOW_ADDR, }; struct map_info ocelot_nvram_map = { - name: "Ocelot NVRAM", - size: NVRAM_WINDOW_SIZE, - buswidth: NVRAM_BUSWIDTH, - read8: ocelot_read8, - copy_from: ocelot_copy_from, - write8: ocelot_write8, - copy_to: ocelot_copy_to + .name = "Ocelot NVRAM", + .size = NVRAM_WINDOW_SIZE, + .buswidth = NVRAM_BUSWIDTH, + .phys = NVRAM_WINDOW_ADDR, }; +static const char *probes[] = { "RedBoot", NULL }; + static int __init init_ocelot_maps(void) { void *pld; @@ -107,12 +81,13 @@ iounmap(pld); /* Now ioremap the NVRAM space */ - ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); - if (!ocelot_nvram_map.map_priv_1) { + ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); + if (!ocelot_nvram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); return -EIO; } - // ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1; + + simple_map_init(&ocelot_nvram_map); /* And do the RAM probe on it to get an MTD device */ nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map); @@ -120,22 +95,21 @@ printk("NVRAM probe failed\n"); goto fail_1; } - nvram_mtd->module = THIS_MODULE; + nvram_mtd->owner = THIS_MODULE; nvram_mtd->erasesize = 16; + /* Override the write() method */ + nvram_mtd->write = ocelot_ram_write; /* Now map the flash space */ - ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); - if (!ocelot_flash_map.map_priv_1) { + ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); + if (!ocelot_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); goto fail_2; } /* Now the cached version */ - ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); + ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); - if (!ocelot_flash_map.map_priv_2) { - /* Doesn't matter if it failed. Just use the uncached version */ - ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1; - } + simple_map_init(&ocelot_flash_map); /* Only probe for flash if the write jumper is present */ if (brd_status & 0x40) { @@ -155,10 +129,10 @@ add_mtd_device(nvram_mtd); - flash_mtd->module = THIS_MODULE; - nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + flash_mtd->owner = THIS_MODULE; + nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); @@ -166,14 +140,13 @@ return 0; fail3: - iounmap((void *)ocelot_flash_map.map_priv_1); - if (ocelot_flash_map.map_priv_2 && - ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) - iounmap((void *)ocelot_flash_map.map_priv_2); + iounmap((void *)ocelot_flash_map.virt); + if (ocelot_flash_map.cached) + iounmap((void *)ocelot_flash_map.cached); fail_2: map_destroy(nvram_mtd); fail_1: - iounmap((void *)ocelot_nvram_map.map_priv_1); + iounmap((void *)ocelot_nvram_map.virt); return -ENXIO; } @@ -182,16 +155,16 @@ { del_mtd_device(nvram_mtd); map_destroy(nvram_mtd); - iounmap((void *)ocelot_nvram_map.map_priv_1); + iounmap((void *)ocelot_nvram_map.virt); if (parsed_parts) del_mtd_partitions(flash_mtd); else del_mtd_device(flash_mtd); map_destroy(flash_mtd); - iounmap((void *)ocelot_flash_map.map_priv_1); - if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) - iounmap((void *)ocelot_flash_map.map_priv_2); + iounmap((void *)ocelot_flash_map.virt); + if (ocelot_flash_map.cached) + iounmap((void *)ocelot_flash_map.cached); } module_init(init_ocelot_maps); diff -Nru a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c --- a/drivers/mtd/maps/octagon-5066.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/octagon-5066.c Thu Dec 4 16:24:25 2003 @@ -1,4 +1,4 @@ -// $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $ +// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $ /* ###################################################################### Octagon 5066 MTD Driver. @@ -31,6 +31,7 @@ #include #include +#include #define WINDOW_START 0xe8000 #define WINDOW_LENGTH 0x8000 @@ -151,32 +152,34 @@ static struct map_info oct5066_map[2] = { { - name: "Octagon 5066 Socket", - size: 512 * 1024, - buswidth: 1, - read8: oct5066_read8, - read16: oct5066_read16, - read32: oct5066_read32, - copy_from: oct5066_copy_from, - write8: oct5066_write8, - write16: oct5066_write16, - write32: oct5066_write32, - copy_to: oct5066_copy_to, - map_priv_1: 1<<6 + .name = "Octagon 5066 Socket", + .phys = NO_XIP, + .size = 512 * 1024, + .buswidth = 1, + .read8 = oct5066_read8, + .read16 = oct5066_read16, + .read32 = oct5066_read32, + .copy_from = oct5066_copy_from, + .write8 = oct5066_write8, + .write16 = oct5066_write16, + .write32 = oct5066_write32, + .copy_to = oct5066_copy_to, + .map_priv_1 = 1<<6 }, { - name: "Octagon 5066 Internal Flash", - size: 2 * 1024 * 1024, - buswidth: 1, - read8: oct5066_read8, - read16: oct5066_read16, - read32: oct5066_read32, - copy_from: oct5066_copy_from, - write8: oct5066_write8, - write16: oct5066_write16, - write32: oct5066_write32, - copy_to: oct5066_copy_to, - map_priv_1: 2<<6 + .name = "Octagon 5066 Internal Flash", + .phys = NO_XIP, + .size = 2 * 1024 * 1024, + .buswidth = 1, + .read8 = oct5066_read8, + .read16 = oct5066_read16, + .read32 = oct5066_read32, + .copy_from = oct5066_copy_from, + .write8 = oct5066_write8, + .write16 = oct5066_write16, + .write32 = oct5066_write32, + .copy_to = oct5066_copy_to, + .map_priv_1 = 2<<6 } }; @@ -262,7 +265,7 @@ if (!oct5066_mtd[i]) oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]); if (oct5066_mtd[i]) { - oct5066_mtd[i]->module = THIS_MODULE; + oct5066_mtd[i]->owner = THIS_MODULE; add_mtd_device(oct5066_mtd[i]); } } diff -Nru a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/omap-toto-flash.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,137 @@ +/* + * NOR Flash memory access on TI Toto board + * + * jzhang@ti.com (C) 2003 Texas Instruments. + * + * (C) 2002 MontVista Software, Inc. + * + * $Id: omap-toto-flash.c,v 1.1 2003/10/21 13:55:21 dwmw2 Exp $ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +#ifndef CONFIG_ARCH_OMAP +#error This is for OMAP architecture only +#endif + +//these lines need be moved to a hardware header file +#define OMAP_TOTO_FLASH_BASE 0xd8000000 +#define OMAP_TOTO_FLASH_SIZE 0x80000 + +static struct map_info omap_toto_map_flash = { + .name = "OMAP Toto flash", + .buswidth = 2, + .virt = OMAP_TOTO_FLASH_BASE, +}; + + +static struct mtd_partition toto_flash_partitions[] = { + { + .name = "BootLoader", + .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/ + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "ReservedSpace", + .size = 0x00030000, + .offset = MTDPART_OFS_APPEND, + //mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + .name = "EnvArea", /* bottom 64KiB for env vars */ + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; + +static struct mtd_partition *parsed_parts; + +static struct mtd_info *flash_mtd; + +static int __init init_flash (void) +{ + + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + const char *part_type; + + /* + * Static partition definition selection + */ + part_type = "static"; + + parts = toto_flash_partitions; + nb_parts = ARRAY_SIZE(toto_flash_partitions); + omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE; + omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE); + + simple_map_init(&omap_toto_map_flash); + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n", + omap_toto_map_flash.buswidth*8); + flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); + if (!flash_mtd) + return -ENXIO; + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } + + if (nb_parts == 0) { + printk(KERN_NOTICE "OMAP toto flash: no partition info available," + "registering whole flash at once\n"); + if (add_mtd_device(flash_mtd)){ + return -ENXIO; + } + } else { + printk(KERN_NOTICE "Using %s partition definition\n", + part_type); + return add_mtd_partitions(flash_mtd, parts, nb_parts); + } + return 0; +} + +int __init omap_toto_mtd_init(void) +{ + int status; + + if (status = init_flash()) { + printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n"); + } + return status; +} + +static void __exit omap_toto_mtd_cleanup(void) +{ + if (flash_mtd) { + del_mtd_partitions(flash_mtd); + map_destroy(flash_mtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(omap_toto_mtd_init); +module_exit(omap_toto_mtd_cleanup); + +MODULE_AUTHOR("Jian Zhang"); +MODULE_DESCRIPTION("OMAP Toto board map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c --- a/drivers/mtd/maps/pb1xxx-flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/pb1xxx-flash.c Thu Dec 4 16:24:25 2003 @@ -3,12 +3,13 @@ * * (C) 2001 Pete Popov * - * $Id: pb1xxx-flash.c,v 1.4 2002/09/13 13:51:54 dwmw2 Exp $ + * $Id: pb1xxx-flash.c,v 1.10 2003/08/28 06:50:24 ppopov Exp $ */ #include #include #include +#include #include #include @@ -25,168 +26,87 @@ #endif #ifdef CONFIG_MIPS_PB1000 + #define WINDOW_ADDR 0x1F800000 #define WINDOW_SIZE 0x800000 -#endif - -__u8 physmap_read8(struct map_info *map, unsigned long ofs) -{ - __u8 ret; - ret = __raw_readb(map->map_priv_1 + ofs); - DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); - return ret; -} - -__u16 physmap_read16(struct map_info *map, unsigned long ofs) -{ - __u16 ret; - ret = __raw_readw(map->map_priv_1 + ofs); - DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); - return ret; -} - -__u32 physmap_read32(struct map_info *map, unsigned long ofs) -{ - __u32 ret; - ret = __raw_readl(map->map_priv_1 + ofs); - DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); - return ret; -} - -void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} -void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); - memcpy_toio(map->map_priv_1 + to, from, len); -} - - - -static struct map_info pb1xxx_map = { - name: "Pb1xxx flash", - read8: physmap_read8, - read16: physmap_read16, - read32: physmap_read32, - copy_from: physmap_copy_from, - write8: physmap_write8, - write16: physmap_write16, - write32: physmap_write32, - copy_to: physmap_copy_to, -}; - - -#ifdef CONFIG_MIPS_PB1000 - -static unsigned long flash_size = 0x00800000; -static unsigned char flash_buswidth = 4; static struct mtd_partition pb1xxx_partitions[] = { { - name: "yamon env", - size: 0x00020000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "User FS", - size: 0x003e0000, - offset: 0x20000, - },{ - name: "boot code", - size: 0x100000, - offset: 0x400000, - mask_flags: MTD_WRITEABLE - },{ - name: "raw/kernel", - size: 0x300000, - offset: 0x500000 - } + .name = "yamon env", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_WRITEABLE}, + { + .name = "User FS", + .size = 0x003e0000, + .offset = 0x20000,}, + { + .name = "boot code", + .size = 0x100000, + .offset = 0x400000, + .mask_flags = MTD_WRITEABLE}, + { + .name = "raw/kernel", + .size = 0x300000, + .offset = 0x500000} }; #elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) -static unsigned char flash_buswidth = 4; #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -/* both 32MiB banks will be used. Combine the first 32MiB bank and the - * first 28MiB of the second bank together into a single jffs/jffs2 +/* both 32MB banks will be used. Combine the first 32MB bank and the + * first 28MB of the second bank together into a single jffs/jffs2 * partition. */ -static unsigned long flash_size = 0x04000000; #define WINDOW_ADDR 0x1C000000 #define WINDOW_SIZE 0x4000000 static struct mtd_partition pb1xxx_partitions[] = { { - name: "User FS", - size: 0x3c00000, - offset: 0x0000000 - },{ - name: "yamon", - size: 0x0100000, - offset: 0x3c00000, - mask_flags: MTD_WRITEABLE - },{ - name: "raw kernel", - size: 0x02c0000, - offset: 0x3d00000 + .name = "User FS", + .size = 0x3c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = 0x3c00000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = 0x02c0000, + .offset = 0x3d00000 } }; #elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) -static unsigned long flash_size = 0x02000000; #define WINDOW_ADDR 0x1E000000 #define WINDOW_SIZE 0x2000000 static struct mtd_partition pb1xxx_partitions[] = { { - name: "User FS", - size: 0x1c00000, - offset: 0x0000000 - },{ - name: "yamon", - size: 0x0100000, - offset: 0x1c00000, - mask_flags: MTD_WRITEABLE - },{ - name: "raw kernel", - size: 0x02c0000, - offset: 0x1d00000 + .name = "User FS", + .size = 0x1c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = 0x1c00000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = 0x02c0000, + .offset = 0x1d00000 } }; #elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -static unsigned long flash_size = 0x02000000; #define WINDOW_ADDR 0x1C000000 #define WINDOW_SIZE 0x2000000 static struct mtd_partition pb1xxx_partitions[] = { { - name: "User FS", - size: 0x1e00000, - offset: 0x0000000 - },{ - name: "raw kernel", - size: 0x0200000, - offset: 0x1e00000, + .name = "User FS", + .size = 0x1e00000, + .offset = 0x0000000 + },{ + .name = "raw kernel", + .size = 0x0200000, + .offset = 0x1e00000, } }; #else @@ -196,11 +116,20 @@ #error Unsupported board #endif +#define NAME "Pb1x00 Linux Flash" +#define PADDR WINDOW_ADDR +#define BUSWIDTH 4 +#define SIZE WINDOW_SIZE +#define PARTITIONS 4 + +static struct map_info pb1xxx_mtd_map = { + .name = NAME, + .size = SIZE, + .buswidth = BUSWIDTH, + .phys = PADDR, +}; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_partition *parsed_parts; -static struct mtd_info *mymtd; +static struct mtd_info *pb1xxx_mtd; int __init pb1xxx_mtd_init(void) { @@ -208,40 +137,37 @@ int nb_parts = 0; char *part_type; - /* Default flash buswidth */ - pb1xxx_map.buswidth = flash_buswidth; - /* * Static partition definition selection */ part_type = "static"; parts = pb1xxx_partitions; - nb_parts = NB_OF(pb1xxx_partitions); - pb1xxx_map.size = flash_size; + nb_parts = ARRAY_SIZE(pb1xxx_partitions); /* * Now let's probe for the actual flash. Do it here since * specific machine settings might have been set above. */ printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", - pb1xxx_map.buswidth*8); - pb1xxx_map.map_priv_1 = - (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - mymtd = do_map_probe("cfi_probe", &pb1xxx_map); - if (!mymtd) return -ENXIO; - mymtd->module = THIS_MODULE; + BUSWIDTH*8); + pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + + simple_map_init(&pb1xxx_mtd_map); + + pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map); + if (!pb1xxx_mtd) return -ENXIO; + pb1xxx_mtd->owner = THIS_MODULE; - add_mtd_partitions(mymtd, parts, nb_parts); + add_mtd_partitions(pb1xxx_mtd, parts, nb_parts); return 0; } static void __exit pb1xxx_mtd_cleanup(void) { - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - if (parsed_parts) - kfree(parsed_parts); + if (pb1xxx_mtd) { + del_mtd_partitions(pb1xxx_mtd); + map_destroy(pb1xxx_mtd); + iounmap((void *) pb1xxx_mtd_map.virt); } } diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c --- a/drivers/mtd/maps/pci.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/pci.c Thu Dec 4 16:24:25 2003 @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.2 2003/01/24 13:11:43 dwmw2 Exp $ + * $Id: pci.c,v 1.5 2003/05/20 20:59:31 dwmw2 Exp $ * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. @@ -98,10 +98,10 @@ } static struct mtd_pci_info intel_iq80310_info = { - init: intel_iq80310_init, - exit: intel_iq80310_exit, - translate: intel_iq80310_translate, - map_name: "cfi_probe", + .init = intel_iq80310_init, + .exit = intel_iq80310_exit, + .translate = intel_iq80310_translate, + .map_name = "cfi_probe", }; /* @@ -181,10 +181,10 @@ } static struct mtd_pci_info intel_dc21285_info = { - init: intel_dc21285_init, - exit: intel_dc21285_exit, - translate: intel_dc21285_translate, - map_name: "jedec_probe", + .init = intel_dc21285_init, + .exit = intel_dc21285_exit, + .translate = intel_dc21285_translate, + .map_name = "jedec_probe", }; /* @@ -193,22 +193,20 @@ static struct pci_device_id mtd_pci_ids[] __devinitdata = { { - vendor: PCI_VENDOR_ID_INTEL, - device: 0x530d, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - class: PCI_CLASS_MEMORY_OTHER << 8, - class_mask: 0xffff00, - driver_data: (unsigned long)&intel_iq80310_info, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x530d, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = PCI_CLASS_MEMORY_OTHER << 8, + .class_mask = 0xffff00, + .driver_data = (unsigned long)&intel_iq80310_info, }, { - vendor: PCI_VENDOR_ID_DEC, - device: PCI_DEVICE_ID_DEC_21285, - subvendor: 0, /* DC21285 defaults to 0 on reset */ - subdevice: 0, /* DC21285 defaults to 0 on reset */ - class: 0, - class_mask: 0, - driver_data: (unsigned long)&intel_dc21285_info, + .vendor = PCI_VENDOR_ID_DEC, + .device = PCI_DEVICE_ID_DEC_21285, + .subvendor = 0, /* DC21285 defaults to 0 on reset */ + .subdevice = 0, /* DC21285 defaults to 0 on reset */ + .driver_data = (unsigned long)&intel_dc21285_info, }, { 0, } }; @@ -275,14 +273,15 @@ } static struct map_info mtd_pci_map = { - read8: mtd_pci_read8, - read16: mtd_pci_read16, - read32: mtd_pci_read32, - copy_from: mtd_pci_copyfrom, - write8: mtd_pci_write8, - write16: mtd_pci_write16, - write32: mtd_pci_write32, - copy_to: mtd_pci_copyto, + .phys = NO_XIP, + .read8 = mtd_pci_read8, + .read16 = mtd_pci_read16, + .read32 = mtd_pci_read32, + .copy_from = mtd_pci_copyfrom, + .write8 = mtd_pci_write8, + .write16 = mtd_pci_write16, + .write32 = mtd_pci_write32, + .copy_to = mtd_pci_copyto, }; static int __devinit @@ -322,7 +321,7 @@ if (!mtd) goto release; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; add_mtd_device(mtd); pci_set_drvdata(dev, mtd); @@ -359,10 +358,10 @@ } static struct pci_driver mtd_pci_driver = { - name: "MTD PCI", - probe: mtd_pci_probe, - remove: __devexit_p(mtd_pci_remove), - id_table: mtd_pci_ids, + .name = "MTD PCI", + .probe = mtd_pci_probe, + .remove = __devexit_p(mtd_pci_remove), + .id_table = mtd_pci_ids, }; static int __init mtd_pci_maps_init(void) diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c --- a/drivers/mtd/maps/pcmciamtd.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/pcmciamtd.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: pcmciamtd.c,v 1.39 2003/01/06 17:51:38 spse Exp $ + * $Id: pcmciamtd.c,v 1.48 2003/06/24 07:14:38 spse Exp $ * * pcmciamtd.c - MTD driver for PCMCIA flash memory cards * @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #include +#include #ifdef CONFIG_MTD_DEBUG static int debug = CONFIG_MTD_DEBUG_VERBOSE; @@ -47,7 +49,7 @@ #define DRIVER_DESC "PCMCIA Flash memory card driver" -#define DRIVER_VERSION "$Revision: 1.39 $" +#define DRIVER_VERSION "$Revision: 1.48 $" /* Size of the PCMCIA address space: 26 bits = 64 MB */ #define MAX_PCMCIA_ADDR 0x4000000 @@ -96,7 +98,7 @@ MODULE_PARM(mem_speed, "i"); MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns"); MODULE_PARM(force_size, "i"); -MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)"); +MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)"); MODULE_PARM(setvpp, "i"); MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)"); MODULE_PARM(vpp, "i"); @@ -106,11 +108,13 @@ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) static inline void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; CardServices(ReportError, handle, &err); } +#endif /* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */ @@ -529,6 +533,7 @@ card_settings(dev, link, &new_name); + dev->pcmcia_map.phys = NO_XIP; dev->pcmcia_map.read8 = pcmcia_read8_remap; dev->pcmcia_map.read16 = pcmcia_read16_remap; dev->pcmcia_map.copy_from = pcmcia_copy_from_remap; @@ -539,7 +544,7 @@ dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp; /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum - that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the + that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the whole card - otherwise we try smaller windows until we succeed */ req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE; @@ -552,7 +557,7 @@ do { int ret; - DEBUG(2, "requesting window with size = %dKB memspeed = %d", + DEBUG(2, "requesting window with size = %dKiB memspeed = %d", req.Size >> 10, req.AccessSpeed); link->win = (window_handle_t)link->handle; ret = CardServices(RequestWindow, &link->win, &req); @@ -560,7 +565,7 @@ if(ret) { req.Size >>= 1; } else { - DEBUG(2, "Got window of size %dKB", req.Size >> 10); + DEBUG(2, "Got window of size %dKiB", req.Size >> 10); dev->win_size = req.Size; break; } @@ -573,7 +578,7 @@ pcmciamtd_release((u_long)link); return; } - DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10); + DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ CS_CHECK(GetStatus, link->handle, &status); @@ -642,21 +647,21 @@ } dev->mtd_info = mtd; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; if(new_name) { int size = 0; char unit = ' '; /* Since we are using a default name, make it better by adding in the size */ - if(mtd->size < 1048576) { /* <1MB in size, show size in K */ + if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */ size = mtd->size >> 10; unit = 'K'; } else { size = mtd->size >> 20; unit = 'M'; } - snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card"); + snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card"); } /* If the memory found is fits completely into the mapped PCMCIA window, @@ -828,16 +833,20 @@ } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) +static struct pcmcia_driver pcmciamtd_driver = { + .drv = { + .name = "pcmciamtd" + }, + .attach = pcmciamtd_attach, + .detach = pcmciamtd_detach, + .owner = THIS_MODULE +}; +#endif + + static int __init init_pcmciamtd(void) { - servinfo_t serv; - - info(DRIVER_DESC " " DRIVER_VERSION); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - err("Card Services release does not match!"); - return -1; - } if(buswidth && buswidth != 1 && buswidth != 2) { info("bad buswidth (%d), using default", buswidth); @@ -851,15 +860,24 @@ info("bad mem_type (%d), using default", mem_type); mem_type = 0; } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) + return pcmcia_register_driver(&pcmciamtd_driver); +#else register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach); return 0; +#endif } static void __exit exit_pcmciamtd(void) { DEBUG(1, DRIVER_DESC " unloading"); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) + pcmcia_unregister_driver(&pcmciamtd_driver); +#else unregister_pccard_driver(&dev_info); +#endif while(dev_list) { dev_link_t *link = dev_list; diff -Nru a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c --- a/drivers/mtd/maps/physmap.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/physmap.c Thu Dec 4 16:24:25 2003 @@ -1,179 +1,114 @@ /* - * $Id: physmap.c,v 1.21 2002/09/05 05:12:54 acurtis Exp $ + * $Id: physmap.c,v 1.30 2003/11/11 19:05:18 jsun Exp $ * * Normal mappings of chips in physical memory + * + * Copyright (C) 2003 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 031022 - [jsun] add run-time configure and partition setup */ #include #include #include +#include +#include #include #include #include #include - -#ifdef CONFIG_MTD_PARTITIONS #include -#endif - -#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START -#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN -#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH static struct mtd_info *mymtd; -__u8 physmap_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 physmap_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} +struct map_info physmap_map = {.name = "phys_mapped_flash"}; -__u32 physmap_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition *mtd_parts; +static int mtd_parts_nb; -void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} +static int num_physmap_partitions; +static struct mtd_partition *physmap_partitions; -void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} +char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; -void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +void physmap_set_partitions(struct mtd_partition *parts, int num_parts) { - memcpy_toio(map->map_priv_1 + to, from, len); + physmap_partitions=parts; + num_physmap_partitions=num_parts; } - -struct map_info physmap_map = { - name: "Physically mapped flash", - size: WINDOW_SIZE, - buswidth: BUSWIDTH, - read8: physmap_read8, - read16: physmap_read16, - read32: physmap_read32, - copy_from: physmap_copy_from, - write8: physmap_write8, - write16: physmap_write16, - write32: physmap_write32, - copy_to: physmap_copy_to -}; - -#ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS -static struct mtd_partition *mtd_parts = 0; -static int mtd_parts_nb = 0; -#else -static struct mtd_partition physmap_partitions[] = { -/* Put your own partition definitions here */ -#if 0 - { - name: "bootROM", - size: 0x80000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "zImage", - size: 0x100000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - } -#endif -}; - -#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition)) - -#endif -#endif +#endif /* CONFIG_MTD_PARTITIONS */ int __init init_physmap(void) { static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; const char **type; - printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); - physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys); + physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size); - if (!physmap_map.map_priv_1) { + if (!physmap_map.virt) { printk("Failed to ioremap\n"); return -EIO; } - + + simple_map_init(&physmap_map); + mymtd = 0; type = rom_probe_types; for(; !mymtd && *type; type++) { mymtd = do_map_probe(*type, &physmap_map); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; - add_mtd_device(mymtd); #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, - "phys"); + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + &mtd_parts, 0); + if (mtd_parts_nb > 0) { - printk(KERN_NOTICE - "Using command line partition definition\n"); add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + return 0; } -#else - if (NUM_PARTITIONS != 0) + + if (num_physmap_partitions != 0) { printk(KERN_NOTICE "Using physmap partition definition\n"); - add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS); + add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); + return 0; } #endif -#endif + add_mtd_device(mymtd); + return 0; } - iounmap((void *)physmap_map.map_priv_1); + iounmap((void *)physmap_map.virt); return -ENXIO; } static void __exit cleanup_physmap(void) { - if (mymtd) { +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_parts_nb) { + del_mtd_partitions(mymtd); + kfree(mtd_parts); + } else if (num_physmap_partitions) { + del_mtd_partitions(mymtd); + } else { del_mtd_device(mymtd); - map_destroy(mymtd); - } - if (physmap_map.map_priv_1) { - iounmap((void *)physmap_map.map_priv_1); - physmap_map.map_priv_1 = 0; } +#else + del_mtd_device(mymtd); +#endif + map_destroy(mymtd); + + iounmap((void *)physmap_map.virt); + physmap_map.virt = 0; } module_init(init_physmap); diff -Nru a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c --- a/drivers/mtd/maps/pnc2000.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/pnc2000.c Thu Dec 4 16:24:25 2003 @@ -5,12 +5,13 @@ * * This code is GPL * - * $Id: pnc2000.c,v 1.10 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $ */ #include #include #include +#include #include #include @@ -24,58 +25,13 @@ * MAP DRIVER STUFF */ -__u8 pnc_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(WINDOW_ADDR + ofs); -} - -__u16 pnc_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(WINDOW_ADDR + ofs); -} - -__u32 pnc_read32(struct map_info *map, unsigned long ofs) -{ - return *(volatile unsigned int *)(WINDOW_ADDR + ofs); -} - -void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(WINDOW_ADDR + from), len); -} - -void pnc_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(WINDOW_ADDR + to), from, len); -} struct map_info pnc_map = { - name: "PNC-2000", - size: WINDOW_SIZE, - buswidth: 4, - read8: pnc_read8, - read16: pnc_read16, - read32: pnc_read32, - copy_from: pnc_copy_from, - write8: pnc_write8, - write16: pnc_write16, - write32: pnc_write32, - copy_to: pnc_copy_to + .name = "PNC-2000", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = 0xFFFFFFFF, + .virt = WINDOW_ADDR, }; @@ -84,19 +40,19 @@ */ static struct mtd_partition pnc_partitions[3] = { { - name: "PNC-2000 boot firmware", - size: 0x20000, - offset: 0 + .name = "PNC-2000 boot firmware", + .size = 0x20000, + .offset = 0 }, { - name: "PNC-2000 kernel", - size: 0x1a0000, - offset: 0x20000 + .name = "PNC-2000 kernel", + .size = 0x1a0000, + .offset = 0x20000 }, { - name: "PNC-2000 filesystem", - size: 0x240000, - offset: 0x1c0000 + .name = "PNC-2000 filesystem", + .size = 0x240000, + .offset = 0x1c0000 } }; @@ -110,9 +66,11 @@ { printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + simple_map_init(&pnc_map); + mymtd = do_map_probe("cfi_probe", &pnc_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; return add_mtd_partitions(mymtd, pnc_partitions, 3); } diff -Nru a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c --- a/drivers/mtd/maps/redwood.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/redwood.c Thu Dec 4 16:24:25 2003 @@ -1,38 +1,23 @@ /* - * $Id: + * $Id: redwood.c,v 1.7 2003/11/21 23:09:52 trini Exp $ * - * redwood.c - mapper for IBM Redwood-4/5 board. - * - * Copyright 2001 MontaVista Softare Inc. - * - * 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 SOFTWARE IS PROVIDED ``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. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * drivers/mtd/maps/redwood.c * - * History: 12/17/2001 - Armin - * migrated to use do_map_probe + * FLASH map for the IBM Redwood 4/5/6 boards. * + * Author: MontaVista Software, Inc. + * + * 2001-2003 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. */ +#include #include #include #include +#include #include #include @@ -40,134 +25,146 @@ #include +#if !defined (CONFIG_REDWOOD_6) + #define WINDOW_ADDR 0xffc00000 #define WINDOW_SIZE 0x00400000 -__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs) -{ - return *(volatile unsigned int *)(map->map_priv_1 + ofs); -} +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x10000 +#define RW_PART1_OF RW_PART0_SZ +#define RW_PART1_SZ 0x200000 - 0x10000 +#define RW_PART2_OF 0x200000 +#define RW_PART2_SZ 0x10000 +#define RW_PART3_OF 0x210000 +#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000) +#define RW_PART4_OF 0x3e0000 +#define RW_PART4_SZ 0x20000 -void redwood_flash_copy_from(struct map_info *map, void *to, - unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} +static struct mtd_partition redwood_flash_partitions[] = { + { + .name = "Redwood OpenBIOS Vital Product Data", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood kernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ + }, + { + .name = "Redwood OpenBIOS non-volatile storage", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood filesystem", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + }, + { + .name = "Redwood OpenBIOS", + .offset = RW_PART4_OF, + .size = RW_PART4_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + } +}; -void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} +#else /* CONFIG_REDWOOD_6 */ +/* FIXME: the window is bigger - armin */ +#define WINDOW_ADDR 0xff800000 +#define WINDOW_SIZE 0x00800000 + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x400000 /* 4 MiB data */ +#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ +#define RW_PART1_SZ 0x10000 /* 64K VPD */ +#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ +#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) +#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ +#define RW_PART3_SZ 0x20000 -void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} +static struct mtd_partition redwood_flash_partitions[] = { + { + .name = "Redwood filesystem", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "Redwood OpenBIOS Vital Product Data", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood kernel", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ + }, + { + .name = "Redwood OpenBIOS", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + } +}; -void redwood_flash_copy_to(struct map_info *map, unsigned long to, - const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} +#endif /* CONFIG_REDWOOD_6 */ struct map_info redwood_flash_map = { - name: "IBM Redwood", - size: WINDOW_SIZE, - buswidth: 2, - read8: redwood_flash_read8, - read16: redwood_flash_read16, - read32: redwood_flash_read32, - copy_from: redwood_flash_copy_from, - write8: redwood_flash_write8, - write16: redwood_flash_write16, - write32: redwood_flash_write32, - copy_to: redwood_flash_copy_to + .name = "IBM Redwood", + .size = WINDOW_SIZE, + .buswidth = 2, + .phys = WINDOW_ADDR, }; -static struct mtd_partition redwood_flash_partitions[] = { - { - name: "Redwood OpenBIOS Vital Product Data", - offset: 0, - size: 0x10000, - mask_flags: MTD_WRITEABLE /* force read-only */ - }, - { - name: "Redwood kernel", - offset: 0x10000, - size: 0x200000 - 0x10000 - }, - { - name: "Redwood OpenBIOS non-volatile storage", - offset: 0x200000, - size: 0x10000, - mask_flags: MTD_WRITEABLE /* force read-only */ - }, - { - name: "Redwood filesystem", - offset: 0x210000, - size: 0x200000 - (0x10000 + 0x20000) - }, - { - name: "Redwood OpenBIOS", - offset: 0x3e0000, - size: 0x20000, - mask_flags: MTD_WRITEABLE /* force read-only */ - } -}; #define NUM_REDWOOD_FLASH_PARTITIONS \ - (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0])) + (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0])) static struct mtd_info *redwood_mtd; int __init init_redwood_flash(void) { - printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n", - WINDOW_SIZE, WINDOW_ADDR); + printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n", + WINDOW_SIZE, WINDOW_ADDR); - redwood_flash_map.map_priv_1 = - (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + redwood_flash_map.virt = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!redwood_flash_map.map_priv_1) { - printk("init_redwood_flash: failed to ioremap\n"); - return -EIO; - } - - redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map); - - if (redwood_mtd) { - redwood_mtd->module = THIS_MODULE; - return add_mtd_partitions(redwood_mtd, - redwood_flash_partitions, - NUM_REDWOOD_FLASH_PARTITIONS); - } + if (!redwood_flash_map.virt) { + printk("init_redwood_flash: failed to ioremap\n"); + return -EIO; + } + simple_map_init(&redwood_flash_map); + + redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map); + + if (redwood_mtd) { + redwood_mtd->owner = THIS_MODULE; + return add_mtd_partitions(redwood_mtd, + redwood_flash_partitions, + NUM_REDWOOD_FLASH_PARTITIONS); + } - return -ENXIO; + return -ENXIO; } static void __exit cleanup_redwood_flash(void) { - if (redwood_mtd) { - del_mtd_partitions(redwood_mtd); - iounmap((void *)redwood_flash_map.map_priv_1); - map_destroy(redwood_mtd); - } + if (redwood_mtd) { + del_mtd_partitions(redwood_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(redwood_mtd); + iounmap((void *)redwood_flash_map.virt); + } } module_init(init_redwood_flash); module_exit(cleanup_redwood_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MontaVista Software "); +MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards"); diff -Nru a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c --- a/drivers/mtd/maps/rpxlite.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/rpxlite.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $ * * Handle mapping of the flash on the RPX Lite and CLLF boards */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,80 +18,31 @@ static struct mtd_info *mymtd; -__u8 rpxlite_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 rpxlite_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 rpxlite_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - -struct map_info rpxlite_map = { - name: "RPX", - size: WINDOW_SIZE, - buswidth: 4, - read8: rpxlite_read8, - read16: rpxlite_read16, - read32: rpxlite_read32, - copy_from: rpxlite_copy_from, - write8: rpxlite_write8, - write16: rpxlite_write16, - write32: rpxlite_write32, - copy_to: rpxlite_copy_to +static struct map_info rpxlite_map = { + .name = "RPX", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = WINDOW_ADDR, }; int __init init_rpxlite(void) { printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); - rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); - if (!rpxlite_map.map_priv_1) { + if (!rpxlite_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&rpxlite_map); mymtd = do_map_probe("cfi_probe", &rpxlite_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_device(mymtd); return 0; } - iounmap((void *)rpxlite_map.map_priv_1); + iounmap((void *)rpxlite_map.virt); return -ENXIO; } @@ -100,9 +52,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (rpxlite_map.map_priv_1) { - iounmap((void *)rpxlite_map.map_priv_1); - rpxlite_map.map_priv_1 = 0; + if (rpxlite_map.virt) { + iounmap((void *)rpxlite_map.virt); + rpxlite_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c --- a/drivers/mtd/maps/sa1100-flash.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/sa1100-flash.c Thu Dec 4 16:24:26 2003 @@ -3,7 +3,7 @@ * * (C) 2000 Nicolas Pitre * - * $Id: sa1100-flash.c,v 1.29 2002/09/06 14:36:19 abz Exp $ + * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $ */ #include @@ -11,287 +11,186 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include +#include #include +#include +#include #ifndef CONFIG_ARCH_SA1100 #error This is for SA1100 architecture only #endif +/* + * This isnt complete yet, so... + */ +#define CONFIG_MTD_SA1100_STATICMAP 1 -#define WINDOW_ADDR 0xe8000000 - -static __u8 sa1100_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 sa1100_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 sa1100_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - -static struct map_info sa1100_map = { - name: "SA1100 flash", - read8: sa1100_read8, - read16: sa1100_read16, - read32: sa1100_read32, - copy_from: sa1100_copy_from, - write8: sa1100_write8, - write16: sa1100_write16, - write32: sa1100_write32, - copy_to: sa1100_copy_to, - - map_priv_1: WINDOW_ADDR, - map_priv_2: -1, -}; - - +#ifdef CONFIG_MTD_SA1100_STATICMAP /* * Here are partition information for all known SA1100-based devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. * - * The *_max_flash_size is the maximum possible mapped flash size which - * is not necessarily the actual flash size. It must be no more than - * the value specified in the "struct map_desc *_io_desc" mapping - * definition for the corresponding machine. + * Please note: + * 1. We no longer support static flash mappings via the machine io_desc + * structure. + * 2. The flash size given should be the largest flash size that can + * be accommodated. + * + * The MTD layer will detect flash chip aliasing and reduce the size of + * the map accordingly. * * Please keep these in alphabetical order, and formatted as per existing * entries. Thanks. */ -#ifdef CONFIG_SA1100_ADSAGC -#define ADSAGC_FLASH_SIZE 0x02000000 -static struct mtd_partition adsagc_partitions[] = { - { - name: "bootROM", - size: 0x80000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "zImage", - size: 0x100000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - } -}; -#endif - #ifdef CONFIG_SA1100_ADSBITSY -#define ADSBITSY_FLASH_SIZE 0x02000000 static struct mtd_partition adsbitsy_partitions[] = { { - name: "bootROM", - size: 0x80000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "zImage", - size: 0x100000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - } -}; -#endif - -#ifdef CONFIG_SA1100_ADSBITSYPLUS -#define ADSBITSYPLUS_FLASH_SIZE 0x02000000 -static struct mtd_partition adsbitsyplus_partitions[] = { - { - name: "bootROM", - size: 0x80000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "zImage", - size: 0x100000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "bootROM", + .size = 0x80000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "zImage", + .size = 0x100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "ramdisk.gz", + .size = 0x300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "User FS", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_ASSABET /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ -#define ASSABET4_FLASH_SIZE 0x00400000 static struct mtd_partition assabet4_partitions[] = { { - name: "bootloader", - size: 0x00020000, - offset: 0, - mask_flags: MTD_WRITEABLE, - }, { - name: "bootloader params", - size: 0x00020000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "bootloader params", + .size = 0x00020000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "jffs", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */ -#define ASSABET5_FLASH_SIZE 0x02000000 static struct mtd_partition assabet5_partitions[] = { { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, - }, { - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "bootloader params", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "jffs", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; -#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE #define assabet_partitions assabet5_partitions #endif #ifdef CONFIG_SA1100_BADGE4 - /* - * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit) + * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit) * Eight 4 KiW Parameter Bottom Blocks (64 KiB) * Sixty-three 32 KiW Main Blocks (4032 Ki b) + * + * + * + * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit) + * Eight 4 KiW Parameter Bottom Blocks (64 KiB) + * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b) */ -#define BADGE4_FLASH_SIZE 0x00400000 static struct mtd_partition badge4_partitions[] = { { - name: "BLOB boot loader", - offset: 0, - size: 0x0000A000 - }, { - name: "params", - offset: MTDPART_OFS_APPEND, - size: 0x00006000 - }, { - name: "kernel", - offset: MTDPART_OFS_APPEND, - size: 0x00100000 - }, { - name: "root", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + .name = "BLOB boot loader", + .offset = 0, + .size = 0x0000A000 + }, { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = 0x00006000 + }, { + .name = "root", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL } }; - #endif #ifdef CONFIG_SA1100_CERF #ifdef CONFIG_SA1100_CERF_FLASH_32MB -#define CERF_FLASH_SIZE 0x02000000 static struct mtd_partition cerf_partitions[] = { { - name: "firmware", - size: 0x00040000, - offset: 0, - }, { - name: "params", - size: 0x00040000, - offset: 0x00040000, - }, { - name: "kernel", - size: 0x00100000, - offset: 0x00080000, - }, { - name: "rootdisk", - size: 0x01E80000, - offset: 0x00180000, + .name = "firmware", + .size = 0x00040000, + .offset = 0, + }, { + .name = "params", + .size = 0x00040000, + .offset = 0x00040000, + }, { + .name = "kernel", + .size = 0x00100000, + .offset = 0x00080000, + }, { + .name = "rootdisk", + .size = 0x01E80000, + .offset = 0x00180000, } }; #elif defined CONFIG_SA1100_CERF_FLASH_16MB -#define CERF_FLASH_SIZE 0x01000000 static struct mtd_partition cerf_partitions[] = { { - name: "firmware", - size: 0x00020000, - offset: 0, - }, { - name: "params", - size: 0x00020000, - offset: 0x00020000, - }, { - name: "kernel", - size: 0x00100000, - offset: 0x00040000, - }, { - name: "rootdisk", - size: 0x00EC0000, - offset: 0x00140000, + .name = "firmware", + .size = 0x00020000, + .offset = 0, + }, { + .name = "params", + .size = 0x00020000, + .offset = 0x00020000, + }, { + .name = "kernel", + .size = 0x00100000, + .offset = 0x00040000, + }, { + .name = "rootdisk", + .size = 0x00EC0000, + .offset = 0x00140000, } }; #elif defined CONFIG_SA1100_CERF_FLASH_8MB @@ -302,39 +201,38 @@ #endif #ifdef CONFIG_SA1100_CONSUS -#define CONSUS_FLASH_SIZE 0x02000000 static struct mtd_partition consus_partitions[] = { { - name: "Consus boot firmware", - offset: 0, - size: 0x00040000, - mask_flags: MTD_WRITABLE, /* force read-only */ - }, { - name: "Consus kernel", - offset: 0x00040000, - size: 0x00100000, - mask_flags: 0, + .name = "Consus boot firmware", + .offset = 0, + .size = 0x00040000, + .mask_flags = MTD_WRITABLE, /* force read-only */ + }, { + .name = "Consus kernel", + .offset = 0x00040000, + .size = 0x00100000, + .mask_flags = 0, }, { - name: "Consus disk", - offset: 0x00140000, + .name = "Consus disk", + .offset = 0x00140000, /* The rest (up to 16M) for jffs. We could put 0 and make it find the size automatically, but right now i have 32 megs. jffs will use all 32 megs if given the chance, and this leads to horrible problems when you try to re-flash the image because blob won't erase the whole partition. */ - size: 0x01000000 - 0x00140000, - mask_flags: 0, + .size = 0x01000000 - 0x00140000, + .mask_flags = 0, }, { /* this disk is a secondary disk, which can be used as needed, for simplicity, make it the size of the other consus partition, although realistically it could be the remainder of the disk (depending on the file system used) */ - name: "Consus disk2", - offset: 0x01000000, - size: 0x01000000 - 0x00140000, - mask_flags: 0, + .name = "Consus disk2", + .offset = 0x01000000, + .size = 0x01000000 - 0x00140000, + .mask_flags = 0, } }; #endif @@ -344,96 +242,95 @@ #define FLEXANET_FLASH_SIZE 0x02000000 static struct mtd_partition flexanet_partitions[] = { { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, - }, { - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "kernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "altkernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "root", - size: 0x00400000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "free1", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "free2", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, - }, { - name: "free3", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, + .name = "bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "bootloader params", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "kernel", + .size = 0x000C0000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "altkernel", + .size = 0x000C0000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "root", + .size = 0x00400000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "free1", + .size = 0x00300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "free2", + .size = 0x00300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "free3", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, } }; #endif #ifdef CONFIG_SA1100_FREEBIRD -#define FREEBIRD_FLASH_SIZE 0x02000000 static struct mtd_partition freebird_partitions[] = { -#if CONFIG_SA1100_FREEBIRD_NEW +#ifdef CONFIG_SA1100_FREEBIRD_NEW { - name: "firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "kernel", - size: 0x00080000, - offset: 0x00040000, - }, { - name: "params", - size: 0x00040000, - offset: 0x000C0000, - }, { - name: "initrd", - size: 0x00100000, - offset: 0x00100000, - }, { - name: "root cramfs", - size: 0x00300000, - offset: 0x00200000, - }, { - name: "usr cramfs", - size: 0x00C00000, - offset: 0x00500000, - }, { - name: "local", - size: MTDPART_SIZ_FULL, - offset: 0x01100000, + .name = "firmware", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "kernel", + .size = 0x00080000, + .offset = 0x00040000, + }, { + .name = "params", + .size = 0x00040000, + .offset = 0x000C0000, + }, { + .name = "initrd", + .size = 0x00100000, + .offset = 0x00100000, + }, { + .name = "root cramfs", + .size = 0x00300000, + .offset = 0x00200000, + }, { + .name = "usr cramfs", + .size = 0x00C00000, + .offset = 0x00500000, + }, { + .name = "local", + .size = MTDPART_SIZ_FULL, + .offset = 0x01100000, } #else { - size: 0x00040000, - offset: 0, + .size = 0x00040000, + .offset = 0, }, { - size: 0x000c0000, - offset: MTDPART_OFS_APPEND, + .size = 0x000c0000, + .offset = MTDPART_OFS_APPEND, }, { - size: 0x00400000, - offset: MTDPART_OFS_APPEND, + .size = 0x00400000, + .offset = MTDPART_OFS_APPEND, }, { - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } #endif }; @@ -441,206 +338,211 @@ #ifdef CONFIG_SA1100_FRODO /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ -#define FRODO_FLASH_SIZE 0x02000000 static struct mtd_partition frodo_partitions[] = { { - name: "Boot Loader", - size: 0x00040000, - offset: 0x00000000 - }, { - name: "Parameter Block", - size: 0x00040000, - offset: MTDPART_OFS_APPEND - }, { - name: "Linux Kernel", - size: 0x00100000, - offset: MTDPART_OFS_APPEND - }, { - name: "Ramdisk", - size: 0x00680000, - offset: MTDPART_OFS_APPEND - }, { - name: "Flash File System", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND + .name = "bootloader", + .size = 0x00040000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE + }, { + .name = "bootloader params", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + }, { + .name = "kernel", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + }, { + .name = "ramdisk", + .size = 0x00400000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + }, { + .name = "file system", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND } }; #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT -#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000 static struct mtd_partition graphicsclient_partitions[] = { { - name: "zImage", - size: 0x100000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "zImage", + .size = 0x100000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "ramdisk.gz", + .size = 0x300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "User FS", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER -#define GRAPHICSMASTER_FLASH_SIZE 0x02000000 static struct mtd_partition graphicsmaster_partitions[] = { { - name: "zImage", - size: 0x100000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "zImage", + .size = 0x100000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "ramdisk.gz", - size: 0x300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "ramdisk.gz", + .size = 0x300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "User FS", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "User FS", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif -#ifdef CONFIG_SA1100_H3600 -#define H3600_FLASH_SIZE 0x02000000 -static struct mtd_partition h3600_partitions[] = { +#ifdef CONFIG_SA1100_H3XXX +static struct mtd_partition h3xxx_partitions[] = { { - name: "H3600 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "H3XXX boot firmware", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "H3600 kernel", - size: 0x00080000, - offset: 0x00040000, - }, { - name: "H3600 params", - size: 0x00040000, - offset: 0x000C0000, +#ifdef CONFIG_MTD_2PARTS_IPAQ + .name = "H3XXX root jffs2", + .size = MTDPART_SIZ_FULL, + .offset = 0x00040000, +#else + .name = "H3XXX kernel", + .size = 0x00080000, + .offset = 0x00040000, + }, { + .name = "H3XXX params", + .size = 0x00040000, + .offset = 0x000C0000, }, { #ifdef CONFIG_JFFS2_FS - name: "H3600 root jffs2", - size: MTDPART_SIZ_FULL, - offset: 0x00100000, + .name = "H3XXX root jffs2", + .size = MTDPART_SIZ_FULL, + .offset = 0x00100000, #else - name: "H3600 initrd", - size: 0x00100000, - offset: 0x00100000, + .name = "H3XXX initrd", + .size = 0x00100000, + .offset = 0x00100000, }, { - name: "H3600 root cramfs", - size: 0x00300000, - offset: 0x00200000, + .name = "H3XXX root cramfs", + .size = 0x00300000, + .offset = 0x00200000, }, { - name: "H3600 usr cramfs", - size: 0x00800000, - offset: 0x00500000, + .name = "H3XXX usr cramfs", + .size = 0x00800000, + .offset = 0x00500000, }, { - name: "H3600 usr local", - size: MTDPART_SIZ_FULL, - offset: 0x00d00000, + .name = "H3XXX usr local", + .size = MTDPART_SIZ_FULL, + .offset = 0x00d00000, +#endif #endif } }; -static void h3600_set_vpp(struct map_info *map, int vpp) +static void h3xxx_set_vpp(struct map_info *map, int vpp) { assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp); } +#else +#define h3xxx_set_vpp NULL #endif #ifdef CONFIG_SA1100_HACKKIT -#define HACKKIT_FLASH_SIZE 0x01000000 static struct mtd_partition hackkit_partitions[] = { { - name: "BLOB", - size: 0x00040000, - offset: 0x00000000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "config", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - }, { - name: "kernel", - size: 0x00100000, - offset: MTDPART_OFS_APPEND, - }, { - name: "initrd", - size: 0x00180000, - offset: MTDPART_OFS_APPEND, - }, { - name: "rootfs", - size: 0x700000, - offset: MTDPART_OFS_APPEND, - }, { - name: "data", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "BLOB", + .size = 0x00040000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "config", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "kernel", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "initrd", + .size = 0x00180000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "rootfs", + .size = 0x700000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "data", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_HUW_WEBPANEL -#define HUW_WEBPANEL_FLASH_SIZE 0x01000000 static struct mtd_partition huw_webpanel_partitions[] = { { - name: "Loader", - size: 0x00040000, - offset: 0, - }, { - name: "Sector 1", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, + .name = "Loader", + .size = 0x00040000, + .offset = 0, + }, { + .name = "Sector 1", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, }, { - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_JORNADA720 -#define JORNADA720_FLASH_SIZE 0x02000000 static struct mtd_partition jornada720_partitions[] = { { - name: "JORNADA720 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "JORNADA720 kernel", - size: 0x000c0000, - offset: 0x00040000, - }, { - name: "JORNADA720 params", - size: 0x00040000, - offset: 0x00100000, - }, { - name: "JORNADA720 initrd", - size: 0x00100000, - offset: 0x00140000, - }, { - name: "JORNADA720 root cramfs", - size: 0x00300000, - offset: 0x00240000, - }, { - name: "JORNADA720 usr cramfs", - size: 0x00800000, - offset: 0x00540000, - }, { - name: "JORNADA720 usr local", - size: 0, /* will expand to the end of the flash */ - offset: 0x00d00000, + .name = "JORNADA720 boot firmware", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "JORNADA720 kernel", + .size = 0x000c0000, + .offset = 0x00040000, + }, { + .name = "JORNADA720 params", + .size = 0x00040000, + .offset = 0x00100000, + }, { + .name = "JORNADA720 initrd", + .size = 0x00100000, + .offset = 0x00140000, + }, { + .name = "JORNADA720 root cramfs", + .size = 0x00300000, + .offset = 0x00240000, + }, { + .name = "JORNADA720 usr cramfs", + .size = 0x00800000, + .offset = 0x00540000, + }, { + .name = "JORNADA720 usr local", + .size = 0, /* will expand to the end of the flash */ + .offset = 0x00d00000, } }; @@ -652,540 +554,816 @@ PPSR &= ~0x80; PPDR |= 0x80; } - -#endif - -#ifdef CONFIG_SA1100_NANOENGINE -/* nanoEngine has one 28F320B3B Flash part in bank 0: */ -#define NANOENGINE_FLASH_SIZE 0x00400000 -static struct mtd_partition nanoengine_partitions[] = { - { - name: "nanoEngine boot firmware and parameter table", - size: 0x00010000, /* 32K */ - offset: 0x00000000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - },{ - name: "kernel/initrd reserved", - size: 0x002f0000, - offset: 0x00010000, - },{ - name: "experimental filesystem allocation", - size: 0x00100000, - offset: 0x00300000, - } -}; +#else +#define jornada720_set_vpp NULL #endif #ifdef CONFIG_SA1100_PANGOLIN -#define PANGOLIN_FLASH_SIZE 0x04000000 static struct mtd_partition pangolin_partitions[] = { { - name: "boot firmware", - size: 0x00080000, - offset: 0x00000000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "kernel", - size: 0x00100000, - offset: 0x00080000, - }, { - name: "initrd", - size: 0x00280000, - offset: 0x00180000, - }, { - name: "initrd-test", - size: 0x03C00000, - offset: 0x00400000, + .name = "boot firmware", + .size = 0x00080000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "kernel", + .size = 0x00100000, + .offset = 0x00080000, + }, { + .name = "initrd", + .size = 0x00280000, + .offset = 0x00180000, + }, { + .name = "initrd-test", + .size = 0x03C00000, + .offset = 0x00400000, } }; #endif #ifdef CONFIG_SA1100_PT_SYSTEM3 /* erase size is 0x40000 == 256k partitions have to have this boundary */ -#define SYSTEM3_FLASH_SIZE 0x01000000 static struct mtd_partition system3_partitions[] = { { - name: "BLOB", - size: 0x00040000, - offset: 0x00000000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "config", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - }, { - name: "kernel", - size: 0x00100000, - offset: MTDPART_OFS_APPEND, - }, { - name: "root", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + .name = "BLOB", + .size = 0x00040000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "config", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "kernel", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "root", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_SHANNON -#define SHANNON_FLASH_SIZE 0x00400000 static struct mtd_partition shannon_partitions[] = { { - name: "BLOB boot loader", - offset: 0, - size: 0x20000 + .name = "BLOB boot loader", + .offset = 0, + .size = 0x20000 }, { - name: "kernel", - offset: MTDPART_OFS_APPEND, - size: 0xe0000 + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 0xe0000 }, { - name: "initrd", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + .name = "initrd", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL } }; #endif #ifdef CONFIG_SA1100_SHERMAN -#define SHERMAN_FLASH_SIZE 0x02000000 static struct mtd_partition sherman_partitions[] = { { - size: 0x50000, - offset: 0, + .size = 0x50000, + .offset = 0, }, { - size: 0x70000, - offset: MTDPART_OFS_APPEND, + .size = 0x70000, + .offset = MTDPART_OFS_APPEND, }, { - size: 0x600000, - offset: MTDPART_OFS_APPEND, + .size = 0x600000, + .offset = MTDPART_OFS_APPEND, }, { - size: 0xA0000, - offset: MTDPART_OFS_APPEND, + .size = 0xA0000, + .offset = MTDPART_OFS_APPEND, } }; #endif #ifdef CONFIG_SA1100_SIMPAD -#define SIMPAD_FLASH_SIZE 0x02000000 static struct mtd_partition simpad_partitions[] = { { - name: "SIMpad boot firmware", - size: 0x00080000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "SIMpad kernel", - size: 0x00100000, - offset: 0x00080000, + .name = "SIMpad boot firmware", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "SIMpad kernel", + .size = 0x00100000, + .offset = 0x00080000, }, { #ifdef CONFIG_JFFS2_FS - name: "SIMpad root jffs2", - size: MTDPART_SIZ_FULL, - offset: 0x00180000, + .name = "SIMpad root jffs2", + .size = MTDPART_SIZ_FULL, + .offset = 0x00180000, #else - name: "SIMpad initrd", - size: 0x00300000, - offset: 0x00180000, - }, { - name: "SIMpad root cramfs", - size: 0x00300000, - offset: 0x00480000, - }, { - name: "SIMpad usr cramfs", - size: 0x005c0000, - offset: 0x00780000, - }, { - name: "SIMpad usr local", - size: MTDPART_SIZ_FULL, - offset: 0x00d40000, + .name = "SIMpad initrd", + .size = 0x00300000, + .offset = 0x00180000, + }, { + .name = "SIMpad root cramfs", + .size = 0x00300000, + .offset = 0x00480000, + }, { + .name = "SIMpad usr cramfs", + .size = 0x005c0000, + .offset = 0x00780000, + }, { + .name = "SIMpad usr local", + .size = MTDPART_SIZ_FULL, + .offset = 0x00d40000, #endif } }; #endif /* CONFIG_SA1100_SIMPAD */ -#ifdef CONFIG_SA1100_SIMPUTER -#define SIMPUTER_FLASH_SIZE 0x02000000 -static struct mtd_partition simputer_partitions[] = { - { - name: "blob+logo", - offset: 0, - size: 0x00040000 - }, - { - name: "kernel", - offset: MTDPART_OFS_APPEND, - size: 0x000C0000 - }, - { - name: "/(cramfs)", - offset: MTDPART_OFS_APPEND, - size: 0x00200000 - }, - { - name: "/usr/local(jffs2)", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL /* expand till the end */ - } -}; -#endif - #ifdef CONFIG_SA1100_STORK -#define STORK_FLASH_SIZE 0x02000000 static struct mtd_partition stork_partitions[] = { { - name: "STORK boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, { - name: "STORK params", - size: 0x00040000, - offset: 0x00040000, - }, { - name: "STORK kernel", - size: 0x00100000, - offset: 0x00080000, + .name = "STORK boot firmware", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "STORK params", + .size = 0x00040000, + .offset = 0x00040000, + }, { + .name = "STORK kernel", + .size = 0x00100000, + .offset = 0x00080000, }, { #ifdef CONFIG_JFFS2_FS - name: "STORK root jffs2", - offset: 0x00180000, - size: MTDPART_SIZ_FULL, + .name = "STORK root jffs2", + .offset = 0x00180000, + .size = MTDPART_SIZ_FULL, #else - name: "STORK initrd", - size: 0x00100000, - offset: 0x00180000, - }, { - name: "STORK root cramfs", - size: 0x00300000, - offset: 0x00280000, - }, { - name: "STORK usr cramfs", - size: 0x00800000, - offset: 0x00580000, - }, { - name: "STORK usr local", - offset: 0x00d80000, - size: MTDPART_SIZ_FULL, + .name = "STORK initrd", + .size = 0x00100000, + .offset = 0x00180000, + }, { + .name = "STORK root cramfs", + .size = 0x00300000, + .offset = 0x00280000, + }, { + .name = "STORK usr cramfs", + .size = 0x00800000, + .offset = 0x00580000, + }, { + .name = "STORK usr local", + .offset = 0x00d80000, + .size = MTDPART_SIZ_FULL, #endif } }; #endif +#ifdef CONFIG_SA1100_TRIZEPS +static struct mtd_partition trizeps_partitions[] = { + { + .name = "Bootloader", + .size = 0x00100000, + .offset = 0, + }, { + .name = "Kernel", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "root", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; +#endif + #ifdef CONFIG_SA1100_YOPY -#define YOPY_FLASH_SIZE 0x08000000 static struct mtd_partition yopy_partitions[] = { { - name: "boot firmware", - size: 0x00040000, - offset: 0x00000000, - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "boot firmware", + .size = 0x00040000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "kernel", - size: 0x00080000, - offset: 0x00080000, + .name = "kernel", + .size = 0x00080000, + .offset = 0x00080000, }, { - name: "initrd", - size: 0x00300000, - offset: 0x00100000, + .name = "initrd", + .size = 0x00300000, + .offset = 0x00100000, }, { - name: "root", - size: 0x01000000, - offset: 0x00400000, + .name = "root", + .size = 0x01000000, + .offset = 0x00400000, } }; #endif -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); - -static struct mtd_partition *parsed_parts; -static struct mtd_info *mymtd; - -int __init sa1100_mtd_init(void) +static int __init sa1100_static_partitions(struct mtd_partition **parts) { - struct mtd_partition *parts; - int nb_parts = 0, ret; - int parsed_nr_parts = 0; - const char *part_type; - unsigned long base = -1UL; + int nb_parts = 0; - /* Default flash buswidth */ - sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4; - - /* - * Static partition definition selection - */ - part_type = "static"; - -#ifdef CONFIG_SA1100_ADSAGC - if (machine_is_adsagc()) { - parts = adsagc_partitions; - nb_parts = ARRAY_SIZE(adsagc_partitions); - sa1100_map.size = ADSAGC_FLASH_SIZE; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; - } -#endif #ifdef CONFIG_SA1100_ADSBITSY if (machine_is_adsbitsy()) { - parts = adsbitsy_partitions; - nb_parts = ARRAY_SIZE(adsbitsy_partitions); - sa1100_map.size = ADSBITSY_FLASH_SIZE; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; - } -#endif -#ifdef CONFIG_SA1100_ADSBITSYPLUS - if (machine_is_adsbitsyplus()) { - parts = adsbitsyplus_partitions; - nb_parts = ARRAY_SIZE(adsbitsyplus_partitions); - sa1100_map.size = ADSBITSYPLUS_FLASH_SIZE; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; + *parts = adsbitsy_partitions; + nb_parts = ARRAY_SIZE(adsbitsy_partitions); } #endif #ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) { - parts = assabet_partitions; - nb_parts = ARRAY_SIZE(assabet_partitions); - sa1100_map.size = ASSABET_FLASH_SIZE; + *parts = assabet_partitions; + nb_parts = ARRAY_SIZE(assabet_partitions); } #endif #ifdef CONFIG_SA1100_BADGE4 if (machine_is_badge4()) { - parts = badge4_partitions; - nb_parts = ARRAY_SIZE(badge4_partitions); - sa1100_map.size = BADGE4_FLASH_SIZE; + *parts = badge4_partitions; + nb_parts = ARRAY_SIZE(badge4_partitions); } #endif #ifdef CONFIG_SA1100_CERF if (machine_is_cerf()) { - parts = cerf_partitions; - nb_parts = ARRAY_SIZE(cerf_partitions); - sa1100_map.size = CERF_FLASH_SIZE; + *parts = cerf_partitions; + nb_parts = ARRAY_SIZE(cerf_partitions); } #endif #ifdef CONFIG_SA1100_CONSUS if (machine_is_consus()) { - parts = consus_partitions; - nb_parts = ARRAY_SIZE(consus_partitions); - sa1100_map.size = CONSUS_FLASH_SIZE; + *parts = consus_partitions; + nb_parts = ARRAY_SIZE(consus_partitions); } #endif #ifdef CONFIG_SA1100_FLEXANET if (machine_is_flexanet()) { - parts = flexanet_partitions; - nb_parts = ARRAY_SIZE(flexanet_partitions); - sa1100_map.size = FLEXANET_FLASH_SIZE; + *parts = flexanet_partitions; + nb_parts = ARRAY_SIZE(flexanet_partitions); } #endif #ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) { - parts = freebird_partitions; - nb_parts = ARRAY_SIZE(freebird_partitions); - sa1100_map.size = FREEBIRD_FLASH_SIZE; + *parts = freebird_partitions; + nb_parts = ARRAY_SIZE(freebird_partitions); } #endif #ifdef CONFIG_SA1100_FRODO if (machine_is_frodo()) { - parts = frodo_partitions; - nb_parts = ARRAY_SIZE(frodo_partitions); - sa1100_map.size = FRODO_FLASH_SIZE; - base = 0x00000000; + *parts = frodo_partitions; + nb_parts = ARRAY_SIZE(frodo_partitions); } -#endif +#endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT if (machine_is_graphicsclient()) { - parts = graphicsclient_partitions; - nb_parts = ARRAY_SIZE(graphicsclient_partitions); - sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; + *parts = graphicsclient_partitions; + nb_parts = ARRAY_SIZE(graphicsclient_partitions); } #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER if (machine_is_graphicsmaster()) { - parts = graphicsmaster_partitions; - nb_parts = ARRAY_SIZE(graphicsmaster_partitions); - sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; + *parts = graphicsmaster_partitions; + nb_parts = ARRAY_SIZE(graphicsmaster_partitions); } #endif -#ifdef CONFIG_SA1100_H3600 - if (machine_is_h3600()) { - parts = h3600_partitions; - nb_parts = ARRAY_SIZE(h3600_partitions); - sa1100_map.size = H3600_FLASH_SIZE; - sa1100_map.set_vpp = h3600_set_vpp; +#ifdef CONFIG_SA1100_H3XXX + if (machine_is_h3xxx()) { + *parts = h3xxx_partitions; + nb_parts = ARRAY_SIZE(h3xxx_partitions); } #endif #ifdef CONFIG_SA1100_HACKKIT if (machine_is_hackkit()) { - parts = hackkit_partitions; + *parts = hackkit_partitions; nb_parts = ARRAY_SIZE(hackkit_partitions); - sa1100_map.size = HACKKIT_FLASH_SIZE; } #endif #ifdef CONFIG_SA1100_HUW_WEBPANEL if (machine_is_huw_webpanel()) { - parts = huw_webpanel_partitions; - nb_parts = ARRAY_SIZE(huw_webpanel_partitions); - sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE; + *parts = huw_webpanel_partitions; + nb_parts = ARRAY_SIZE(huw_webpanel_partitions); } #endif #ifdef CONFIG_SA1100_JORNADA720 if (machine_is_jornada720()) { - parts = jornada720_partitions; - nb_parts = ARRAY_SIZE(jornada720_partitions); - sa1100_map.size = JORNADA720_FLASH_SIZE; - sa1100_map.set_vpp = jornada720_set_vpp; - } -#endif -#ifdef CONFIG_SA1100_NANOENGINE - if (machine_is_nanoengine()) { - parts = nanoengine_partitions; - nb_parts = ARRAY_SIZE(nanoengine_partitions); - sa1100_map.size = NANOENGINE_FLASH_SIZE; + *parts = jornada720_partitions; + nb_parts = ARRAY_SIZE(jornada720_partitions); } #endif #ifdef CONFIG_SA1100_PANGOLIN if (machine_is_pangolin()) { - parts = pangolin_partitions; - nb_parts = ARRAY_SIZE(pangolin_partitions); - sa1100_map.size = PANGOLIN_FLASH_SIZE; + *parts = pangolin_partitions; + nb_parts = ARRAY_SIZE(pangolin_partitions); } #endif #ifdef CONFIG_SA1100_PT_SYSTEM3 if (machine_is_pt_system3()) { - parts = system3_partitions; - nb_parts = ARRAY_SIZE(system3_partitions); - sa1100_map.size = SYSTEM3_FLASH_SIZE; + *parts = system3_partitions; + nb_parts = ARRAY_SIZE(system3_partitions); } #endif #ifdef CONFIG_SA1100_SHANNON if (machine_is_shannon()) { - parts = shannon_partitions; - nb_parts = ARRAY_SIZE(shannon_partitions); - sa1100_map.size = SHANNON_FLASH_SIZE; + *parts = shannon_partitions; + nb_parts = ARRAY_SIZE(shannon_partitions); } #endif #ifdef CONFIG_SA1100_SHERMAN if (machine_is_sherman()) { - parts = sherman_partitions; - nb_parts = ARRAY_SIZE(sherman_partitions); - sa1100_map.size = SHERMAN_FLASH_SIZE; + *parts = sherman_partitions; + nb_parts = ARRAY_SIZE(sherman_partitions); } #endif #ifdef CONFIG_SA1100_SIMPAD if (machine_is_simpad()) { - parts = simpad_partitions; - nb_parts = ARRAY_SIZE(simpad_partitions); - sa1100_map.size = SIMPAD_FLASH_SIZE; - } -#endif -#ifdef CONFIG_SA1100_SIMPUTER - if (machine_is_simputer()) { - parts = simputer_partitions; - nb_parts = ARRAY_SIZE(simputer_partitions); - sa1100_map.size = SIMPUTER_FLASH_SIZE; + *parts = simpad_partitions; + nb_parts = ARRAY_SIZE(simpad_partitions); } #endif #ifdef CONFIG_SA1100_STORK if (machine_is_stork()) { - parts = stork_partitions; - nb_parts = ARRAY_SIZE(stork_partitions); - sa1100_map.size = STORK_FLASH_SIZE; + *parts = stork_partitions; + nb_parts = ARRAY_SIZE(stork_partitions); + } +#endif +#ifdef CONFIG_SA1100_TRIZEPS + if (machine_is_trizeps()) { + *parts = trizeps_partitions; + nb_parts = ARRAY_SIZE(trizeps_partitions); } #endif #ifdef CONFIG_SA1100_YOPY if (machine_is_yopy()) { - parts = yopy_partitions; - nb_parts = ARRAY_SIZE(yopy_partitions); - sa1100_map.size = YOPY_FLASH_SIZE; + *parts = yopy_partitions; + nb_parts = ARRAY_SIZE(yopy_partitions); } #endif + return nb_parts; +} +#endif + +struct sa_info { + unsigned long base; + unsigned long size; + int width; + void *vbase; + void (*set_vpp)(struct map_info *, int); + struct map_info *map; + struct mtd_info *mtd; + struct resource *res; +}; + +#define NR_SUBMTD 4 + +static struct sa_info info[NR_SUBMTD]; + +static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd) +{ + struct mtd_info *subdev[nr]; + struct map_info *maps; + int i, found = 0, ret = 0; + /* - * For simple flash devices, use ioremap to map the flash. + * Allocate the map_info structs in one go. */ - if (base != (unsigned long)-1) { - if (!request_mem_region(base, sa1100_map.size, "flash")) - return -EBUSY; - sa1100_map.map_priv_2 = base; - sa1100_map.map_priv_1 = (unsigned long) - ioremap(base, sa1100_map.size); - ret = -ENOMEM; - if (!sa1100_map.map_priv_1) - goto out_err; - } + maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); + if (!maps) + return -ENOMEM; + + memset(maps, 0, sizeof(struct map_info) * nr); /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. + * Claim and then map the memory regions. */ - printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); - mymtd = do_map_probe("jedec_probe", &sa1100_map); - if (!mymtd) - mymtd = do_map_probe("cfi_probe", &sa1100_map); - ret = -ENXIO; - if (!mymtd) - goto out_err; - mymtd->module = THIS_MODULE; + for (i = 0; i < nr; i++) { + if (sa[i].base == (unsigned long)-1) + break; + + sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash"); + if (!sa[i].res) { + ret = -EBUSY; + break; + } + + sa[i].map = maps + i; + + sa[i].vbase = ioremap(sa[i].base, sa[i].size); + if (!sa[i].vbase) { + ret = -ENOMEM; + break; + } + + sa[i].map->virt = (unsigned long)sa[i].vbase; + sa[i].map->phys = sa[i].base; + sa[i].map->set_vpp = sa[i].set_vpp; + sa[i].map->buswidth = sa[i].width; + sa[i].map->size = sa[i].size; + + simple_map_init(sa[i].map); + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + sa[i].mtd = do_map_probe("cfi_probe", sa[i].map); + if (sa[i].mtd == NULL) { + ret = -ENXIO; + break; + } + sa[i].mtd->owner = THIS_MODULE; + subdev[i] = sa[i].mtd; + + printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " + "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20, + sa[i].width * 8); + found += 1; + } /* - * Dynamic partition selection stuff (might override the static ones) + * ENXIO is special. It means we didn't find a chip when + * we probed. We need to tear down the mapping, free the + * resource and mark it as such. */ -#ifdef CONFIG_MTD_REDBOOT_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_redboot_partitions(mymtd, &parsed_parts); - - if (ret > 0) { - part_type = "RedBoot"; - parsed_nr_parts = ret; - } + if (ret == -ENXIO) { + iounmap(sa[i].vbase); + sa[i].vbase = NULL; + release_resource(sa[i].res); + sa[i].res = NULL; } + + /* + * If we found one device, don't bother with concat support. + * If we found multiple devices, use concat if we have it + * available, otherwise fail. + */ + if (ret == 0 || ret == -ENXIO) { + if (found == 1) { + *rmtd = subdev[0]; + ret = 0; + } else if (found > 1) { + /* + * We detected multiple devices. Concatenate + * them together. + */ +#ifdef CONFIG_MTD_CONCAT + *rmtd = mtd_concat_create(subdev, found, + "sa1100 flash"); + if (*rmtd == NULL) + ret = -ENXIO; +#else + printk(KERN_ERR "SA1100 flash: multiple devices " + "found but MTD concat support disabled.\n"); + ret = -ENXIO; #endif -#ifdef CONFIG_MTD_CMDLINE_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100"); - if (ret > 0) { - part_type = "Command Line"; - parsed_nr_parts = ret; } } + + /* + * If we failed, clean up. + */ + if (ret) { + do { + if (sa[i].mtd) + map_destroy(sa[i].mtd); + if (sa[i].vbase) + iounmap(sa[i].vbase); + if (sa[i].res) + release_resource(sa[i].res); + } while (i--); + + kfree(maps); + } + + return ret; +} + +static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd) +{ + int i; + + del_mtd_partitions(mtd); + +#ifdef CONFIG_MTD_CONCAT + if (mtd != sa[0].mtd) + mtd_concat_destroy(mtd); #endif - if (parsed_nr_parts > 0) { - parts = parsed_parts; - nb_parts = parsed_nr_parts; + for (i = NR_SUBMTD; i >= 0; i--) { + if (sa[i].mtd) + map_destroy(sa[i].mtd); + if (sa[i].vbase) + iounmap(sa[i].vbase); + if (sa[i].res) + release_resource(sa[i].res); } + kfree(sa[0].map); +} - if (nb_parts == 0) { - printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n"); - add_mtd_device(mymtd); - } else { - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - add_mtd_partitions(mymtd, parts, nb_parts); +/* + * A Thought: can we automatically detect the flash? + * - Check to see if the region is busy (yes -> failure) + * - Is the MSC setup for flash (no -> failure) + * - Probe for flash + */ + +static struct map_info sa1100_probe_map __initdata = { + .name = "SA1100-flash", +}; + +static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys) +{ + struct mtd_info *mtd; + + printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ", + phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32); + + if (check_mem_region(phys, 0x08000000)) { + printk("busy\n"); + return; + } + + if ((msc & 3) == 1) { + printk("wrong type\n"); + return; + } + + sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4; + sa1100_probe_map.size = SZ_1M; + sa1100_probe_map.phys = phys; + sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M); + if (sa1100_probe_map.virt == 0) + goto fail; + simple_map_init(&sa1100_probe_map); + + /* Shame cfi_probe blurts out kernel messages... */ + mtd = do_map_probe("cfi_probe", &sa1100_probe_map); + if (mtd) + map_destroy(mtd); + iounmap((void *)sa1100_probe_map.virt); + + if (!mtd) + goto fail; + + printk("pass\n"); + return; + + fail: + printk("failed\n"); +} + +static void __init sa1100_probe_flash(void) +{ + printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n"); + sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS); + sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS); + sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS); + sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS); + sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS); + sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS); + printk(KERN_INFO "-- SA11xx Flash probe complete.\n"); +} + +static int __init sa1100_locate_flash(void) +{ + int i, nr = -ENODEV; + + sa1100_probe_flash(); + + if (machine_is_adsbitsy()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_assabet()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + info[1].base = SA1100_CS1_PHYS; /* neponset */ + info[1].size = SZ_32M; + nr = 2; + } + if (machine_is_badge4()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_64M; + nr = 1; + } + if (machine_is_cerf()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_consus()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_flexanet()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_freebird()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_frodo()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_graphicsclient()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_graphicsmaster()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_h3xxx()) { + info[0].set_vpp = h3xxx_set_vpp; + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_huw_webpanel()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_itsy()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_jornada720()) { + info[0].set_vpp = jornada720_set_vpp; + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_nanoengine()) { + info[0].base = SA1100_CS0_PHYS; + info[1].size = SZ_32M; + nr = 1; + } + if (machine_is_pangolin()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_64M; + nr = 1; + } + if (machine_is_pfs168()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_pleb()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_4M; + info[1].base = SA1100_CS1_PHYS; + info[1].size = SZ_4M; + nr = 2; } - return 0; + if (machine_is_pt_system3()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_shannon()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_4M; + nr = 1; + } + if (machine_is_sherman()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_simpad()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_stork()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_trizeps()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_victor()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_2M; + nr = 1; + } + if (machine_is_yopy()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_64M; + info[1].base = SA1100_CS1_PHYS; + info[1].size = SZ_64M; + nr = 2; + } + + if (nr < 0) + return nr; - out_err: - if (sa1100_map.map_priv_2 != -1) { - iounmap((void *)sa1100_map.map_priv_1); - release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); + /* + * Retrieve the buswidth from the MSC registers. + * We currently only implement CS0 and CS1 here. + */ + for (i = 0; i < nr; i++) { + switch (info[i].base) { + default: + printk(KERN_WARNING "SA1100 flash: unknown base address " + "0x%08lx, assuming CS0\n", info[i].base); + case SA1100_CS0_PHYS: + info[i].width = (MSC0 & MSC_RBW) ? 2 : 4; + break; + + case SA1100_CS1_PHYS: + info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4; + break; + } + } + + return nr; +} + +static struct mtd_partition *parsed_parts; +const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; + +static void __init sa1100_locate_partitions(struct mtd_info *mtd) +{ + const char *part_type = NULL; + int nr_parts = 0; + + do { + /* + * Partition selection stuff. + */ +#ifdef CONFIG_MTD_PARTITIONS + nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0); + if (nr_parts > 0) { + part_type = "dynamic"; + break; + } +#endif +#ifdef CONFIG_MTD_SA1100_STATICMAP + nr_parts = sa1100_static_partitions(&parsed_parts); + if (nr_parts > 0) { + part_type = "static"; + break; + } +#endif + } while (0); + + if (nr_parts == 0) { + printk(KERN_NOTICE "SA1100 flash: no partition info " + "available, registering whole flash\n"); + add_mtd_device(mtd); + } else { + printk(KERN_NOTICE "SA1100 flash: using %s partition " + "definition\n", part_type); + add_mtd_partitions(mtd, parsed_parts, nr_parts); } + + /* Always succeeds. */ +} + +static void __exit sa1100_destroy_partitions(void) +{ + if (parsed_parts) + kfree(parsed_parts); +} + +static struct mtd_info *mymtd; + +static int __init sa1100_mtd_init(void) +{ + int ret; + int nr; + + nr = sa1100_locate_flash(); + if (nr < 0) + return nr; + + ret = sa1100_setup_mtd(info, nr, &mymtd); + if (ret == 0) + sa1100_locate_partitions(mymtd); + return ret; } static void __exit sa1100_mtd_cleanup(void) { - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - if (parsed_parts) - kfree(parsed_parts); - } - if (sa1100_map.map_priv_2 != -1) { - iounmap((void *)sa1100_map.map_priv_1); - release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); - } + sa1100_destroy_mtd(info, mymtd); + sa1100_destroy_partitions(); } module_init(sa1100_mtd_init); diff -Nru a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/sbc8240.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,417 @@ +/* + * Handle mapping of the flash memory access routines on the SBC8240 board. + * + * Carolyn Smith, Tektronix, Inc. + * + * This code is GPLed + * + * $Id: sbc8240.c,v 1.2 2003/09/30 19:37:00 thayne Exp $ + * + */ + +/* + * The SBC8240 has 2 flash banks. + * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors. + * It contains the U-Boot code (7 sectors) and the environment (1 sector). + * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector, + * 2 x 8 KiB sectors, 1 x 16 KiB sectors. + * Both parts are JEDEC compatible. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_MTD_PARTITIONS +#include +#endif + +#define DEBUG + +#ifdef DEBUG +# define debugk(fmt,args...) printk(fmt ,##args) +#else +# define debugk(fmt,args...) +#endif + + +#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */ +#define WINDOW_SIZE0 0x00080000 +#define BUSWIDTH0 1 + +#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */ +#define WINDOW_SIZE1 0x00400000 +#define BUSWIDTH1 8 + +#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */ +#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */ + + +static __u8 sbc8240_read8 (struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 sbc8240_read16 (struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 sbc8240_read32 (struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +unsigned long long result64; + +static __u64 sbc8240_read64 (struct map_info *map, unsigned long ofs) +{ + unsigned long flags, msr, saved_msr; + volatile long saved_fr[2]; + volatile unsigned long long result; + volatile unsigned long *p; + + save_flags(flags); + cli(); + + /* turn off floating point unavailable exceptions */ + + __asm__ __volatile__ ( + "mfmsr %0" + : "=r" (msr) :); + + saved_msr = msr; + msr |= MSR_FP; + msr &= ~(MSR_FE0 | MSR_FE1); + + __asm__ __volatile__ ( + "mtmsr %0\n" + "isync\n" + : : "r" (msr)); + + /* read the data via a floating point register */ + + ofs = map->map_priv_1 + ofs; + p = (unsigned long *) &result64; + + __asm__ __volatile__ ( + "lfd 1,0(%1)\n" + "stfd 1,0(%0)\n" + : : "r" (p), "r" (ofs) + ); + + /* restore state */ + + __asm__ __volatile__ ( + "mtmsr %0\n" + "isync\n" + : : "r" (saved_msr)); + + restore_flags(flags); + + p = (unsigned long *) &result64; + debugk("sbc8240_read64 ofs 0x%x result 0x%08x%08x\n", ofs, *p, *(p+1)); + + return result64; +} + +static void sbc8240_copy_from (struct map_info *map, + void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio (to, (void *) (map->map_priv_1 + from), len); +} + +static void sbc8240_write8 (struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void sbc8240_write16 (struct map_info *map, __u16 d, + unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void sbc8240_write32 (struct map_info *map, __u32 d, + unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void sbc8240_write64 (struct map_info *map, __u64 data, + unsigned long adr) +{ + unsigned long long tmp; + unsigned long flags, msr, saved_msr, *p; + volatile long saved_fr[2]; + + save_flags(flags); + cli(); + + /* turn off floating point unavailable exceptions */ + + __asm__ __volatile__ ( + "mfmsr %0" + : "=r" (msr) :); + + saved_msr = msr; + msr |= MSR_FP; + msr &= ~(MSR_FE0 | MSR_FE1); + + __asm__ __volatile__ ( + "mtmsr %0\n" + "isync\n" + : : "r" (msr)); + + + /* write the data via a floating point register */ + + tmp = data; + p = (unsigned long *) &tmp; + adr = map->map_priv_1 + adr; + debugk("sbc8240_write64 adr 0x%x data 0x%08x%08x\n", adr, *p, *(p+1)); + + __asm__ __volatile__ ( + "stfd 1,0(%2)\n" + "lfd 1,0(%0)\n" + "stfd 1,0(%1)\n" + "lfd 1,0(%2)\n" + : : "r" (p), "r" (adr), "b" (saved_fr) + ); + + /* restore state */ + + __asm__ __volatile__ ( + "mtmsr %0\n" + "isync\n" + : : "r" (saved_msr)); + + restore_flags(flags); +} + +static void sbc8240_copy_to (struct map_info *map, + unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio ((void *) (map->map_priv_1 + to), from, len); +} + +static struct map_info sbc8240_map[2] = { + { + .name = "sbc8240 Flash Bank #0", + .size = WINDOW_SIZE0, + .buswidth = BUSWIDTH0, + .read8 = sbc8240_read8, + .read16 = sbc8240_read16, + .read32 = sbc8240_read32, + .read64 = sbc8240_read64, + .copy_from = sbc8240_copy_from, + .write8 = sbc8240_write8, + .write16 = sbc8240_write16, + .write32 = sbc8240_write32, + .write64 = sbc8240_write64, + .copy_to = sbc8240_copy_to + }, + { + .name = "sbc8240 Flash Bank #1", + .size = WINDOW_SIZE1, + .buswidth = BUSWIDTH1, + .read8 = sbc8240_read8, + .read16 = sbc8240_read16, + .read32 = sbc8240_read32, + .read64 = sbc8240_read64, + .copy_from = sbc8240_copy_from, + .write8 = sbc8240_write8, + .write16 = sbc8240_write16, + .write32 = sbc8240_write32, + .write64 = sbc8240_write64, + .copy_to = sbc8240_copy_to + } +}; + +#define NUM_FLASH_BANKS (sizeof(sbc8240_map) / sizeof(struct map_info)) + +/* + * The following defines the partition layout of SBC8240 boards. + * + * See include/linux/mtd/partitions.h for definition of the + * mtd_partition structure. + * + * The *_max_flash_size is the maximum possible mapped flash size + * which is not necessarily the actual flash size. It must correspond + * to the value specified in the mapping definition defined by the + * "struct map_desc *_io_desc" for the corresponding machine. + */ + +#ifdef CONFIG_MTD_PARTITIONS + +static struct mtd_partition sbc8240_uboot_partitions [] = { + /* Bank 0 */ + { + .name = "U-boot", /* U-Boot Firmware */ + .offset = 0, + .size = 0x00070000, /* 7 x 64 KiB sectors */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "environment", /* U-Boot environment */ + .offset = 0x00070000, + .size = 0x00010000, /* 1 x 64 KiB sector */ + }, +}; + +static struct mtd_partition sbc8240_fs_partitions [] = { + { + .name = "jffs", /* JFFS filesystem */ + .offset = 0, + .size = 0x003C0000, /* 4 * 15 * 64KiB */ + }, + { + .name = "tmp32", + .offset = 0x003C0000, + .size = 0x00020000, /* 4 * 32KiB */ + }, + { + .name = "tmp8a", + .offset = 0x003E0000, + .size = 0x00008000, /* 4 * 8KiB */ + }, + { + .name = "tmp8b", + .offset = 0x003E8000, + .size = 0x00008000, /* 4 * 8KiB */ + }, + { + .name = "tmp16", + .offset = 0x003F0000, + .size = 0x00010000, /* 4 * 16KiB */ + } +}; + +#define NB_OF(x) (sizeof (x) / sizeof (x[0])) + +/* trivial struct to describe partition information */ +struct mtd_part_def +{ + int nums; + unsigned char *type; + struct mtd_partition* mtd_part; +}; + +static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS]; +static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS]; + + +#endif /* CONFIG_MTD_PARTITIONS */ + + +int __init init_sbc8240_mtd (void) +{ + static struct _cjs { + u_long addr; + u_long size; + } pt[NUM_FLASH_BANKS] = { + { + .addr = WINDOW_ADDR0, + .size = WINDOW_SIZE0 + }, + { + .addr = WINDOW_ADDR1, + .size = WINDOW_SIZE1 + }, + }; + + int devicesfound = 0; + int i; + + for (i = 0; i < NUM_FLASH_BANKS; i++) { + printk (KERN_NOTICE MSG_PREFIX + "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr); + + sbc8240_map[i].map_priv_1 = + (unsigned long) ioremap (pt[i].addr, pt[i].size); + if (!sbc8240_map[i].map_priv_1) { + printk (MSG_PREFIX "failed to ioremap\n"); + return -EIO; + } + + sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]); + + if (sbc8240_mtd[i]) { + sbc8240_mtd[i]->module = THIS_MODULE; + devicesfound++; + } + } + + if (!devicesfound) { + printk(KERN_NOTICE MSG_PREFIX + "No suppported flash chips found!\n"); + return -ENXIO; + } + +#ifdef CONFIG_MTD_PARTITIONS + sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions; + sbc8240_part_banks[0].type = "static image"; + sbc8240_part_banks[0].nums = NB_OF(sbc8240_uboot_partitions); + sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions; + sbc8240_part_banks[1].type = "static file system"; + sbc8240_part_banks[1].nums = NB_OF(sbc8240_fs_partitions); + + for (i = 0; i < NUM_FLASH_BANKS; i++) { + + if (!sbc8240_mtd[i]) continue; + if (sbc8240_part_banks[i].nums == 0) { + printk (KERN_NOTICE MSG_PREFIX + "No partition info available, registering whole device\n"); + add_mtd_device(sbc8240_mtd[i]); + } else { + printk (KERN_NOTICE MSG_PREFIX + "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); + add_mtd_partitions (sbc8240_mtd[i], + sbc8240_part_banks[i].mtd_part, + sbc8240_part_banks[i].nums); + } + } +#else + printk(KERN_NOTICE MSG_PREFIX + "Registering %d flash banks at once\n", devicesfound); + + for (i = 0; i < devicesfound; i++) { + add_mtd_device(sbc8240_mtd[i]); + } +#endif /* CONFIG_MTD_PARTITIONS */ + + return devicesfound == 0 ? -ENXIO : 0; +} + +static void __exit cleanup_sbc8240_mtd (void) +{ + int i; + + for (i = 0; i < NUM_FLASH_BANKS; i++) { + if (sbc8240_mtd[i]) { + del_mtd_device (sbc8240_mtd[i]); + map_destroy (sbc8240_mtd[i]); + } + if (sbc8240_map[i].map_priv_1) { + iounmap ((void *) sbc8240_map[i].map_priv_1); + sbc8240_map[i].map_priv_1 = 0; + } + } +} + +module_init (init_sbc8240_mtd); +module_exit (cleanup_sbc8240_mtd); + +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Carolyn Smith "); +MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards"); + diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c --- a/drivers/mtd/maps/sbc_gxx.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/sbc_gxx.c Thu Dec 4 16:24:25 2003 @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.21 2003/01/24 13:40:14 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $ The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. @@ -91,14 +91,14 @@ * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ - { name: "SBC-GXx flash boot partition", - offset: 0, - size: BOOT_PARTITION_SIZE_KiB*1024 }, - { name: "SBC-GXx flash data partition", - offset: BOOT_PARTITION_SIZE_KiB*1024, - size: (DATA_PARTITION_SIZE_KiB)*1024 }, - { name: "SBC-GXx flash application partition", - offset: (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } + { .name = "SBC-GXx flash boot partition", + .offset = 0, + .size = BOOT_PARTITION_SIZE_KiB*1024 }, + { .name = "SBC-GXx flash data partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, + .size = (DATA_PARTITION_SIZE_KiB)*1024 }, + { .name = "SBC-GXx flash application partition", + .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } }; #define NUM_PARTITIONS 3 @@ -203,19 +203,20 @@ } static struct map_info sbc_gxx_map = { - name: "SBC-GXx flash", - size: MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount + .name = "SBC-GXx flash", + .phys = NO_XIP, + .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount of flash so the cfi probe routines find all the chips */ - buswidth: 1, - read8: sbc_gxx_read8, - read16: sbc_gxx_read16, - read32: sbc_gxx_read32, - copy_from: sbc_gxx_copy_from, - write8: sbc_gxx_write8, - write16: sbc_gxx_write16, - write32: sbc_gxx_write32, - copy_to: sbc_gxx_copy_to + .buswidth = 1, + .read8 = sbc_gxx_read8, + .read16 = sbc_gxx_read16, + .read32 = sbc_gxx_read32, + .copy_from = sbc_gxx_copy_from, + .write8 = sbc_gxx_write8, + .write16 = sbc_gxx_write16, + .write32 = sbc_gxx_write32, + .copy_to = sbc_gxx_copy_to }; /* MTD device for all of the flash. */ @@ -234,12 +235,6 @@ int __init init_sbc_gxx(void) { - if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { - printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", - sbc_gxx_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); - return -EAGAIN; - } iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", @@ -247,7 +242,14 @@ return -EIO; } - request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" ); + if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { + printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", + sbc_gxx_map.name, + PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); + iounmap((void *)iomapadr); + return -EAGAIN; + } + printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", sbc_gxx_map.name, @@ -261,7 +263,7 @@ return -ENXIO; } - all_mtd->module=THIS_MODULE; + all_mtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS ); diff -Nru a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c --- a/drivers/mtd/maps/sc520cdp.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/sc520cdp.c Thu Dec 4 16:24:26 2003 @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $ + * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -84,88 +85,25 @@ #define WINDOW_SIZE_1 0x00800000 #define WINDOW_SIZE_2 0x00080000 -static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} static struct map_info sc520cdp_map[] = { { - name: "SC520CDP Flash Bank #0", - size: WINDOW_SIZE_0, - buswidth: 4, - read8: sc520cdp_read8, - read16: sc520cdp_read16, - read32: sc520cdp_read32, - copy_from: sc520cdp_copy_from, - write8: sc520cdp_write8, - write16: sc520cdp_write16, - write32: sc520cdp_write32, - copy_to: sc520cdp_copy_to, - map_priv_2: WINDOW_ADDR_0 + .name = "SC520CDP Flash Bank #0", + .size = WINDOW_SIZE_0, + .buswidth = 4, + .phys = WINDOW_ADDR_0 }, { - name: "SC520CDP Flash Bank #1", - size: WINDOW_SIZE_1, - buswidth: 4, - read8: sc520cdp_read8, - read16: sc520cdp_read16, - read32: sc520cdp_read32, - copy_from: sc520cdp_copy_from, - write8: sc520cdp_write8, - write16: sc520cdp_write16, - write32: sc520cdp_write32, - copy_to: sc520cdp_copy_to, - map_priv_2: WINDOW_ADDR_1 + .name = "SC520CDP Flash Bank #1", + .size = WINDOW_SIZE_1, + .buswidth = 4, + .phys = WINDOW_ADDR_1 }, { - name: "SC520CDP DIL Flash", - size: WINDOW_SIZE_2, - buswidth: 1, - read8: sc520cdp_read8, - read16: sc520cdp_read16, - read32: sc520cdp_read32, - copy_from: sc520cdp_copy_from, - write8: sc520cdp_write8, - write16: sc520cdp_write16, - write32: sc520cdp_write32, - copy_to: sc520cdp_copy_to, - map_priv_2: WINDOW_ADDR_2 + .name = "SC520CDP DIL Flash", + .size = WINDOW_SIZE_2, + .buswidth = 1, + .phys = WINDOW_ADDR_2 }, }; @@ -255,9 +193,9 @@ /* map in SC520's MMCR area */ mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT); if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */ - /* force map_priv_2 fields to BIOS defaults: */ + /* force physical address fields to BIOS defaults: */ for(i = 0; i < NUM_FLASH_BANKS; i++) - sc520cdp_map[i].map_priv_2 = par_table[i].default_address; + sc520cdp_map[i].phys = par_table[i].default_address; return; } @@ -282,7 +220,7 @@ sc520cdp_map[i].name); printk(KERN_NOTICE "Trying default address 0x%lx\n", par_table[i].default_address); - sc520cdp_map[i].map_priv_2 = par_table[i].default_address; + sc520cdp_map[i].phys = par_table[i].default_address; } } iounmap((void *)mmcr); @@ -300,13 +238,18 @@ #endif for (i = 0; i < NUM_FLASH_BANKS; i++) { - printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2); - sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size); + printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", + sc520cdp_map[i].size, sc520cdp_map[i].phys); - if (!sc520cdp_map[i].map_priv_1) { + sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); + + if (!sc520cdp_map[i].virt) { printk("Failed to ioremap_nocache\n"); return -EIO; } + + simple_map_init(&sc520cdp_map[i]); + mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); if(!mymtd[i]) mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); @@ -314,11 +257,11 @@ mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); if (mymtd[i]) { - mymtd[i]->module = THIS_MODULE; + mymtd[i]->owner = THIS_MODULE; ++devices_found; } else { - iounmap((void *)sc520cdp_map[i].map_priv_1); + iounmap((void *)sc520cdp_map[i].virt); } } if(devices_found >= 2) { @@ -346,9 +289,9 @@ for (i = 0; i < NUM_FLASH_BANKS; i++) { if (mymtd[i]) map_destroy(mymtd[i]); - if (sc520cdp_map[i].map_priv_1) { - iounmap((void *)sc520cdp_map[i].map_priv_1); - sc520cdp_map[i].map_priv_1 = 0; + if (sc520cdp_map[i].virt) { + iounmap((void *)sc520cdp_map[i].virt); + sc520cdp_map[i].virt = 0; } } } diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c --- a/drivers/mtd/maps/scb2_flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/scb2_flash.c Thu Dec 4 16:24:25 2003 @@ -1,6 +1,6 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $Id: scb2_flash.c,v 1.2 2003/01/24 13:09:56 dwmw2 Exp $ + * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $ * Copyright (C) 2002 Sun Microsystems, Inc. * Tim Hockin * @@ -14,7 +14,7 @@ * try to request it here, but if it fails, we carry on anyway. * * This is how the chip is attached, so said the schematic: - * * a 4 MiB (32 Mb) 16 bit chip + * * a 4 MiB (32 Mib) 16 bit chip * * a 1 MiB memory region * * A20 and A21 pulled up * * D8-D15 ignored @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -60,65 +61,13 @@ #define SCB2_ADDR 0xfff00000 #define SCB2_WINDOW 0x00100000 -static __u8 scb2_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 scb2_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static __u32 scb2_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -static void scb2_copy_from(struct map_info *map, void *to, - unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -static void scb2_copy_to(struct map_info *map, unsigned long to, - const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} static void *scb2_ioaddr; static struct mtd_info *scb2_mtd; struct map_info scb2_map = { - name: "SCB2 BIOS Flash", - size: 0, - buswidth: 1, - read8: scb2_read8, - read16: scb2_read16, - read32: scb2_read32, - copy_from: scb2_copy_from, - write8: scb2_write8, - write16: scb2_write16, - write32: scb2_write32, - copy_to: scb2_copy_to, + .name = "SCB2 BIOS Flash", + .size = 0, + .buswidth = 1, }; static int region_fail; @@ -137,6 +86,8 @@ return -1; } + /* I wasn't here. I didn't see. dwmw2. */ + /* the chip is sometimes bigger than the map - what a waste */ mtd->size = map->size; @@ -211,9 +162,12 @@ return -ENOMEM; } - scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr; + scb2_map.phys = SCB2_ADDR; + scb2_map.virt = (unsigned long)scb2_ioaddr; scb2_map.size = SCB2_WINDOW; + simple_map_init(&scb2_map); + /* try to find a chip */ scb2_mtd = do_map_probe("cfi_probe", &scb2_map); @@ -225,7 +179,7 @@ return -ENODEV; } - scb2_mtd->module = THIS_MODULE; + scb2_mtd->owner = THIS_MODULE; if (scb2_fixup_mtd(scb2_mtd) < 0) { del_mtd_device(scb2_mtd); map_destroy(scb2_mtd); @@ -235,7 +189,7 @@ return -ENODEV; } - printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n", + printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); add_mtd_device(scb2_mtd); @@ -266,19 +220,19 @@ static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = { { - vendor: PCI_VENDOR_ID_SERVERWORKS, - device: PCI_DEVICE_ID_SERVERWORKS_CSB5, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_CSB5, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID }, { 0, } }; static struct pci_driver scb2_flash_driver = { - name: "Intel SCB2 BIOS Flash", - id_table: scb2_flash_pci_ids, - probe: scb2_flash_probe, - remove: __devexit_p(scb2_flash_remove), + .name = "Intel SCB2 BIOS Flash", + .id_table = scb2_flash_pci_ids, + .probe = scb2_flash_probe, + .remove = __devexit_p(scb2_flash_remove), }; static int __init diff -Nru a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c --- a/drivers/mtd/maps/scx200_docflash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/scx200_docflash.c Thu Dec 4 16:24:25 2003 @@ -2,7 +2,7 @@ Copyright (c) 2001,2002 Christer Weinigel - $Id: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $ + $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $ National Semiconductor SCx200 flash mapped with DOCCS */ @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -75,46 +76,9 @@ #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) #endif -static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} static struct map_info scx200_docflash_map = { .name = "NatSemi SCx200 DOCCS Flash", - .read8 = scx200_docflash_read8, - .read16 = scx200_docflash_read16, - .copy_from = scx200_docflash_copy_from, - .write8 = scx200_docflash_write8, - .write16 = scx200_docflash_write16, - .copy_to = scx200_docflash_copy_to }; int __init init_scx200_docflash(void) @@ -213,8 +177,11 @@ else scx200_docflash_map.buswidth = 2; - scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); - if (!scx200_docflash_map.map_priv_1) { + simple_map_init(&scx200_docflash_map); + + scx200_docflash_map.phys = docmem.start; + scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); + if (!scx200_docflash_map.virt) { printk(KERN_ERR NAME ": failed to ioremap the flash\n"); release_resource(&docmem); return -EIO; @@ -223,7 +190,7 @@ mymtd = do_map_probe(flashtype, &scx200_docflash_map); if (!mymtd) { printk(KERN_ERR NAME ": unable to detect flash\n"); - iounmap((void *)scx200_docflash_map.map_priv_1); + iounmap((void *)scx200_docflash_map.virt); release_resource(&docmem); return -ENXIO; } @@ -231,7 +198,7 @@ if (size < mymtd->size) printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n"); - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; #if PARTITION partition_info[3].offset = mymtd->size-partition_info[3].size; @@ -253,8 +220,8 @@ #endif map_destroy(mymtd); } - if (scx200_docflash_map.map_priv_1) { - iounmap((void *)scx200_docflash_map.map_priv_1); + if (scx200_docflash_map.virt) { + iounmap((void *)scx200_docflash_map.virt); release_resource(&docmem); } } diff -Nru a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c --- a/drivers/mtd/maps/solutionengine.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/solutionengine.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $ + * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,60 +19,39 @@ #include -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); - -__u32 soleng_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void soleng_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - - static struct mtd_info *flash_mtd; static struct mtd_info *eprom_mtd; static struct mtd_partition *parsed_parts; struct map_info soleng_eprom_map = { - name: "Solution Engine EPROM", - size: 0x400000, - buswidth: 4, - copy_from: soleng_copy_from, + .name = "Solution Engine EPROM", + .size = 0x400000, + .buswidth = 4, }; struct map_info soleng_flash_map = { - name: "Solution Engine FLASH", - size: 0x400000, - buswidth: 4, - read32: soleng_read32, - copy_from: soleng_copy_from, - write32: soleng_write32, + .name = "Solution Engine FLASH", + .size = 0x400000, + .buswidth = 4, }; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + #ifdef CONFIG_MTD_SUPERH_RESERVE static struct mtd_partition superh_se_partitions[] = { /* Reserved for boot code, read-only */ { - name: "flash_boot", - offset: 0x00000000, - size: CONFIG_MTD_SUPERH_RESERVE, - mask_flags: MTD_WRITEABLE, + .name = "flash_boot", + .offset = 0x00000000, + .size = CONFIG_MTD_SUPERH_RESERVE, + .mask_flags = MTD_WRITEABLE, }, /* All else is writable (e.g. JFFS) */ { - name: "Flash FS", - offset: MTDPART_OFS_NXTBLK, - size: MTDPART_SIZ_FULL, + .name = "Flash FS", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, } }; #endif /* CONFIG_MTD_SUPERH_RESERVE */ @@ -81,16 +61,22 @@ int nr_parts = 0; /* First probe at offset 0 */ - soleng_flash_map.map_priv_1 = P2SEGADDR(0); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000); - + soleng_flash_map.phys = 0; + soleng_flash_map.virt = P2SEGADDR(0); + soleng_eprom_map.phys = 0x01000000; + soleng_eprom_map.virt = P1SEGADDR(0x01000000); + simple_map_init(&soleng_eprom_map); + simple_map_init(&soleng_flash_map); + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Not there. Try swapping */ printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); - soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0); + soleng_flash_map.phys = 0x01000000; + soleng_flash_map.virt = P2SEGADDR(0x01000000); + soleng_eprom_map.phys = 0; + soleng_eprom_map.virt = P1SEGADDR(0); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Eep. */ @@ -99,25 +85,20 @@ } } printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", - soleng_flash_map.map_priv_1 & 0x1fffffff, - soleng_eprom_map.map_priv_1 & 0x1fffffff); - flash_mtd->module = THIS_MODULE; + soleng_flash_map.phys & 0x1fffffff, + soleng_eprom_map.phys & 0x1fffffff); + flash_mtd->owner = THIS_MODULE; eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); if (eprom_mtd) { - eprom_mtd->module = THIS_MODULE; + eprom_mtd->owner = THIS_MODULE; add_mtd_device(eprom_mtd); } -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); - if (nr_parts > 0) - printk(KERN_NOTICE "Found RedBoot partition table.\n"); - else if (nr_parts < 0) - printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); -#endif /* CONFIG_MTD_REDBOOT_PARTS */ + nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); + #if CONFIG_MTD_SUPERH_RESERVE - if (nr_parts == 0) { + if (nr_parts <= 0) { printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", CONFIG_MTD_SUPERH_RESERVE); parsed_parts = superh_se_partitions; diff -Nru a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c --- a/drivers/mtd/maps/sun_uflash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/sun_uflash.c Thu Dec 4 16:24:25 2003 @@ -1,4 +1,4 @@ -/* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $ +/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $ * * sun_uflash - Driver implementation for user-programmable flash * present on many Sun Microsystems SME boardsets. @@ -48,60 +48,11 @@ struct list_head list; }; -__u8 uflash_read8(struct map_info *map, unsigned long ofs) -{ - return(__raw_readb(map->map_priv_1 + ofs)); -} - -__u16 uflash_read16(struct map_info *map, unsigned long ofs) -{ - return(__raw_readw(map->map_priv_1 + ofs)); -} - -__u32 uflash_read32(struct map_info *map, unsigned long ofs) -{ - return(__raw_readl(map->map_priv_1 + ofs)); -} - -void uflash_copy_from(struct map_info *map, void *to, unsigned long from, - ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void uflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); -} - -void uflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); -} - -void uflash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); -} - -void uflash_copy_to(struct map_info *map, unsigned long to, const void *from, - ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} struct map_info uflash_map_templ = { - name: "SUNW,???-????", - size: UFLASH_WINDOW_SIZE, - buswidth: UFLASH_BUSWIDTH, - read8: uflash_read8, - read16: uflash_read16, - read32: uflash_read32, - copy_from: uflash_copy_from, - write8: uflash_write8, - write16: uflash_write16, - write32: uflash_write32, - copy_to: uflash_copy_to + .name = "SUNW,???-????", + .size = UFLASH_WINDOW_SIZE, + .buswidth = UFLASH_BUSWIDTH, }; int uflash_devinit(struct linux_ebus_device* edev) @@ -145,20 +96,22 @@ if(0 != pdev->name && 0 < strlen(pdev->name)) { pdev->map.name = pdev->name; } - - pdev->map.map_priv_1 = + pdev->phys = edev->resource[0].start; + pdev->virt = (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size); - if(0 == pdev->map.map_priv_1) { + if(0 == pdev->map.virt) { printk("%s: failed to map device\n", __FUNCTION__); kfree(pdev->name); kfree(pdev); return(-1); } + simple_map_init(&pdev->map); + /* MTD registration */ pdev->mtd = do_map_probe("cfi_probe", &pdev->map); if(0 == pdev->mtd) { - iounmap((void *)pdev->map.map_priv_1); + iounmap((void *)pdev->map.virt); kfree(pdev->name); kfree(pdev); return(-ENXIO); @@ -166,7 +119,7 @@ list_add(&pdev->list, &device_list); - pdev->mtd->module = THIS_MODULE; + pdev->mtd->owner = THIS_MODULE; add_mtd_device(pdev->mtd); return(0); @@ -211,9 +164,9 @@ del_mtd_device(udev->mtd); map_destroy(udev->mtd); } - if(0 != udev->map.map_priv_1) { - iounmap((void*)udev->map.map_priv_1); - udev->map.map_priv_1 = 0; + if(0 != udev->map.virt) { + iounmap((void*)udev->map.virt); + udev->map.virt = 0; } if(0 != udev->name) { kfree(udev->name); diff -Nru a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c --- a/drivers/mtd/maps/tqm8xxl.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/tqm8xxl.c Thu Dec 4 16:24:25 2003 @@ -2,7 +2,7 @@ * Handle mapping of the flash memory access routines * on TQM8xxL based devices. * - * $Id: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $ + * $Id: tqm8xxl.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $ * * based on rpxlite.c * @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -51,46 +52,6 @@ static unsigned long num_banks; static unsigned long start_scan_addr; -__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs) -{ - return *((__u8 *)(map->map_priv_1 + ofs)); -} - -__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs) -{ - return *((__u16 *)(map->map_priv_1 + ofs)); -} - -__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs) -{ - return *((__u32 *)(map->map_priv_1 + ofs)); -} - -void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *((__u8 *)(map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *((__u16 *)( map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *((__u32 *)(map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - /* * Here are partition information for all known TQM8xxL series devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition @@ -107,50 +68,48 @@ static unsigned long tqm8xxl_max_flash_size = 0x00800000; /* partition definition for first flash bank - * also ref. to "drivers\char\flash_config.c" + * (cf. "drivers/char/flash_config.c") */ static struct mtd_partition tqm8xxl_partitions[] = { { - name: "ppcboot", - offset: 0x00000000, - size: 0x00020000, /* 128KB */ - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "ppcboot", + .offset = 0x00000000, + .size = 0x00020000, /* 128KB */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "kernel", /* default kernel image */ - offset: 0x00020000, - size: 0x000e0000, - mask_flags: MTD_WRITEABLE, /* force read-only */ + .name = "kernel", /* default kernel image */ + .offset = 0x00020000, + .size = 0x000e0000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - name: "user", - offset: 0x00100000, - size: 0x00100000, + .name = "user", + .offset = 0x00100000, + .size = 0x00100000, }, { - name: "initrd", - offset: 0x00200000, - size: 0x00200000, + .name = "initrd", + .offset = 0x00200000, + .size = 0x00200000, } }; -/* partition definition for second flahs bank */ +/* partition definition for second flash bank */ static struct mtd_partition tqm8xxl_fs_partitions[] = { { - name: "cramfs", - offset: 0x00000000, - size: 0x00200000, + .name = "cramfs", + .offset = 0x00000000, + .size = 0x00200000, }, { - name: "jffs", - offset: 0x00200000, - size: 0x00200000, - //size: MTDPART_SIZ_FULL, + .name = "jffs", + .offset = 0x00200000, + .size = 0x00200000, + .//size = MTDPART_SIZ_FULL, } }; #endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - int __init init_tqm_mtd(void) { int idx = 0, ret = 0; @@ -160,67 +119,73 @@ flash_addr = bd->bi_flashstart; flash_size = bd->bi_flashsize; - //request maximum flash size address spzce + + //request maximum flash size address space start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); if (!start_scan_addr) { - //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR); - printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); + printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); return -EIO; } - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) - { + + for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { if(mtd_size >= flash_size) break; - printk("%s: chip probing count %d\n", __FUNCTION__, idx); + printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); - if(map_banks[idx] == NULL) - { - //return -ENOMEM; + if(map_banks[idx] == NULL) { ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ goto error_mem; } + memset((void *)map_banks[idx], 0, sizeof(struct map_info)); map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); - if(map_banks[idx]->name == NULL) - { - //return -ENOMEM; + + if (!map_banks[idx]->name) { ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ goto error_mem; } - memset((void *)map_banks[idx]->name, 0, 16); - sprintf(map_banks[idx]->name, "TQM8xxL%d", idx); + map_banks[idx]->size = flash_size; map_banks[idx]->buswidth = 4; - map_banks[idx]->read8 = tqm8xxl_read8; - map_banks[idx]->read16 = tqm8xxl_read16; - map_banks[idx]->read32 = tqm8xxl_read32; - map_banks[idx]->copy_from = tqm8xxl_copy_from; - map_banks[idx]->write8 = tqm8xxl_write8; - map_banks[idx]->write16 = tqm8xxl_write16; - map_banks[idx]->write32 = tqm8xxl_write32; - map_banks[idx]->copy_to = tqm8xxl_copy_to; - map_banks[idx]->map_priv_1 = - start_scan_addr + ((idx > 0) ? + + simple_map_init(map_banks[idx]); + + map_banks[idx]->virt = start_scan_addr; + map_banks[idx]->phys = flash_addr; + /* FIXME: This looks utterly bogus, but I'm trying to + preserve the behaviour of the original (shown here)... + + map_banks[idx]->map_priv_1 = + start_scan_addr + ((idx > 0) ? (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); + */ + + if (idx && mtd_banks[idx-1]) { + map_banks[idx]->virt += mtd_banks[idx-1]->size; + map_banks[idx]->phys += mtd_banks[idx-1]->size; + } + //start to probe flash chips mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); - if(mtd_banks[idx]) - { - mtd_banks[idx]->module = THIS_MODULE; + + if (mtd_banks[idx]) { + mtd_banks[idx]->owner = THIS_MODULE; mtd_size += mtd_banks[idx]->size; num_banks++; - printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, + + printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, mtd_banks[idx]->name, mtd_banks[idx]->size); } } /* no supported flash chips found */ - if(!num_banks) - { - printk("TQM8xxL: No support flash chips found!\n"); + if (!num_banks) { + printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n"); ret = -ENXIO; goto error_mem; } @@ -231,12 +196,13 @@ */ part_banks[0].mtd_part = tqm8xxl_partitions; part_banks[0].type = "Static image"; - part_banks[0].nums = NB_OF(tqm8xxl_partitions); + part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions); + part_banks[1].mtd_part = tqm8xxl_fs_partitions; part_banks[1].type = "Static file system"; - part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions); - for(idx = 0; idx < num_banks ; idx++) - { + part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions); + + for(idx = 0; idx < num_banks ; idx++) { if (part_banks[idx].nums == 0) { printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx); add_mtd_device(mtd_banks[idx]); @@ -254,12 +220,9 @@ #endif return 0; error_mem: - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) - { - if(map_banks[idx] != NULL) - { - if(map_banks[idx]->name != NULL) - { + for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if(map_banks[idx] != NULL) { + if(map_banks[idx]->name != NULL) { kfree(map_banks[idx]->name); map_banks[idx]->name = NULL; } @@ -267,18 +230,15 @@ map_banks[idx] = NULL; } } - //return -ENOMEM; error: iounmap((void *)start_scan_addr); - //return -ENXIO; return ret; } static void __exit cleanup_tqm_mtd(void) { unsigned int idx = 0; - for(idx = 0 ; idx < num_banks ; idx++) - { + for(idx = 0 ; idx < num_banks ; idx++) { /* destroy mtd_info previously allocated */ if (mtd_banks[idx]) { del_mtd_partitions(mtd_banks[idx]); @@ -288,6 +248,7 @@ kfree(map_banks[idx]->name); kfree(map_banks[idx]); } + if (start_scan_addr) { iounmap((void *)start_scan_addr); start_scan_addr = 0; diff -Nru a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c --- a/drivers/mtd/maps/tsunami_flash.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/tsunami_flash.c Thu Dec 4 16:24:25 2003 @@ -2,11 +2,13 @@ * tsunami_flash.c * * flash chip on alpha ds10... - * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $ */ #include #include +#include #include +#include #define FLASH_ENABLE_PORT 0x00C00001 #define FLASH_ENABLE_BYTE 0x01 @@ -58,18 +60,12 @@ static struct map_info tsunami_flash_map = { .name = "flash chip on the Tsunami TIG bus", .size = MAX_TIG_FLASH_SIZE, + .phys = NO_XIP; .buswidth = 1, .read8 = tsunami_flash_read8, - .read16 = 0, - .read32 = 0, .copy_from = tsunami_flash_copy_from, .write8 = tsunami_flash_write8, - .write16 = 0, - .write32 = 0, .copy_to = tsunami_flash_copy_to, - .set_vpp = 0, - .map_priv_1 = 0, - }; static struct mtd_info *tsunami_flash_mtd; @@ -99,7 +95,7 @@ tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); } if (tsunami_flash_mtd) { - tsunami_flash_mtd->module = THIS_MODULE; + tsunami_flash_mtd->owner = THIS_MODULE; add_mtd_device(tsunami_flash_mtd); return 0; } diff -Nru a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c --- a/drivers/mtd/maps/uclinux.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/maps/uclinux.c Thu Dec 4 16:24:26 2003 @@ -5,7 +5,7 @@ * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) * - * $Id: uclinux.c,v 1.2 2002/08/07 00:43:45 gerg Exp $ + * $Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $ */ /****************************************************************************/ @@ -24,58 +24,11 @@ /****************************************************************************/ -__u8 uclinux_read8(struct map_info *map, unsigned long ofs) -{ - return(*((__u8 *) (map->map_priv_1 + ofs))); -} - -__u16 uclinux_read16(struct map_info *map, unsigned long ofs) -{ - return(*((__u16 *) (map->map_priv_1 + ofs))); -} - -__u32 uclinux_read32(struct map_info *map, unsigned long ofs) -{ - return(*((__u32 *) (map->map_priv_1 + ofs))); -} - -void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *((__u8 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *((__u16 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *((__u32 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *) (map->map_priv_1 + to), from, len); -} /****************************************************************************/ struct map_info uclinux_ram_map = { - name: "RAM", - read8: uclinux_read8, - read16: uclinux_read16, - read32: uclinux_read32, - copy_from: uclinux_copy_from, - write8: uclinux_write8, - write16: uclinux_write16, - write32: uclinux_write32, - copy_to: uclinux_copy_to, + .name = "RAM", }; struct mtd_info *uclinux_ram_mtdinfo; @@ -83,7 +36,7 @@ /****************************************************************************/ struct mtd_partition uclinux_romfs[] = { - { name: "ROMfs", offset: 0 } + { .name = "ROMfs" } }; #define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0])) @@ -94,7 +47,7 @@ size_t *retlen, u_char **mtdbuf) { struct map_info *map = (struct map_info *) mtd->priv; - *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from)); + *mtdbuf = (u_char *) (map->virt + ((int) from)); *retlen = len; return(0); } @@ -108,29 +61,31 @@ extern char _ebss; mapp = &uclinux_ram_map; - mapp->map_priv_2 = (unsigned long) &_ebss; + mapp->phys = (unsigned long) &_ebss; mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); mapp->buswidth = 4; printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", (int) mapp->map_priv_2, (int) mapp->size); - mapp->map_priv_1 = (unsigned long) - ioremap_nocache(mapp->map_priv_2, mapp->size); + mapp->virt = (unsigned long) + ioremap_nocache(mapp->phys, mapp->size); - if (mapp->map_priv_1 == 0) { + if (mapp->virt == 0) { printk("uclinux[mtd]: ioremap_nocache() failed\n"); return(-EIO); } + simple_map_init(mapp); + mtd = do_map_probe("map_ram", mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); - iounmap((void *) mapp->map_priv_1); + iounmap((void *) mapp->virt); return(-ENXIO); } - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->point = uclinux_point; mtd->priv = mapp; @@ -155,8 +110,8 @@ uclinux_ram_mtdinfo = NULL; } if (uclinux_ram_map.map_priv_1) { - iounmap((void *) uclinux_ram_map.map_priv_1); - uclinux_ram_map.map_priv_1 = 0; + iounmap((void *) uclinux_ram_map.virt); + uclinux_ram_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c --- a/drivers/mtd/maps/vmax301.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/maps/vmax301.c Thu Dec 4 16:24:25 2003 @@ -1,4 +1,4 @@ -// $Id: vmax301.c,v 1.24 2001/10/02 15:05:14 dwmw2 Exp $ +// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $ /* ###################################################################### Tempustech VMAX SBC301 MTD Driver. @@ -24,6 +24,7 @@ #include #include +#include #define WINDOW_START 0xd8000 @@ -142,34 +143,36 @@ static struct map_info vmax_map[2] = { { - name: "VMAX301 Internal Flash", - size: 3*2*1024*1024, - buswidth: 1, - read8: vmax301_read8, - read16: vmax301_read16, - read32: vmax301_read32, - copy_from: vmax301_copy_from, - write8: vmax301_write8, - write16: vmax301_write16, - write32: vmax301_write32, - copy_to: vmax301_copy_to, - map_priv_1: WINDOW_START + WINDOW_LENGTH, - map_priv_2: 0xFFFFFFFF + .name = "VMAX301 Internal Flash", + .phys = NO_XIP, + .size = 3*2*1024*1024, + .buswidth = 1, + .read8 = vmax301_read8, + .read16 = vmax301_read16, + .read32 = vmax301_read32, + .copy_from = vmax301_copy_from, + .write8 = vmax301_write8, + .write16 = vmax301_write16, + .write32 = vmax301_write32, + .copy_to = vmax301_copy_to, + .map_priv_1 = WINDOW_START + WINDOW_LENGTH, + .map_priv_2 = 0xFFFFFFFF }, { - name: "VMAX301 Socket", - size: 0, - buswidth: 1, - read8: vmax301_read8, - read16: vmax301_read16, - read32: vmax301_read32, - copy_from: vmax301_copy_from, - write8: vmax301_write8, - write16: vmax301_write16, - write32: vmax301_write32, - copy_to: vmax301_copy_to, - map_priv_1: WINDOW_START + (3*WINDOW_LENGTH), - map_priv_2: 0xFFFFFFFF + .name = "VMAX301 Socket", + .phys = NO_XIP, + .size = 0, + .buswidth = 1, + .read8 = vmax301_read8, + .read16 = vmax301_read16, + .read32 = vmax301_read32, + .copy_from = vmax301_copy_from, + .write8 = vmax301_write8, + .write16 = vmax301_write16, + .write32 = vmax301_write32, + .copy_to = vmax301_copy_to, + .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH), + .map_priv_2 = 0xFFFFFFFF } }; @@ -206,8 +209,8 @@ address of the first half, because it's used more often. */ - vmax_map[0].map_priv_1 = iomapadr + WINDOW_START; - vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START); + vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; + vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); for (i=0; i<2; i++) { vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); @@ -218,7 +221,7 @@ if (!vmax_mtd[i]) vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]); if (vmax_mtd[i]) { - vmax_mtd[i]->module = THIS_MODULE; + vmax_mtd[i]->owner = THIS_MODULE; add_mtd_device(vmax_mtd[i]); } } diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c --- a/drivers/mtd/mtdblock.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/mtdblock.c Thu Dec 4 16:24:25 2003 @@ -1,52 +1,25 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.64 2003/10/04 17:14:14 dwmw2 Exp $ * - * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache + * (C) 2000-2003 Nicolas Pitre + * (C) 1999-2003 David Woodhouse */ #include #include #include #include +#include +#include #include +#include #include -#include - -#define MAJOR_NR MTD_BLOCK_MAJOR -#define DEVICE_NAME "mtdblock" -#define DEVICE_REQUEST mtdblock_request -#define DEVICE_NR(device) (device) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM -#include -/* for old kernels... */ -#ifndef QUEUE_EMPTY -#define QUEUE_EMPTY (!CURRENT) -#endif -#if LINUX_VERSION_CODE < 0x20300 -#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) -#else -#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) -#endif - -#ifdef CONFIG_DEVFS_FS -#include -static void mtd_notify_add(struct mtd_info* mtd); -static void mtd_notify_remove(struct mtd_info* mtd); -static struct mtd_notifier notifier = { - mtd_notify_add, - mtd_notify_remove, - NULL -}; -static devfs_handle_t devfs_dir_handle = NULL; -static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES]; -#endif +#include static struct mtdblk_dev { - struct mtd_info *mtd; /* Locked */ + struct mtd_info *mtd; int count; struct semaphore cache_sem; unsigned char *cache_data; @@ -55,19 +28,6 @@ enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; } *mtdblks[MAX_MTD_DEVICES]; -static spinlock_t mtdblks_lock; - -static int mtd_sizes[MAX_MTD_DEVICES]; -static int mtd_blksizes[MAX_MTD_DEVICES]; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) -#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT -#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define BLK_INC_USE_COUNT do {} while(0) -#define BLK_DEC_USE_COUNT do {} while(0) -#endif - /* * Cache stuff... * @@ -151,7 +111,7 @@ return ret; /* - * Here we could argably set the cache state to STATE_CLEAN. + * Here we could argubly set the cache state to STATE_CLEAN. * However this could lead to inconsistency since we will not * be notified if this content is altered on the flash by other * means. Let's declare it empty and leave buffering tasks to @@ -277,57 +237,47 @@ return 0; } +static int mtdblock_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) +{ + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; + return do_cached_read(mtdblk, block<<9, 512, buf); +} +static int mtdblock_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) +{ + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; + if (unlikely(!mtdblk->cache_data)) { + mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); + if (!mtdblk->cache_data) + return -EINTR; + /* -EINTR is not really correct, but it is the best match + * documented in man 2 write for all cases. We could also + * return -EAGAIN sometimes, but why bother? + */ + } + return do_cached_write(mtdblk, block<<9, 512, buf); +} -static int mtdblock_open(struct inode *inode, struct file *file) +static int mtdblock_open(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk; - struct mtd_info *mtd; - int dev; + struct mtd_info *mtd = mbd->mtd; + int dev = mbd->devnum; DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); - if (!inode) - return -EINVAL; - - dev = MINOR(inode->i_rdev); - if (dev >= MAX_MTD_DEVICES) - return -EINVAL; - - BLK_INC_USE_COUNT; - - mtd = get_mtd_device(NULL, dev); - if (!mtd) - return -ENODEV; - if (MTD_ABSENT == mtd->type) { - put_mtd_device(mtd); - BLK_DEC_USE_COUNT; - return -ENODEV; - } - - spin_lock(&mtdblks_lock); - - /* If it's already open, no need to piss about. */ if (mtdblks[dev]) { mtdblks[dev]->count++; - spin_unlock(&mtdblks_lock); - put_mtd_device(mtd); return 0; } - /* OK, it's not open. Try to find it */ - - /* First we have to drop the lock, because we have to - to things which might sleep. - */ - spin_unlock(&mtdblks_lock); - + /* OK, it's not open. Create cache info for it */ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); - if (!mtdblk) { - put_mtd_device(mtd); - BLK_DEC_USE_COUNT; + if (!mtdblk) return -ENOMEM; - } + memset(mtdblk, 0, sizeof(*mtdblk)); mtdblk->count = 1; mtdblk->mtd = mtd; @@ -337,336 +287,102 @@ if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM && mtdblk->mtd->erasesize) { mtdblk->cache_size = mtdblk->mtd->erasesize; - mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); - if (!mtdblk->cache_data) { - put_mtd_device(mtdblk->mtd); - kfree(mtdblk); - BLK_DEC_USE_COUNT; - return -ENOMEM; - } - } - - /* OK, we've created a new one. Add it to the list. */ - - spin_lock(&mtdblks_lock); - - if (mtdblks[dev]) { - /* Another CPU made one at the same time as us. */ - mtdblks[dev]->count++; - spin_unlock(&mtdblks_lock); - put_mtd_device(mtdblk->mtd); - vfree(mtdblk->cache_data); - kfree(mtdblk); - return 0; + mtdblk->cache_data = NULL; } mtdblks[dev] = mtdblk; - mtd_sizes[dev] = mtdblk->mtd->size/1024; - if (mtdblk->mtd->erasesize) - mtd_blksizes[dev] = mtdblk->mtd->erasesize; - if (mtd_blksizes[dev] > PAGE_SIZE) - mtd_blksizes[dev] = PAGE_SIZE; - set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE)); - - spin_unlock(&mtdblks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; } -static release_t mtdblock_release(struct inode *inode, struct file *file) +static int mtdblock_release(struct mtd_blktrans_dev *mbd) { - int dev; - struct mtdblk_dev *mtdblk; - DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); - - if (inode == NULL) - release_return(-ENODEV); + int dev = mbd->devnum; + struct mtdblk_dev *mtdblk = mtdblks[dev]; - dev = MINOR(inode->i_rdev); - mtdblk = mtdblks[dev]; + DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); - spin_lock(&mtdblks_lock); if (!--mtdblk->count) { /* It was the last usage. Free the device */ mtdblks[dev] = NULL; - spin_unlock(&mtdblks_lock); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); - put_mtd_device(mtdblk->mtd); vfree(mtdblk->cache_data); kfree(mtdblk); - } else { - spin_unlock(&mtdblks_lock); } - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); - BLK_DEC_USE_COUNT; - release_return(0); + return 0; } - -/* - * This is a special request_fn because it is executed in a process context - * to be able to sleep independently of the caller. The io_request_lock - * is held upon entry and exit. - * The head of our request queue is considered active so there is no need - * to dequeue requests before we are done. - */ -static void handle_mtdblock_request(void) +static int mtdblock_flush(struct mtd_blktrans_dev *dev) { - struct request *req; - struct mtdblk_dev *mtdblk; - unsigned int res; - - for (;;) { - INIT_REQUEST; - req = CURRENT; - spin_unlock_irq(&io_request_lock); - mtdblk = mtdblks[MINOR(req->rq_dev)]; - res = 0; - - if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES) - panic("%s: minor out of bounds", __FUNCTION__); - - if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) - goto end_req; - - // Handle the request - switch (req->cmd) - { - int err; - - case READ: - down(&mtdblk->cache_sem); - err = do_cached_read (mtdblk, req->sector << 9, - req->current_nr_sectors << 9, - req->buffer); - up(&mtdblk->cache_sem); - if (!err) - res = 1; - break; - - case WRITE: - // Read only device - if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) - break; - - // Do the write - down(&mtdblk->cache_sem); - err = do_cached_write (mtdblk, req->sector << 9, - req->current_nr_sectors << 9, - req->buffer); - up(&mtdblk->cache_sem); - if (!err) - res = 1; - break; - } - -end_req: - spin_lock_irq(&io_request_lock); - end_request(res); - } -} + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; -static volatile int leaving = 0; -static DECLARE_MUTEX_LOCKED(thread_sem); -static DECLARE_WAIT_QUEUE_HEAD(thr_wq); - -int mtdblock_thread(void *dummy) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* we might get involved when memory gets low, so use PF_MEMALLOC */ - tsk->flags |= PF_MEMALLOC; - strcpy(tsk->comm, "mtdblockd"); - spin_lock_irq(&tsk->sigmask_lock); - sigfillset(&tsk->blocked); - recalc_sigpending(tsk); - spin_unlock_irq(&tsk->sigmask_lock); - daemonize(); - - while (!leaving) { - add_wait_queue(&thr_wq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&io_request_lock); - if (QUEUE_EMPTY || QUEUE_PLUGGED) { - spin_unlock_irq(&io_request_lock); - schedule(); - remove_wait_queue(&thr_wq, &wait); - } else { - remove_wait_queue(&thr_wq, &wait); - set_current_state(TASK_RUNNING); - handle_mtdblock_request(); - spin_unlock_irq(&io_request_lock); - } - } + down(&mtdblk->cache_sem); + write_cached_data(mtdblk); + up(&mtdblk->cache_sem); - up(&thread_sem); + if (mtdblk->mtd->sync) + mtdblk->mtd->sync(mtdblk->mtd); return 0; } -#if LINUX_VERSION_CODE < 0x20300 -#define RQFUNC_ARG void -#else -#define RQFUNC_ARG request_queue_t *q -#endif - -static void mtdblock_request(RQFUNC_ARG) +static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - /* Don't do anything, except wake the thread if necessary */ - wake_up(&thr_wq); -} + struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return; -static int mtdblock_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct mtdblk_dev *mtdblk; - - mtdblk = mtdblks[MINOR(inode->i_rdev)]; + memset(dev, 0, sizeof(*dev)); -#ifdef PARANOIA - if (!mtdblk) - BUG(); -#endif + dev->mtd = mtd; + dev->devnum = mtd->index; + dev->blksize = 512; + dev->size = mtd->size >> 9; + dev->tr = tr; - switch (cmd) { - case BLKGETSIZE: /* Return device size */ - return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg); - -#ifdef BLKGETSIZE64 - case BLKGETSIZE64: - return put_user((u64)mtdblk->mtd->size, (u64 *)arg); -#endif - - case BLKFLSBUF: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; -#endif - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - down(&mtdblk->cache_sem); - write_cached_data(mtdblk); - up(&mtdblk->cache_sem); - if (mtdblk->mtd->sync) - mtdblk->mtd->sync(mtdblk->mtd); - return 0; + if (!(mtd->flags & MTD_WRITEABLE)) + dev->readonly = 1; - default: - return -EINVAL; - } + add_mtd_blktrans_dev(dev); } -#if LINUX_VERSION_CODE < 0x20326 -static struct file_operations mtd_fops = -{ - open: mtdblock_open, - ioctl: mtdblock_ioctl, - release: mtdblock_release, - read: block_read, - write: block_write -}; -#else -static struct block_device_operations mtd_fops = +static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) - owner: THIS_MODULE, -#endif - open: mtdblock_open, - release: mtdblock_release, - ioctl: mtdblock_ioctl -}; -#endif - -#ifdef CONFIG_DEVFS_FS -/* Notification that a new device has been added. Create the devfs entry for - * it. */ - -static void mtd_notify_add(struct mtd_info* mtd) -{ - char name[8]; - - if (!mtd || mtd->type == MTD_ABSENT) - return; - - sprintf(name, "%d", mtd->index); - devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name, - DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index, - S_IFBLK | S_IRUGO | S_IWUGO, - &mtd_fops, NULL); + del_mtd_blktrans_dev(dev); + kfree(dev); } -static void mtd_notify_remove(struct mtd_info* mtd) -{ - if (!mtd || mtd->type == MTD_ABSENT) - return; - - devfs_unregister(devfs_rw_handle[mtd->index]); -} -#endif +struct mtd_blktrans_ops mtdblock_tr = { + .name = "mtdblock", + .major = 31, + .part_bits = 0, + .open = mtdblock_open, + .flush = mtdblock_flush, + .release = mtdblock_release, + .readsect = mtdblock_readsect, + .writesect = mtdblock_writesect, + .add_mtd = mtdblock_add_mtd, + .remove_dev = mtdblock_remove_dev, + .owner = THIS_MODULE, +}; int __init init_mtdblock(void) { - int i; - - spin_lock_init(&mtdblks_lock); -#ifdef CONFIG_DEVFS_FS - if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops)) - { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_BLOCK_MAJOR); - return -EAGAIN; - } - - devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); - register_mtd_user(¬ifier); -#else - if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_BLOCK_MAJOR); - return -EAGAIN; - } -#endif - - /* We fill it in at open() time. */ - for (i=0; i< MAX_MTD_DEVICES; i++) { - mtd_sizes[i] = 0; - mtd_blksizes[i] = BLOCK_SIZE; - } - init_waitqueue_head(&thr_wq); - /* Allow the block size to default to BLOCK_SIZE. */ - blksize_size[MAJOR_NR] = mtd_blksizes; - blk_size[MAJOR_NR] = mtd_sizes; - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); - kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); - return 0; + return register_mtd_blktrans(&mtdblock_tr); } static void __exit cleanup_mtdblock(void) { - leaving = 1; - wake_up(&thr_wq); - down(&thread_sem); -#ifdef CONFIG_DEVFS_FS - unregister_mtd_user(¬ifier); - devfs_unregister(devfs_dir_handle); - devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME); -#else - unregister_blkdev(MAJOR_NR,DEVICE_NAME); -#endif - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - blksize_size[MAJOR_NR] = NULL; - blk_size[MAJOR_NR] = NULL; + deregister_mtd_blktrans(&mtdblock_tr); } module_init(init_mtdblock); diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c --- a/drivers/mtd/mtdblock_ro.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/mtdblock_ro.c Thu Dec 4 16:24:25 2003 @@ -1,301 +1,87 @@ /* - * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $ + * $Id: mtdblock_ro.c,v 1.18 2003/06/23 12:00:08 dwmw2 Exp $ * - * Read-only version of the mtdblock device, without the - * read/erase/modify/writeback stuff + * (C) 2003 David Woodhouse + * + * Simple read-only (writable only for RAM) mtdblock driver */ -#ifdef MTDBLOCK_DEBUG -#define DEBUGLVL debug -#endif - - -#include -#include - +#include +#include #include -#include +#include -#define MAJOR_NR MTD_BLOCK_MAJOR -#define DEVICE_NAME "mtdblock" -#define DEVICE_REQUEST mtdblock_request -#define DEVICE_NR(device) (device) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM -#include - -#if LINUX_VERSION_CODE < 0x20300 -#define RQFUNC_ARG void -#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) -#else -#define RQFUNC_ARG request_queue_t *q -#endif - -#ifdef MTDBLOCK_DEBUG -static int debug = MTDBLOCK_DEBUG; -MODULE_PARM(debug, "i"); -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) -#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT -#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define BLK_INC_USE_COUNT do {} while(0) -#define BLK_DEC_USE_COUNT do {} while(0) -#endif - -static int mtd_sizes[MAX_MTD_DEVICES]; - - -static int mtdblock_open(struct inode *inode, struct file *file) +static int mtdblock_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - struct mtd_info *mtd = NULL; - - int dev; - - DEBUG(1,"mtdblock_open\n"); - - if (inode == 0) - return -EINVAL; - - dev = MINOR(inode->i_rdev); - - mtd = get_mtd_device(NULL, dev); - if (!mtd) - return -EINVAL; - if (MTD_ABSENT == mtd->type) { - put_mtd_device(mtd); - return -EINVAL; - } - - BLK_INC_USE_COUNT; - - mtd_sizes[dev] = mtd->size>>9; - - DEBUG(1, "ok\n"); + size_t retlen; + if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf)) + return 1; return 0; } -static release_t mtdblock_release(struct inode *inode, struct file *file) +static int mtdblock_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - int dev; - struct mtd_info *mtd; + size_t retlen; - DEBUG(1, "mtdblock_release\n"); - - if (inode == NULL) - release_return(-ENODEV); - - dev = MINOR(inode->i_rdev); - mtd = __get_mtd_device(NULL, dev); - - if (!mtd) { - printk(KERN_WARNING "MTD device is absent on mtd_release!\n"); - BLK_DEC_USE_COUNT; - release_return(-ENODEV); - } - - if (mtd->sync) - mtd->sync(mtd); + if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf)) + return 1; + return 0; +} - put_mtd_device(mtd); +static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) +{ + struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); - DEBUG(1, "ok\n"); + if (!dev) + return; - BLK_DEC_USE_COUNT; - release_return(0); -} + memset(dev, 0, sizeof(*dev)); + dev->mtd = mtd; + dev->devnum = mtd->index; + dev->blksize = 512; + dev->size = mtd->size >> 9; + dev->tr = tr; + if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) != + (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) + dev->readonly = 1; -static void mtdblock_request(RQFUNC_ARG) -{ - struct request *current_request; - unsigned int res = 0; - struct mtd_info *mtd; - - while (1) - { - /* Grab the Request and unlink it from the request list, INIT_REQUEST - will execute a return if we are done. */ - INIT_REQUEST; - current_request = CURRENT; - - if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES) - { - printk("mtd: Unsupported device!\n"); - end_request(0); - continue; - } - - // Grab our MTD structure - - mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev)); - if (!mtd) { - printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV); - end_request(0); - } - - if (current_request->sector << 9 > mtd->size || - (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size) - { - printk("mtd: Attempt to read past end of device!\n"); - printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, - current_request->sector, current_request->current_nr_sectors); - end_request(0); - continue; - } - - /* Remove the request we are handling from the request list so nobody messes - with it */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - /* Now drop the lock that the ll_rw_blk functions grabbed for us - and process the request. This is necessary due to the extreme time - we spend processing it. */ - spin_unlock_irq(&io_request_lock); -#endif - - // Handle the request - switch (current_request->cmd) - { - size_t retlen; - - case READ: - if (MTD_READ(mtd,current_request->sector<<9, - current_request->current_nr_sectors << 9, - &retlen, current_request->buffer) == 0) - res = 1; - else - res = 0; - break; - - case WRITE: - - /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector, - current_request->current_nr_sectors); - */ - - // Read only device - if ((mtd->flags & MTD_CAP_RAM) == 0) - { - res = 0; - break; - } - - // Do the write - if (MTD_WRITE(mtd,current_request->sector<<9, - current_request->current_nr_sectors << 9, - &retlen, current_request->buffer) == 0) - res = 1; - else - res = 0; - break; - - // Shouldn't happen - default: - printk("mtd: unknown request\n"); - break; - } - - // Grab the lock and re-thread the item onto the linked list -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - spin_lock_irq(&io_request_lock); -#endif - end_request(res); - } + add_mtd_blktrans_dev(dev); } - - -static int mtdblock_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) { - struct mtd_info *mtd; - - mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev)); - - if (!mtd) return -EINVAL; - - switch (cmd) { - case BLKGETSIZE: /* Return device size */ - return put_user((mtd->size >> 9), (unsigned long *) arg); - -#ifdef BLKGETSIZE64 - case BLKGETSIZE64: - return put_user((u64)mtd->size, (u64 *)arg); -#endif - - case BLKFLSBUF: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if(!capable(CAP_SYS_ADMIN)) return -EACCES; -#endif - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - if (mtd->sync) - mtd->sync(mtd); - return 0; - - default: - return -ENOTTY; - } + del_mtd_blktrans_dev(dev); + kfree(dev); } -#if LINUX_VERSION_CODE < 0x20326 -static struct file_operations mtd_fops = -{ - open: mtdblock_open, - ioctl: mtdblock_ioctl, - release: mtdblock_release, - read: block_read, - write: block_write -}; -#else -static struct block_device_operations mtd_fops = -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) - owner: THIS_MODULE, -#endif - open: mtdblock_open, - release: mtdblock_release, - ioctl: mtdblock_ioctl +struct mtd_blktrans_ops mtdblock_tr = { + .name = "mtdblock", + .major = 31, + .part_bits = 0, + .readsect = mtdblock_readsect, + .writesect = mtdblock_writesect, + .add_mtd = mtdblock_add_mtd, + .remove_dev = mtdblock_remove_dev, + .owner = THIS_MODULE, }; -#endif -int __init init_mtdblock(void) +static int __init mtdblock_init(void) { - int i; - - if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_BLOCK_MAJOR); - return -EAGAIN; - } - - /* We fill it in at open() time. */ - for (i=0; i< MAX_MTD_DEVICES; i++) { - mtd_sizes[i] = 0; - } - - /* Allow the block size to default to BLOCK_SIZE. */ - blksize_size[MAJOR_NR] = NULL; - blk_size[MAJOR_NR] = mtd_sizes; - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); - return 0; + return register_mtd_blktrans(&mtdblock_tr); } -static void __exit cleanup_mtdblock(void) +static void __exit mtdblock_exit(void) { - unregister_blkdev(MAJOR_NR,DEVICE_NAME); - blk_size[MAJOR_NR] = NULL; - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + deregister_mtd_blktrans(&mtdblock_tr); } -module_init(init_mtdblock); -module_exit(cleanup_mtdblock); - +module_init(mtdblock_init); +module_exit(mtdblock_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Erwin Authried et al."); +MODULE_AUTHOR("David Woodhouse "); MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices"); diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c --- a/drivers/mtd/mtdchar.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/mtdchar.c Thu Dec 4 16:24:25 2003 @@ -1,8 +1,7 @@ /* - * $Id: mtdchar.c,v 1.49 2003/01/24 12:02:58 dwmw2 Exp $ + * $Id: mtdchar.c,v 1.56 2003/11/14 19:50:03 thayne Exp $ * * Character-device access to raw MTD devices. - * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c * */ @@ -10,7 +9,11 @@ #include #include #include +#include #include +#include +#include +#include #ifdef CONFIG_DEVFS_FS #include @@ -18,8 +21,8 @@ static void mtd_notify_remove(struct mtd_info* mtd); static struct mtd_notifier notifier = { - add: mtd_notify_add, - remove: mtd_notify_remove, + .add = mtd_notify_add, + .remove = mtd_notify_remove, }; static devfs_handle_t devfs_dir_handle; @@ -60,7 +63,7 @@ static int mtd_open(struct inode *inode, struct file *file) { - int minor = minor(inode->i_rdev); + int minor = iminor(inode); int devnum = minor >> 1; struct mtd_info *mtd; @@ -442,80 +445,12 @@ break; } - case MEMWRITEDATA: + case MEMSETOOBSEL: { - struct mtd_oob_buf buf; - void *databuf; - ssize_t retlen; - - if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf))) - return -EFAULT; - - if (buf.length > 0x4096) - return -EINVAL; - - if (!mtd->write_ecc) - ret = -EOPNOTSUPP; - else - ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length); - - if (ret) - return ret; - - databuf = kmalloc(buf.length, GFP_KERNEL); - if (!databuf) - return -ENOMEM; - - if (copy_from_user(databuf, buf.ptr, buf.length)) { - kfree(databuf); + if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo))) return -EFAULT; - } - - ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0); - - if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t))) - ret = -EFAULT; - - kfree(databuf); break; - } - - case MEMREADDATA: - { - struct mtd_oob_buf buf; - void *databuf; - ssize_t retlen = 0; - - if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf))) - return -EFAULT; - - if (buf.length > 0x4096) - return -EINVAL; - - if (!mtd->read_ecc) - ret = -EOPNOTSUPP; - else - ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length); - - if (ret) - return ret; - - databuf = kmalloc(buf.length, GFP_KERNEL); - if (!databuf) - return -ENOMEM; - - ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0); - - if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t))) - ret = -EFAULT; - else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) - ret = -EFAULT; - - kfree(databuf); - break; - } - default: DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO); @@ -526,13 +461,13 @@ } /* memory_ioctl */ static struct file_operations mtd_fops = { - owner: THIS_MODULE, - llseek: mtd_lseek, /* lseek */ - read: mtd_read, /* read */ - write: mtd_write, /* write */ - ioctl: mtd_ioctl, /* ioctl */ - open: mtd_open, /* open */ - release: mtd_close, /* release */ + .owner = THIS_MODULE, + .llseek = mtd_lseek, + .read = mtd_read, + .write = mtd_write, + .ioctl = mtd_ioctl, + .open = mtd_open, + .release = mtd_close, }; @@ -572,26 +507,18 @@ static int __init init_mtdchar(void) { -#ifdef CONFIG_DEVFS_FS - if (devfs_register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) + if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", MTD_CHAR_MAJOR); return -EAGAIN; } +#ifdef CONFIG_DEVFS_FS devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL); register_mtd_user(¬ifier); -#else - if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) - { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_CHAR_MAJOR); - return -EAGAIN; - } #endif - return 0; } @@ -600,10 +527,8 @@ #ifdef CONFIG_DEVFS_FS unregister_mtd_user(¬ifier); devfs_unregister(devfs_dir_handle); - devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); -#else - unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); #endif + unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); } module_init(init_mtdchar); diff -Nru a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c --- a/drivers/mtd/mtdconcat.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/mtdconcat.c Thu Dec 4 16:24:26 2003 @@ -3,9 +3,11 @@ * * (C) 2002 Robert Kaiser * + * NAND support by Christian Gan + * * This code is GPL * - * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $ + * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $ */ #include @@ -24,7 +26,7 @@ */ struct mtd_concat { struct mtd_info mtd; - int num_subdev; + int num_subdev; struct mtd_info **subdev; }; @@ -35,21 +37,112 @@ #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) - /* * Given a pointer to the MTD object in the mtd_concat structure, * we can retrieve the pointer to that structure with this macro. */ #define CONCAT(x) ((struct mtd_concat *)(x)) - /* * MTD methods which look up the relevant subdevice, translate the * effective address and pass through to the subdevice. */ -static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int +concat_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) { + /* Not destined for this subdev */ + size = 0; + from -= subdev->size; + continue; + } + if (from + len > subdev->size) + /* First part goes into this subdev */ + size = subdev->size - from; + else + /* Entire transaction goes into this subdev */ + size = len; + + err = subdev->read(subdev, from, size, &retsize, buf); + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + return err; +} + +static int +concat_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) { + size = 0; + to -= subdev->size; + continue; + } + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else + err = subdev->write(subdev, to, size, &retsize, buf); + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + return err; +} + +static int +concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * eccbuf, + struct nand_oobinfo *oobsel) { struct mtd_concat *concat = CONCAT(mtd); int err = -EINVAL; @@ -57,43 +150,56 @@ *retlen = 0; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size, retsize; - if (from >= subdev->size) - { - size = 0; + if (from >= subdev->size) { + /* Not destined for this subdev */ + size = 0; from -= subdev->size; + continue; } + + if (from + len > subdev->size) + /* First part goes into this subdev */ + size = subdev->size - from; else - { - if (from + len > subdev->size) - size = subdev->size - from; - else - size = len; - - err = subdev->read(subdev, from, size, &retsize, buf); - - if(err) - break; - - *retlen += retsize; - len -= size; - if(len == 0) - break; + /* Entire transaction goes into this subdev */ + size = len; + if (subdev->read_ecc) + err = subdev->read_ecc(subdev, from, size, + &retsize, buf, eccbuf, oobsel); + else err = -EINVAL; - buf += size; - from = 0; + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + if (eccbuf) { + eccbuf += subdev->oobsize; + /* in nand.c at least, eccbufs are + tagged with 2 (int)eccstatus'; we + must account for these */ + eccbuf += 2 * (sizeof (int)); } + from = 0; } return err; } -static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int +concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf, u_char * eccbuf, + struct nand_oobinfo *oobsel) { struct mtd_concat *concat = CONCAT(mtd); int err = -EINVAL; @@ -104,47 +210,146 @@ *retlen = 0; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size, retsize; - if (to >= subdev->size) - { - size = 0; + if (to >= subdev->size) { + size = 0; to -= subdev->size; + continue; + } + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else if (subdev->write_ecc) + err = subdev->write_ecc(subdev, to, size, + &retsize, buf, eccbuf, oobsel); + else + err = -EINVAL; + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + if (eccbuf) + eccbuf += subdev->oobsize; + to = 0; + } + return err; +} + +static int +concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) { + /* Not destined for this subdev */ + size = 0; + from -= subdev->size; + continue; } + if (from + len > subdev->size) + /* First part goes into this subdev */ + size = subdev->size - from; else - { - if (to + len > subdev->size) - size = subdev->size - to; - else - size = len; - - if (!(subdev->flags & MTD_WRITEABLE)) - err = -EROFS; - else - err = subdev->write(subdev, to, size, &retsize, buf); - - if(err) - break; - - *retlen += retsize; - len -= size; - if(len == 0) - break; + /* Entire transaction goes into this subdev */ + size = len; + if (subdev->read_oob) + err = subdev->read_oob(subdev, from, size, + &retsize, buf); + else err = -EINVAL; - buf += size; - to = 0; + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + return err; +} + +static int +concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) { + size = 0; + to -= subdev->size; + continue; } + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else if (subdev->write_oob) + err = subdev->write_oob(subdev, to, size, &retsize, + buf); + else + err = -EINVAL; + + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; } return err; } -static void concat_erase_callback (struct erase_info *instr) +static void concat_erase_callback(struct erase_info *instr) { - wake_up((wait_queue_head_t *)instr->priv); + wake_up((wait_queue_head_t *) instr->priv); } static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) @@ -160,18 +365,18 @@ erase->mtd = mtd; erase->callback = concat_erase_callback; - erase->priv = (unsigned long)&waitq; - + erase->priv = (unsigned long) &waitq; + /* * FIXME: Allow INTERRUPTIBLE. Which means * not having the wait_queue head on the stack. */ err = mtd->erase(mtd, erase); - if (!err) - { + if (!err) { set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&waitq, &wait); - if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) + if (erase->state != MTD_ERASE_DONE + && erase->state != MTD_ERASE_FAILED) schedule(); remove_wait_queue(&waitq, &wait); set_current_state(TASK_RUNNING); @@ -181,7 +386,7 @@ return err; } -static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) +static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mtd_concat *concat = CONCAT(mtd); struct mtd_info *subdev; @@ -192,10 +397,10 @@ if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - if(instr->addr > concat->mtd.size) + if (instr->addr > concat->mtd.size) return -EINVAL; - if(instr->len + instr->addr > concat->mtd.size) + if (instr->len + instr->addr > concat->mtd.size) return -EINVAL; /* @@ -204,23 +409,22 @@ * region info rather than looking at each particular sub-device * in turn. */ - if (!concat->mtd.numeraseregions) - { /* the easy case: device has uniform erase block size */ - if(instr->addr & (concat->mtd.erasesize - 1)) + if (!concat->mtd.numeraseregions) { + /* the easy case: device has uniform erase block size */ + if (instr->addr & (concat->mtd.erasesize - 1)) return -EINVAL; - if(instr->len & (concat->mtd.erasesize - 1)) + if (instr->len & (concat->mtd.erasesize - 1)) return -EINVAL; - } - else - { /* device has variable erase size */ - struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; + } else { + /* device has variable erase size */ + struct mtd_erase_region_info *erase_regions = + concat->mtd.eraseregions; /* * Find the erase region where the to-be-erased area begins: */ - for(i = 0; i < concat->mtd.numeraseregions && - instr->addr >= erase_regions[i].offset; i++) - ; + for (i = 0; i < concat->mtd.numeraseregions && + instr->addr >= erase_regions[i].offset; i++) ; --i; /* @@ -228,25 +432,26 @@ * to-be-erased area begins. Verify that the starting * offset is aligned to this region's erase size: */ - if (instr->addr & (erase_regions[i].erasesize-1)) + if (instr->addr & (erase_regions[i].erasesize - 1)) return -EINVAL; /* * now find the erase region where the to-be-erased area ends: */ - for(; i < concat->mtd.numeraseregions && - (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) - ; + for (; i < concat->mtd.numeraseregions && + (instr->addr + instr->len) >= erase_regions[i].offset; + ++i) ; --i; /* * check if the ending offset is aligned to this region's erase size */ - if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) + if ((instr->addr + instr->len) & (erase_regions[i].erasesize - + 1)) return -EINVAL; } /* make a local copy of instr to avoid modifying the caller's struct */ - erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); + erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); if (!erase) return -ENOMEM; @@ -258,39 +463,40 @@ * find the subdevice where the to-be-erased area begins, adjust * starting offset to be relative to the subdevice start */ - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { subdev = concat->subdev[i]; - if(subdev->size <= erase->addr) + if (subdev->size <= erase->addr) erase->addr -= subdev->size; else break; - } - if(i >= concat->num_subdev) /* must never happen since size */ - BUG(); /* limit has been verified above */ + } + + /* must never happen since size limit has been verified above */ + if (i >= concat->num_subdev) + BUG(); /* now do the erase: */ err = 0; - for(;length > 0; i++) /* loop for all subevices affected by this request */ - { - subdev = concat->subdev[i]; /* get current subdevice */ + for (; length > 0; i++) { + /* loop for all subdevices affected by this request */ + subdev = concat->subdev[i]; /* get current subdevice */ /* limit length to subdevice's size: */ - if(erase->addr + length > subdev->size) + if (erase->addr + length > subdev->size) erase->len = subdev->size - erase->addr; else erase->len = length; - if (!(subdev->flags & MTD_WRITEABLE)) - { + if (!(subdev->flags & MTD_WRITEABLE)) { err = -EROFS; break; } length -= erase->len; - if ((err = concat_dev_erase(subdev, erase))) - { - if(err == -EINVAL) /* sanity check: must never happen since */ - BUG(); /* block alignment has been checked above */ + if ((err = concat_dev_erase(subdev, erase))) { + /* sanity check: should never happen since + * block alignment has been checked above */ + if (err == -EINVAL) + BUG(); break; } /* @@ -313,85 +519,79 @@ return 0; } -static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; - if ((len + ofs) > mtd->size) + if ((len + ofs) > mtd->size) return -EINVAL; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size; - if (ofs >= subdev->size) - { - size = 0; + if (ofs >= subdev->size) { + size = 0; ofs -= subdev->size; + continue; } + if (ofs + len > subdev->size) + size = subdev->size - ofs; else - { - if (ofs + len > subdev->size) - size = subdev->size - ofs; - else - size = len; - - err = subdev->lock(subdev, ofs, size); - - if(err) - break; - - len -= size; - if(len == 0) - break; + size = len; - err = -EINVAL; - ofs = 0; - } + err = subdev->lock(subdev, ofs, size); + + if (err) + break; + + len -= size; + if (len == 0) + break; + + err = -EINVAL; + ofs = 0; } + return err; } -static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; - if ((len + ofs) > mtd->size) + if ((len + ofs) > mtd->size) return -EINVAL; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size; - if (ofs >= subdev->size) - { - size = 0; + if (ofs >= subdev->size) { + size = 0; ofs -= subdev->size; + continue; } + if (ofs + len > subdev->size) + size = subdev->size - ofs; else - { - if (ofs + len > subdev->size) - size = subdev->size - ofs; - else - size = len; - - err = subdev->unlock(subdev, ofs, size); - - if(err) - break; - - len -= size; - if(len == 0) - break; + size = len; - err = -EINVAL; - ofs = 0; - } + err = subdev->unlock(subdev, ofs, size); + + if (err) + break; + + len -= size; + if (len == 0) + break; + + err = -EINVAL; + ofs = 0; } + return err; } @@ -400,8 +600,7 @@ struct mtd_concat *concat = CONCAT(mtd); int i; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; subdev->sync(subdev); } @@ -412,10 +611,9 @@ struct mtd_concat *concat = CONCAT(mtd); int i, rc = 0; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - if((rc = subdev->suspend(subdev)) < 0) + if ((rc = subdev->suspend(subdev)) < 0) return rc; } return rc; @@ -426,8 +624,7 @@ struct mtd_concat *concat = CONCAT(mtd); int i; - for(i = 0; i < concat->num_subdev; i++) - { + for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; subdev->resume(subdev); } @@ -439,11 +636,10 @@ * stored to *new_dev upon success. This function does _not_ * register any devices: this is the caller's responsibility. */ -struct mtd_info *mtd_concat_create( - struct mtd_info *subdev[], /* subdevices to concatenate */ - int num_devs, /* number of subdevices */ - char *name) /* name for the new device */ -{ +struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + char *name) +{ /* name for the new device */ int i; size_t size; struct mtd_concat *concat; @@ -451,90 +647,103 @@ int num_erase_region; printk(KERN_NOTICE "Concatenating MTD devices:\n"); - for(i = 0; i < num_devs; i++) + for (i = 0; i < num_devs; i++) printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); printk(KERN_NOTICE "into device \"%s\"\n", name); /* allocate the device structure */ size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); - concat = kmalloc (size, GFP_KERNEL); - if(!concat) - { - printk ("memory allocation error while creating concatenated device \"%s\"\n", - name); - return NULL; + concat = kmalloc(size, GFP_KERNEL); + if (!concat) { + printk + ("memory allocation error while creating concatenated device \"%s\"\n", + name); + return NULL; } memset(concat, 0, size); - concat->subdev = (struct mtd_info **)(concat + 1); + concat->subdev = (struct mtd_info **) (concat + 1); /* * Set up the new "super" device's MTD object structure, check for * incompatibilites between the subdevices. */ - concat->mtd.type = subdev[0]->type; - concat->mtd.flags = subdev[0]->flags; - concat->mtd.size = subdev[0]->size; + concat->mtd.type = subdev[0]->type; + concat->mtd.flags = subdev[0]->flags; + concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; - concat->mtd.oobblock = subdev[0]->oobblock; - concat->mtd.oobsize = subdev[0]->oobsize; - concat->mtd.ecctype = subdev[0]->ecctype; - concat->mtd.eccsize = subdev[0]->eccsize; - - concat->subdev[0] = subdev[0]; - - for(i = 1; i < num_devs; i++) - { - if(concat->mtd.type != subdev[i]->type) - { + concat->mtd.oobblock = subdev[0]->oobblock; + concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.ecctype = subdev[0]->ecctype; + concat->mtd.eccsize = subdev[0]->eccsize; + if (subdev[0]->read_ecc) + concat->mtd.read_ecc = concat_read_ecc; + if (subdev[0]->write_ecc) + concat->mtd.write_ecc = concat_write_ecc; + if (subdev[0]->read_oob) + concat->mtd.read_oob = concat_read_oob; + if (subdev[0]->write_oob) + concat->mtd.write_oob = concat_write_oob; + + concat->subdev[0] = subdev[0]; + + for (i = 1; i < num_devs; i++) { + if (concat->mtd.type != subdev[i]->type) { kfree(concat); - printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); + printk("Incompatible device type on \"%s\"\n", + subdev[i]->name); return NULL; } - if(concat->mtd.flags != subdev[i]->flags) - { /* - * Expect all flags except MTD_WRITEABLE to be equal on - * all subdevices. + if (concat->mtd.flags != subdev[i]->flags) { + /* + * Expect all flags except MTD_WRITEABLE to be + * equal on all subdevices. */ - if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) - { + if ((concat->mtd.flags ^ subdev[i]-> + flags) & ~MTD_WRITEABLE) { kfree(concat); - printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); + printk("Incompatible device flags on \"%s\"\n", + subdev[i]->name); return NULL; - } - else /* if writeable attribute differs, make super device writeable */ - concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; + } else + /* if writeable attribute differs, + make super device writeable */ + concat->mtd.flags |= + subdev[i]->flags & MTD_WRITEABLE; } concat->mtd.size += subdev[i]->size; - if(concat->mtd.oobblock != subdev[i]->oobblock || - concat->mtd.oobsize != subdev[i]->oobsize || - concat->mtd.ecctype != subdev[i]->ecctype || - concat->mtd.eccsize != subdev[i]->eccsize) - { + if (concat->mtd.oobblock != subdev[i]->oobblock || + concat->mtd.oobsize != subdev[i]->oobsize || + concat->mtd.ecctype != subdev[i]->ecctype || + concat->mtd.eccsize != subdev[i]->eccsize || + !concat->mtd.read_ecc != !subdev[i]->read_ecc || + !concat->mtd.write_ecc != !subdev[i]->write_ecc || + !concat->mtd.read_oob != !subdev[i]->read_oob || + !concat->mtd.write_oob != !subdev[i]->write_oob) { kfree(concat); - printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); + printk("Incompatible OOB or ECC data on \"%s\"\n", + subdev[i]->name); return NULL; } concat->subdev[i] = subdev[i]; - + } - concat->num_subdev = num_devs; - concat->mtd.name = name; + concat->num_subdev = num_devs; + concat->mtd.name = name; /* * NOTE: for now, we do not provide any readv()/writev() methods * because they are messy to implement and they are not * used to a great extent anyway. */ - concat->mtd.erase = concat_erase; - concat->mtd.read = concat_read; - concat->mtd.write = concat_write; - concat->mtd.sync = concat_sync; - concat->mtd.lock = concat_lock; - concat->mtd.unlock = concat_unlock; + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.sync = concat_sync; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; concat->mtd.suspend = concat_suspend; - concat->mtd.resume = concat_resume; - + concat->mtd.resume = concat_resume; /* * Combine the erase block size info of the subdevices: @@ -544,44 +753,44 @@ */ max_erasesize = curr_erasesize = subdev[0]->erasesize; num_erase_region = 1; - for(i = 0; i < num_devs; i++) - { - if(subdev[i]->numeraseregions == 0) - { /* current subdevice has uniform erase size */ - if(subdev[i]->erasesize != curr_erasesize) - { /* if it differs from the last subdevice's erase size, count it */ + for (i = 0; i < num_devs; i++) { + if (subdev[i]->numeraseregions == 0) { + /* current subdevice has uniform erase size */ + if (subdev[i]->erasesize != curr_erasesize) { + /* if it differs from the last subdevice's erase size, count it */ ++num_erase_region; curr_erasesize = subdev[i]->erasesize; - if(curr_erasesize > max_erasesize) + if (curr_erasesize > max_erasesize) max_erasesize = curr_erasesize; } - } - else - { /* current subdevice has variable erase size */ + } else { + /* current subdevice has variable erase size */ int j; - for(j = 0; j < subdev[i]->numeraseregions; j++) - { /* walk the list of erase regions, count any changes */ - if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) - { + for (j = 0; j < subdev[i]->numeraseregions; j++) { + + /* walk the list of erase regions, count any changes */ + if (subdev[i]->eraseregions[j].erasesize != + curr_erasesize) { ++num_erase_region; - curr_erasesize = subdev[i]->eraseregions[j].erasesize; - if(curr_erasesize > max_erasesize) + curr_erasesize = + subdev[i]->eraseregions[j]. + erasesize; + if (curr_erasesize > max_erasesize) max_erasesize = curr_erasesize; } } } } - if(num_erase_region == 1) - { /* + if (num_erase_region == 1) { + /* * All subdevices have the same uniform erase size. * This is easy: */ concat->mtd.erasesize = curr_erasesize; concat->mtd.numeraseregions = 0; - } - else - { /* + } else { + /* * erase block size varies across the subdevices: allocate * space to store the data describing the variable erase regions */ @@ -590,13 +799,14 @@ concat->mtd.erasesize = max_erasesize; concat->mtd.numeraseregions = num_erase_region; - concat->mtd.eraseregions = erase_region_p = kmalloc ( - num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); - if(!erase_region_p) - { + concat->mtd.eraseregions = erase_region_p = + kmalloc(num_erase_region * + sizeof (struct mtd_erase_region_info), GFP_KERNEL); + if (!erase_region_p) { kfree(concat); - printk ("memory allocation error while creating erase region list" - " for device \"%s\"\n", name); + printk + ("memory allocation error while creating erase region list" + " for device \"%s\"\n", name); return NULL; } @@ -606,46 +816,53 @@ */ curr_erasesize = subdev[0]->erasesize; begin = position = 0; - for(i = 0; i < num_devs; i++) - { - if(subdev[i]->numeraseregions == 0) - { /* current subdevice has uniform erase size */ - if(subdev[i]->erasesize != curr_erasesize) - { /* + for (i = 0; i < num_devs; i++) { + if (subdev[i]->numeraseregions == 0) { + /* current subdevice has uniform erase size */ + if (subdev[i]->erasesize != curr_erasesize) { + /* * fill in an mtd_erase_region_info structure for the area * we have walked so far: */ - erase_region_p->offset = begin; - erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = (position - begin) / curr_erasesize; + erase_region_p->offset = begin; + erase_region_p->erasesize = + curr_erasesize; + erase_region_p->numblocks = + (position - begin) / curr_erasesize; begin = position; curr_erasesize = subdev[i]->erasesize; ++erase_region_p; } position += subdev[i]->size; - } - else - { /* current subdevice has variable erase size */ + } else { + /* current subdevice has variable erase size */ int j; - for(j = 0; j < subdev[i]->numeraseregions; j++) - { /* walk the list of erase regions, count any changes */ - if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) - { - erase_region_p->offset = begin; - erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = (position - begin) / curr_erasesize; + for (j = 0; j < subdev[i]->numeraseregions; j++) { + /* walk the list of erase regions, count any changes */ + if (subdev[i]->eraseregions[j]. + erasesize != curr_erasesize) { + erase_region_p->offset = begin; + erase_region_p->erasesize = + curr_erasesize; + erase_region_p->numblocks = + (position - + begin) / curr_erasesize; begin = position; - curr_erasesize = subdev[i]->eraseregions[j].erasesize; + curr_erasesize = + subdev[i]->eraseregions[j]. + erasesize; ++erase_region_p; } - position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; + position += + subdev[i]->eraseregions[j]. + numblocks * curr_erasesize; } } } /* Now write the final entry */ - erase_region_p->offset = begin; + erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; erase_region_p->numblocks = (position - begin) / curr_erasesize; } @@ -660,15 +877,13 @@ void mtd_concat_destroy(struct mtd_info *mtd) { struct mtd_concat *concat = CONCAT(mtd); - if(concat->mtd.numeraseregions) + if (concat->mtd.numeraseregions) kfree(concat->mtd.eraseregions); kfree(concat); } - EXPORT_SYMBOL(mtd_concat_create); EXPORT_SYMBOL(mtd_concat_destroy); - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Kaiser "); diff -Nru a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c --- a/drivers/mtd/mtdcore.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/mtdcore.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.34 2003/01/24 23:32:25 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -17,6 +17,7 @@ #include #include #include +#include #include #ifdef CONFIG_PROC_FS #include @@ -24,9 +25,15 @@ #include -static DECLARE_MUTEX(mtd_table_mutex); -static struct mtd_info *mtd_table[MAX_MTD_DEVICES]; -static struct mtd_notifier *mtd_notifiers = NULL; +/* These are exported solely for the purpose of mtd_blkdevs.c. You + should not use them for _anything_ else */ +DECLARE_MUTEX(mtd_table_mutex); +struct mtd_info *mtd_table[MAX_MTD_DEVICES]; + +EXPORT_SYMBOL_GPL(mtd_table_mutex); +EXPORT_SYMBOL_GPL(mtd_table); + +static LIST_HEAD(mtd_notifiers); /** * add_mtd_device - register an MTD device @@ -44,21 +51,28 @@ down(&mtd_table_mutex); - for (i=0; i< MAX_MTD_DEVICES; i++) - if (!mtd_table[i]) - { - struct mtd_notifier *not=mtd_notifiers; + for (i=0; i < MAX_MTD_DEVICES; i++) + if (!mtd_table[i]) { + struct list_head *this; mtd_table[i] = mtd; mtd->index = i; + mtd->usecount = 0; + DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); - while (not) - { - (*(not->add))(mtd); - not = not->next; + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each(this, &mtd_notifiers) { + struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + not->add(mtd); } + up(&mtd_table_mutex); - MOD_INC_USE_COUNT; + /* We _know_ we aren't being removed, because + our caller is still holding us here. So none + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); return 0; } @@ -78,29 +92,34 @@ int del_mtd_device (struct mtd_info *mtd) { - struct mtd_notifier *not=mtd_notifiers; - int i; + int ret; down(&mtd_table_mutex); - for (i=0; i < MAX_MTD_DEVICES; i++) - { - if (mtd_table[i] == mtd) - { - while (not) - { - (*(not->remove))(mtd); - not = not->next; - } - mtd_table[i] = NULL; - up (&mtd_table_mutex); - MOD_DEC_USE_COUNT; - return 0; + if (mtd_table[mtd->index] != mtd) { + ret = -ENODEV; + } else if (mtd->usecount) { + printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", + mtd->index, mtd->name, mtd->usecount); + ret = -EBUSY; + } else { + struct list_head *this; + + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each(this, &mtd_notifiers) { + struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + not->remove(mtd); } + + mtd_table[mtd->index] = NULL; + + module_put(THIS_MODULE); + ret = 0; } up(&mtd_table_mutex); - return 1; + return ret; } /** @@ -118,10 +137,9 @@ down(&mtd_table_mutex); - new->next = mtd_notifiers; - mtd_notifiers = new; + list_add(&new->list, &mtd_notifiers); - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); for (i=0; i< MAX_MTD_DEVICES; i++) if (mtd_table[i]) @@ -142,34 +160,24 @@ int unregister_mtd_user (struct mtd_notifier *old) { - struct mtd_notifier **prev = &mtd_notifiers; - struct mtd_notifier *cur; int i; down(&mtd_table_mutex); - while ((cur = *prev)) { - if (cur == old) { - *prev = cur->next; - - MOD_DEC_USE_COUNT; - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (mtd_table[i]) - old->remove(mtd_table[i]); + module_put(THIS_MODULE); + + for (i=0; i< MAX_MTD_DEVICES; i++) + if (mtd_table[i]) + old->remove(mtd_table[i]); - up(&mtd_table_mutex); - return 0; - } - prev = &cur->next; - } + list_del(&old->list); up(&mtd_table_mutex); - return 1; + return 0; } /** - * __get_mtd_device - obtain a validated handle for an MTD device + * get_mtd_device - obtain a validated handle for an MTD device * @mtd: last known address of the required MTD device * @num: internal device number of the required MTD device * @@ -177,11 +185,10 @@ * table, if any. Given an address and num == -1, search the device table * for a device with that address and return if it's still present. Given * both, return the num'th driver only if its address matches. Return NULL - * if not. get_mtd_device() increases the use count, but - * __get_mtd_device() doesn't - you should generally use get_mtd_device(). + * if not. */ -struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num) +struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) { struct mtd_info *ret = NULL; int i; @@ -197,11 +204,28 @@ if (mtd && mtd != ret) ret = NULL; } - + + if (ret && !try_module_get(ret->owner)) + ret = NULL; + + if (ret) + ret->usecount++; + up(&mtd_table_mutex); return ret; } +void put_mtd_device(struct mtd_info *mtd) +{ + int c; + + down(&mtd_table_mutex); + c = --mtd->usecount; + up(&mtd_table_mutex); + BUG_ON(c < 0); + + module_put(mtd->owner); +} /* default_mtd_writev - default mtd writev method for MTD devices that * dont implement their own @@ -265,7 +289,8 @@ EXPORT_SYMBOL(add_mtd_device); EXPORT_SYMBOL(del_mtd_device); -EXPORT_SYMBOL(__get_mtd_device); +EXPORT_SYMBOL(get_mtd_device); +EXPORT_SYMBOL(put_mtd_device); EXPORT_SYMBOL(register_mtd_user); EXPORT_SYMBOL(unregister_mtd_user); EXPORT_SYMBOL(default_mtd_writev); diff -Nru a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/mtdpart.c Thu Dec 4 16:24:25 2003 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.32 2002/10/21 13:40:05 jocke Exp $ + * $Id: mtdpart.c,v 1.42 2003/07/09 11:19:01 dwmw2 Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob @@ -16,10 +16,11 @@ #include #include #include - +#include +#include #include #include - +#include /* Our partition linked list */ static LIST_HEAD(mtd_partitions); @@ -54,8 +55,12 @@ len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->read (part->master, from + part->offset, + if (part->master->read_ecc == NULL) + return part->master->read (part->master, from + part->offset, len, retlen, buf); + else + return part->master->read_ecc (part->master, from + part->offset, + len, retlen, buf, NULL, &mtd->oobinfo); } static int part_point (struct mtd_info *mtd, loff_t from, size_t len, @@ -78,9 +83,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel) + size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) { struct mtd_part *part = PART(mtd); + if (oobsel == NULL) + oobsel = &mtd->oobinfo; if (from >= mtd->size) len = 0; else if (from + len > mtd->size) @@ -113,7 +120,7 @@ size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, + return part->master->read_fact_prot_reg (part->master, from, len, retlen, buf); } @@ -127,17 +134,24 @@ len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write (part->master, to + part->offset, + if (part->master->write_ecc == NULL) + return part->master->write (part->master, to + part->offset, len, retlen, buf); + else + return part->master->write_ecc (part->master, to + part->offset, + len, retlen, buf, NULL, &mtd->oobinfo); + } static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, - u_char *eccbuf, int oobsel) + u_char *eccbuf, struct nand_oobinfo *oobsel) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; if (to >= mtd->size) len = 0; else if (to + len > mtd->size) @@ -174,25 +188,37 @@ struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - return part->master->writev (part->master, vecs, count, + if (part->master->writev_ecc == NULL) + return part->master->writev (part->master, vecs, count, to + part->offset, retlen); + else + return part->master->writev_ecc (part->master, vecs, count, + to + part->offset, retlen, + NULL, &mtd->oobinfo); } static int part_readv (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen) { struct mtd_part *part = PART(mtd); - return part->master->readv (part->master, vecs, count, + if (part->master->readv_ecc == NULL) + return part->master->readv (part->master, vecs, count, from + part->offset, retlen); + else + return part->master->readv_ecc (part->master, vecs, count, + from + part->offset, retlen, + NULL, &mtd->oobinfo); } static int part_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen, - u_char *eccbuf, int oobsel) + u_char *eccbuf, struct nand_oobinfo *oobsel) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; return part->master->writev_ecc (part->master, vecs, count, to + part->offset, retlen, eccbuf, oobsel); @@ -200,9 +226,11 @@ static int part_readv_ecc (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen, - u_char *eccbuf, int oobsel) + u_char *eccbuf, struct nand_oobinfo *oobsel) { struct mtd_part *part = PART(mtd); + if (oobsel == NULL) + oobsel = &mtd->oobinfo; return part->master->readv_ecc (part->master, vecs, count, from + part->offset, retlen, eccbuf, oobsel); @@ -288,7 +316,7 @@ */ int add_mtd_partitions(struct mtd_info *master, - struct mtd_partition *parts, + const struct mtd_partition *parts, int nbparts) { struct mtd_part *slave; @@ -321,7 +349,7 @@ slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; - slave->mtd.module = master->module; + slave->mtd.owner = master->owner; slave->mtd.read = part_read; slave->mtd.write = part_write; @@ -452,6 +480,75 @@ EXPORT_SYMBOL(add_mtd_partitions); EXPORT_SYMBOL(del_mtd_partitions); +static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(part_parsers); + +struct mtd_part_parser *get_partition_parser(const char *name) +{ + struct list_head *this; + void *ret = NULL; + spin_lock(&part_parser_lock); + + list_for_each(this, &part_parsers) { + struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list); + + if (!strcmp(p->name, name) && try_module_get(p->owner)) { + ret = p; + break; + } + } + spin_unlock(&part_parser_lock); + + return ret; +} + +int register_mtd_parser(struct mtd_part_parser *p) +{ + spin_lock(&part_parser_lock); + list_add(&p->list, &part_parsers); + spin_unlock(&part_parser_lock); + + return 0; +} + +int deregister_mtd_parser(struct mtd_part_parser *p) +{ + spin_lock(&part_parser_lock); + list_del(&p->list); + spin_unlock(&part_parser_lock); + return 0; +} + +int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, unsigned long origin) +{ + struct mtd_part_parser *parser; + int ret = 0; + + for ( ; ret <= 0 && *types; types++) { + parser = get_partition_parser(*types); +#ifdef CONFIG_KMOD + if (!parser && !request_module("%s", *types)) + parser = get_partition_parser(*types); +#endif + if (!parser) { + printk(KERN_NOTICE "%s partition parsing not available\n", + *types); + continue; + } + ret = (*parser->parse_fn)(master, pparts, origin); + if (ret > 0) { + printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", + ret, parser->name, master->name); + } + put_partition_parser(parser); + } + return ret; +} + +EXPORT_SYMBOL_GPL(parse_mtd_partitions); +EXPORT_SYMBOL_GPL(register_mtd_parser); +EXPORT_SYMBOL_GPL(deregister_mtd_parser); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nicolas Pitre "); diff -Nru a/drivers/mtd/nand/Config.in b/drivers/mtd/nand/Config.in --- a/drivers/mtd/nand/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/Config.in Thu Dec 4 16:24:25 2003 @@ -1,6 +1,6 @@ # drivers/mtd/nand/Config.in -# $Id: Config.in,v 1.11 2002/12/01 13:23:05 gleixner Exp $ +# $Id: Config.in,v 1.14 2003/11/04 22:59:11 ahennessy Exp $ mainmenu_option next_comment @@ -11,26 +11,27 @@ bool ' Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE fi -if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then - dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND +if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND $CONFIG_ARCH_P720T + dep_tristate ' NAND Flash device on TOTO board' CONFIG_MTD_NAND_TOTO $CONFIG_MTD_NAND $CONFIG_ARCH_OMAP + dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND $CONFIG_ARCH_AUTCPU12 + dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND $CONFIG_ARCH_EDB7312 fi -if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then - dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND -fi - -if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then - dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND -fi - -if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then +if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then define_bool CONFIG_MTD_NAND_IDS y +else + if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then + define_bool CONFIG_MTD_NAND_IDS m + fi fi -if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then -if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then - define_bool CONFIG_MTD_NAND_IDS m +if [ "$CONFIG_TOSHIBA_RBTX4925" = "y" ]; then + dep_tristate ' SmartMedia Card on Toshiba RBTX4925 reference board' CONFIG_MTD_NAND_TX4925NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4925_MPLEX_NAND fi + +if [ "$CONFIG_TOSHIBA_RBTX4938" = "y" ]; then + dep_tristate ' NAND Flash device on Toshiba RBTX4938 reference board' CONFIG_MTD_NAND_TX4938NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND fi endmenu diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile --- a/drivers/mtd/nand/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/Makefile Thu Dec 4 16:24:25 2003 @@ -1,16 +1,20 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $ +# $Id: Makefile.common,v 1.4 2003/11/04 22:59:11 ahennessy Exp $ -O_TARGET := nandlink.o - -export-objs := nand.o nand_ecc.o nand_ids.o +ifeq ($(PATCHLEVEL),4) +O_TARGET := nandlink.o +export-objs := nand.o nand_ecc.o nand_ids.o +endif obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o +obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o +obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o +obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o -include $(TOPDIR)/Rules.make +-include $(TOPDIR)/Rules.make diff -Nru a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c --- a/drivers/mtd/nand/autcpu12.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/autcpu12.c Thu Dec 4 16:24:25 2003 @@ -4,9 +4,9 @@ * Copyright (c) 2002 Thomas Gleixner * * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: autcpu12.c,v 1.6 2002/11/11 15:47:56 gleixner Exp $ + * $Id: autcpu12.c,v 1.13 2003/07/11 15:12:29 dwmw2 Exp $ * * 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 @@ -25,10 +25,10 @@ * added page_cache * * 10-06-2002 TG 128K card support added - * */ #include +#include #include #include #include @@ -70,6 +70,7 @@ /* * Define partitions for flash devices */ +extern struct nand_oobinfo jffs2_oobinfo; static struct mtd_partition partition_info16k[] = { { name: "AUTCPU12 flash partition 1", @@ -95,7 +96,7 @@ size: 16 * SZ_1M }, { name: "AUTCPU12 flash partition 2", offset: 16 * SZ_1M, - size: 48 * SZ_1M}, + size: 48 * SZ_1M }, }; static struct mtd_partition partition_info128k[] = { @@ -104,7 +105,7 @@ size: 16 * SZ_1M }, { name: "AUTCPU12 flash partition 2", offset: 16 * SZ_1M, - size: 112 * SZ_1M}, + size: 112 * SZ_1M }, }; #define NUM_PARTITIONS16K 2 @@ -114,7 +115,7 @@ /* * hardware specific access to control-lines */ -void autcpu12_hwcontrol(int cmd) +static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) { switch(cmd){ @@ -133,7 +134,7 @@ /* * read device ready pin */ -int autcpu12_device_ready(void) +int autcpu12_device_ready(struct mtd_info *mtd) { return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; @@ -184,7 +185,7 @@ this->eccmode = NAND_ECC_SOFT; /* Scan to find existance of the device */ - if (nand_scan (autcpu12_mtd)) { + if (nand_scan (autcpu12_mtd, 1)) { err = -ENXIO; goto out_ior; } @@ -197,15 +198,6 @@ goto out_ior; } - /* Allocate memory for internal data buffer */ - this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL); - if (!this->data_cache) { - printk ("Unable to allocate NAND data cache for AUTCPU12.\n"); - err = -ENOMEM; - goto out_buf; - } - this->cache_page = -1; - /* Register the partitions */ switch(autcpu12_mtd->size){ case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; @@ -215,13 +207,11 @@ default: { printk ("Unsupported SmartMedia device\n"); err = -ENXIO; - goto out_cac; + goto out_buf; } } goto out; -out_cac: - kfree (this->data_cache); out_buf: kfree (this->data_buf); out_ior: @@ -250,7 +240,6 @@ /* Free internal data buffers */ kfree (this->data_buf); - kfree (this->data_cache); /* unmap physical adress */ iounmap((void *)autcpu12_fio_base); diff -Nru a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c --- a/drivers/mtd/nand/edb7312.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/edb7312.c Thu Dec 4 16:24:25 2003 @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: edb7312.c,v 1.3 2002/06/06 12:58:16 mag Exp $ + * $Id: edb7312.c,v 1.7 2003/07/11 15:12:29 dwmw2 Exp $ * * 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 @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -77,16 +78,13 @@ }; #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); #endif /* * hardware specific access to control-lines */ -static void ep7312_hwcontrol(int cmd) +static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) { switch(cmd) { @@ -116,10 +114,13 @@ /* * read device ready pin */ -static int ep7312_device_ready(void) +static int ep7312_device_ready(struct mtd_info *mtd) { return 1; } +#ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif /* * Main initialization routine @@ -174,7 +175,7 @@ this->chip_delay = 15; /* Scan to find existence of the device */ - if (nand_scan (ep7312_mtd)) { + if (nand_scan (ep7312_mtd, 1)) { iounmap((void *)ep7312_fio_base); kfree (ep7312_mtd); return -ENXIO; @@ -189,27 +190,16 @@ return -ENOMEM; } - /* Allocate memory for internal data buffer */ - this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL); - if (!this->data_cache) { - printk("Unable to allocate NAND data cache for EDB7312.\n"); - kfree (this->data_buf); - iounmap((void *)ep7312_fio_base); - kfree (ep7312_mtd); - return -ENOMEM; - } - this->cache_page = -1; - -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, - "edb7312-nand"); +#ifdef CONFIG_PARTITIONS + ep7312_mtd->name = "edb7312-nand"; + mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, + &mtd_parts, 0); if (mtd_parts_nb > 0) - part_type = "command line"; + part_type = "command line"; else - mtd_parts_nb = 0; + mtd_parts_nb = 0; #endif - if (mtd_parts_nb == 0) - { + if (mtd_parts_nb == 0) { mtd_parts = partition_info; mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; @@ -236,7 +226,6 @@ /* Free internal data buffer */ kfree (this->data_buf); - kfree (this->data_cache); /* Free the MTD device structure */ kfree (ep7312_mtd); diff -Nru a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c --- a/drivers/mtd/nand/nand.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/nand.c Thu Dec 4 16:24:25 2003 @@ -8,7 +8,7 @@ * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * * 10-29-2001 Thomas Gleixner (tglx@linutronix.de) @@ -112,10 +112,27 @@ * for mtd->read_ecc / mtd->write_ecc * some minor cleanups * - * 12-05-2000 tglx: Dave Ellis (DGE@sixnetio) provided the fix for + * 12-05-2002 tglx: Dave Ellis (DGE@sixnetio) provided the fix for * WRITE_VERIFY long time ago. Thanks for remembering me. + * + * 02-14-2003 tglx: Reject non page aligned writes + * Fixed ecc select in nand_write_page to match semantics. + * + * 02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector + * + * 02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to + + a structure, which will be supplied by a filesystem driver + * If NULL is given, then the defaults (none or defaults + * supplied by ioctl (MEMSETOOBSEL) are used. + * For partitions the partition defaults are used (mtdpart.c) + * + * 06-04-2003 tglx: fix compile errors and fix write verify problem for + * some chips, which need either a delay between the readback + * and the next write command or have the CE removed. The + * CE disable/enable is much faster than a 20us delay and + * it should work on all available chips. * - * $Id: nand.c,v 1.36 2002/12/05 20:59:11 gleixner Exp $ + * $Id: nand.c,v 1.60 2003/10/23 08:28:43 dwmw2 Exp $ * * 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 @@ -130,102 +147,151 @@ #include #include #include +#include #include #include /* - * Macros for low-level register control - */ -#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); - -#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE); - -/* - * out of band configuration for different filesystems - */ -static int oobconfigs[][6] = { - { 0,0,0,0,0,0}, - - { NAND_JFFS2_OOB_ECCPOS0, NAND_JFFS2_OOB_ECCPOS1, NAND_JFFS2_OOB_ECCPOS2, - NAND_JFFS2_OOB_ECCPOS3, NAND_JFFS2_OOB_ECCPOS4, NAND_JFFS2_OOB_ECCPOS5 }, - - { NAND_YAFFS_OOB_ECCPOS0, NAND_YAFFS_OOB_ECCPOS1, NAND_YAFFS_OOB_ECCPOS2, - NAND_YAFFS_OOB_ECCPOS3, NAND_YAFFS_OOB_ECCPOS4, NAND_YAFFS_OOB_ECCPOS5 } -}; - -/* * NAND low-level MTD interface functions */ +static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); +static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); + static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel); + size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel); + size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t * retlen); static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel); + unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); static void nand_sync (struct mtd_info *mtd); -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col, - int last, u_char *oob_buf, int oobsel); +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel); + +static u_char nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + return readb(this->IO_ADDR_R); +} + +static void nand_write_byte(struct mtd_info *mtd, u_char byte) +{ + struct nand_chip *this = mtd->priv; + writeb(byte, this->IO_ADDR_W); +} + +static void nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + switch(chip) { + case -1: + this->hwcontrol(mtd, NAND_CTL_CLRNCE); + break; + case 0: + this->hwcontrol(mtd, NAND_CTL_SETNCE); + break; + + default: + BUG(); + } +} + +static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_W); +} + +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_R); +} + +static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i=0; iIO_ADDR_R)) + return i; + + return 0; +} + +/* Appropriate chip should already be selected */ +static int nand_block_bad(struct mtd_info *mtd, unsigned long page) +{ + struct nand_chip *this = mtd->priv; + + this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page); + if (this->read_byte(mtd) != 0xff) + return 1; + + return 0; +} + /* * Send command to NAND device */ static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) { register struct nand_chip *this = mtd->priv; - register unsigned long NAND_IO_ADDR = this->IO_ADDR_W; /* Begin command latch cycle */ - this->hwcontrol (NAND_CTL_SETCLE); + this->hwcontrol(mtd, NAND_CTL_SETCLE); /* * Write out the command to the device. */ - if (command != NAND_CMD_SEQIN) - writeb (command, NAND_IO_ADDR); - else { - if (mtd->oobblock == 256 && column >= 256) { - column -= 256; - writeb (NAND_CMD_READOOB, NAND_IO_ADDR); - writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); - } else if (mtd->oobblock == 512 && column >= 256) { - if (column < 512) { - column -= 256; - writeb (NAND_CMD_READ1, NAND_IO_ADDR); - writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); - } else { - column -= 512; - writeb (NAND_CMD_READOOB, NAND_IO_ADDR); - writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); - } + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->oobblock) { + /* OOB area */ + column -= mtd->oobblock; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; } else { - writeb (NAND_CMD_READ0, NAND_IO_ADDR); - writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); + column -= 256; + readcmd = NAND_CMD_READ1; } + this->write_byte(mtd, readcmd); } + this->write_byte(mtd, command); /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol (NAND_CTL_CLRCLE); + this->hwcontrol(mtd, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { - this->hwcontrol (NAND_CTL_SETALE); + this->hwcontrol(mtd, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) - writeb (column, NAND_IO_ADDR); + this->write_byte(mtd, column); if (page_addr != -1) { - writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR); - writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR); + this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); + this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); /* One more address cycle for higher density devices */ if (mtd->size & 0x0c000000) - writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR); + this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); } /* Latch in address */ - this->hwcontrol (NAND_CTL_CLRALE); + this->hwcontrol(mtd, NAND_CTL_CLRALE); } /* @@ -244,10 +310,11 @@ case NAND_CMD_RESET: if (this->dev_ready) break; - this->hwcontrol (NAND_CTL_SETCLE); - writeb (NAND_CMD_STATUS, NAND_IO_ADDR); - this->hwcontrol (NAND_CTL_CLRCLE); - while ( !(readb (this->IO_ADDR_R) & 0x40)); + udelay(this->chip_delay); + this->hwcontrol(mtd, NAND_CTL_SETCLE); + this->write_byte(mtd, NAND_CMD_STATUS); + this->hwcontrol(mtd, NAND_CTL_CLRCLE); + while ( !(this->read_byte(mtd) & 0x40)); return; /* This applies to read commands */ @@ -263,7 +330,7 @@ } /* wait until command is processed */ - while (!this->dev_ready()); + while (!this->dev_ready(mtd)); } /* @@ -288,17 +355,17 @@ spin_unlock_bh (&this->chip_lock); return; } - +#if 0 /* This was broken. And of dubious utility */ if (this->state == FL_ERASING) { if (new_state != FL_ERASING) { this->state = new_state; spin_unlock_bh (&this->chip_lock); - nand_select (); /* select in any case */ + this->select_chip(mtd, 0); /* select in any case */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); return; } } - +#endif set_current_state (TASK_UNINTERRUPTIBLE); add_wait_queue (&this->wq, &wait); spin_unlock_bh (&this->chip_lock); @@ -334,17 +401,17 @@ return 0; } if (this->dev_ready) { - if (this->dev_ready ()) + if (this->dev_ready(mtd)) break; } - if (readb (this->IO_ADDR_R) & 0x40) + if (this->read_byte(mtd) & 0x40) break; spin_unlock_bh (&this->chip_lock); yield (); spin_lock_bh (&this->chip_lock); } - status = (int) readb (this->IO_ADDR_R); + status = (int) this->read_byte(mtd); spin_unlock_bh (&this->chip_lock); return status; @@ -352,15 +419,16 @@ /* * Nand_page_program function is used for write and writev ! + * This function will always program a full page of data + * If you call it with a non page aligned buffer, you're lost :) */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, - int page, int col, int last, u_char *oob_buf, int oobsel) +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel) { int i, status; u_char ecc_code[6], *oob_data; - int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE; - int *oob_config = oobconfigs[oobsel]; - + int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; + int *oob_config = oobsel->eccpos; + /* pad oob area, if we have no oob buffer from fs-driver */ if (!oob_buf) { oob_data = &this->data_buf[mtd->oobblock]; @@ -369,66 +437,42 @@ } else oob_data = oob_buf; - /* software ecc 3 Bytes ECC / 256 Byte Data ? */ - if (eccmode == NAND_ECC_SOFT) { - /* Read back previous written data, if col > 0 */ - if (col) { - this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); - for (i = 0; i < col; i++) - this->data_poi[i] = readb (this->IO_ADDR_R); - } - if ((col < this->eccsize) && (last >= this->eccsize)) { - this->calculate_ecc (&this->data_poi[0], &(ecc_code[0])); - for (i = 0; i < 3; i++) - oob_data[oob_config[i]] = ecc_code[i]; - } - /* Calculate and write the second ECC if we have enough data */ - if ((mtd->oobblock == 512) && (last == 512)) { - this->calculate_ecc (&this->data_poi[256], &(ecc_code[3])); - for (i = 3; i < 6; i++) - oob_data[oob_config[i]] = ecc_code[i]; - } - } else { - /* For hardware ECC skip ECC, if we have no full page write */ - if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock)) - eccmode = NAND_ECC_NONE; - } - - /* Prepad for partial page programming !!! */ - for (i = 0; i < col; i++) - this->data_poi[i] = 0xff; - - /* Postpad for partial page programming !!! oob is already padded */ - for (i = last; i < mtd->oobblock; i++) - this->data_poi[i] = 0xff; - /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); /* Write out complete page of data, take care of eccmode */ - switch (this->eccmode) { + switch (eccmode) { /* No ecc and software ecc 3/256, write all */ case NAND_ECC_NONE: + printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); + this->write_buf(mtd, this->data_poi, mtd->oobblock); + break; case NAND_ECC_SOFT: - for (i = 0; i < mtd->oobblock; i++) - writeb ( this->data_poi[i] , this->IO_ADDR_W); + this->calculate_ecc(mtd, &this->data_poi[0], &(ecc_code[0])); + for (i = 0; i < 3; i++) + oob_data[oob_config[i]] = ecc_code[i]; + /* Calculate and write the second ECC for 512 Byte page size */ + if (mtd->oobblock == 512) { + this->calculate_ecc(mtd, &this->data_poi[256], &(ecc_code[3])); + for (i = 3; i < 6; i++) + oob_data[oob_config[i]] = ecc_code[i]; + } + this->write_buf(mtd, this->data_poi, mtd->oobblock); break; /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */ case NAND_ECC_HW3_256: - this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write */ - for (i = 0; i < mtd->eccsize; i++) - writeb ( this->data_poi[i] , this->IO_ADDR_W); + this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */ + this->write_buf(mtd, this->data_poi, mtd->eccsize); - this->calculate_ecc (NULL, &(ecc_code[0])); + this->calculate_ecc(mtd, NULL, &(ecc_code[0])); for (i = 0; i < 3; i++) oob_data[oob_config[i]] = ecc_code[i]; if (mtd->oobblock == 512) { - this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ - for (i = mtd->eccsize; i < mtd->oobblock; i++) - writeb ( this->data_poi[i] , this->IO_ADDR_W); - this->calculate_ecc (NULL, &(ecc_code[3])); + this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ + this->write_buf(mtd, &this->data_poi[mtd->eccsize], mtd->oobblock - mtd->eccsize); + this->calculate_ecc(mtd, NULL, &(ecc_code[3])); for (i = 3; i < 6; i++) oob_data[oob_config[i]] = ecc_code[i]; } @@ -436,20 +480,18 @@ /* Hardware ecc 3 byte / 512 byte data, write full page */ case NAND_ECC_HW3_512: - this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ - for (i = 0; i < mtd->oobblock; i++) - writeb ( this->data_poi[i] , this->IO_ADDR_W); - this->calculate_ecc (NULL, &(ecc_code[0])); + this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ + this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->calculate_ecc(mtd, NULL, &(ecc_code[0])); for (i = 0; i < 3; i++) oob_data[oob_config[i]] = ecc_code[i]; break; /* Hardware ecc 6 byte / 512 byte data, write full page */ case NAND_ECC_HW6_512: - this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ - for (i = 0; i < mtd->oobblock; i++) - writeb ( this->data_poi[i] , this->IO_ADDR_W); - this->calculate_ecc (NULL, &(ecc_code[0])); + this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ + this->write_buf(mtd, this->data_poi, mtd->oobblock); + this->calculate_ecc(mtd, NULL, &(ecc_code[0])); for (i = 0; i < 6; i++) oob_data[oob_config[i]] = ecc_code[i]; break; @@ -460,8 +502,7 @@ } /* Write out OOB data */ - for (i = 0; i < mtd->oobsize; i++) - writeb ( oob_data[i] , this->IO_ADDR_W); + this->write_buf(mtd, oob_data, mtd->oobsize); /* Send command to actually program the data */ this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); @@ -490,25 +531,21 @@ */ /* Send command to read back the page */ - this->cmdfunc (mtd, NAND_CMD_READ0, col, page); + this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); /* Loop through and verify the data */ - for (i = col; i < last; i++) { - if (this->data_poi[i] != readb (this->IO_ADDR_R)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); - return -EIO; - } + if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + return -EIO; } /* check, if we have a fs-supplied oob-buffer */ if (oob_buf) { - for (i = 0; i < mtd->oobsize; i++) { - if (oob_data[i] != readb (this->IO_ADDR_R)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); - return -EIO; - } + if (this->verify_buf(mtd, oob_data, mtd->oobsize)) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + return -EIO; } } else { - if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) { + if (eccmode != NAND_ECC_NONE) { int ecc_bytes = 0; switch (this->eccmode) { @@ -518,8 +555,7 @@ case NAND_ECC_HW6_512: ecc_bytes = 6; break; } - for (i = 0; i < mtd->oobsize; i++) - oob_data[i] = readb (this->IO_ADDR_R); + this->read_buf(mtd, oob_data, mtd->oobsize); for (i = 0; i < ecc_bytes; i++) { if (oob_data[oob_config[i]] != ecc_code[i]) { @@ -531,6 +567,13 @@ } } } + /* + * Terminate the read command. This is faster than sending a reset command or + * applying a 20us delay before issuing the next programm sequence. + * This is not a problem for all chips, but I have found a bunch of them. + */ + this->select_chip(mtd, -1); + this->select_chip(mtd, 0); #endif return 0; } @@ -540,7 +583,7 @@ */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, 0)); + return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); } @@ -548,7 +591,7 @@ * NAND read with ECC */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * oob_buf, int oobsel) + size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { int j, col, page, end, ecc; int erase_state = 0; @@ -557,10 +600,16 @@ u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[6]; u_char ecc_code[6]; - int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE; + int eccmode; + int *oob_config; + + // use chip default if zero + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; + oob_config = oobsel->eccpos; - int *oob_config = oobconfigs[oobsel]; - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ @@ -574,7 +623,7 @@ nand_get_chip (this, mtd ,FL_READING, &erase_state); /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); /* First we calculate the starting page */ page = from >> this->page_shift; @@ -596,7 +645,7 @@ if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready()); + while (!this->dev_ready(mtd)); } /* @@ -616,39 +665,40 @@ j = 0; switch (eccmode) { - case NAND_ECC_NONE: /* No ECC, Read in a page */ - while (j < end) - data_poi[j++] = readb (this->IO_ADDR_R); + case NAND_ECC_NONE: { /* No ECC, Read in a page */ + static unsigned long lastwhinge = 0; + if ((lastwhinge / HZ) != (jiffies / HZ)) { + printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n"); + lastwhinge = jiffies; + } + this->read_buf(mtd, data_poi, end); break; + } case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ - while (j < end) - data_poi[j++] = readb (this->IO_ADDR_R); - this->calculate_ecc (&data_poi[0], &ecc_calc[0]); + this->read_buf(mtd, data_poi, end); + this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); if (mtd->oobblock == 512) - this->calculate_ecc (&data_poi[256], &ecc_calc[3]); + this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); break; case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */ - this->enable_hwecc (NAND_ECC_READ); - while (j < ecc) - data_poi[j++] = readb (this->IO_ADDR_R); - this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ + this->enable_hwecc(mtd, NAND_ECC_READ); + this->read_buf(mtd, data_poi, ecc); + this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */ - this->enable_hwecc (NAND_ECC_READ); - while (j < end) - data_poi[j++] = readb (this->IO_ADDR_R); - this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */ + this->enable_hwecc(mtd, NAND_ECC_READ); + this->read_buf(mtd, &data_poi[ecc], end-ecc); + this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); /* read from hardware */ } break; case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */ - this->enable_hwecc (NAND_ECC_READ); - while (j < end) - data_poi[j++] = readb (this->IO_ADDR_R); - this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ + this->enable_hwecc(mtd, NAND_ECC_READ); + this->read_buf(mtd, data_poi, end); + this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ break; default: @@ -658,7 +708,7 @@ /* read oobdata */ for (j = 0; j < mtd->oobsize; j++) - oob_data[oob + j] = readb (this->IO_ADDR_R); + oob_data[oob + j] = this->read_byte(mtd); /* Skip ECC, if not active */ if (eccmode == NAND_ECC_NONE) @@ -669,7 +719,7 @@ ecc_code[j] = oob_data[oob + oob_config[j]]; /* correct data, if neccecary */ - ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]); + ecc_status = this->correct_data(mtd, &data_poi[0], &ecc_code[0], &ecc_calc[0]); /* check, if we have a fs supplied oob-buffer */ if (oob_buf) { oob += mtd->oobsize; @@ -682,7 +732,7 @@ } if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) { - ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]); + ecc_status = this->correct_data(mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]); if (oob_buf) { *((int *)&oob_data[oob]) = ecc_status; oob += sizeof(int); @@ -705,7 +755,7 @@ } /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); @@ -753,7 +803,7 @@ nand_get_chip (this, mtd , FL_READING, &erase_state); /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page); @@ -761,13 +811,20 @@ * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ - for (i = 0; i < len; i++) { - buf[i] = readb (this->IO_ADDR_R); - if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1)) - udelay (this->chip_delay); + i = 0; + while (i < len) { + int thislen = (mtd->oobsize - col) & (mtd->oobsize - 1); + if (!thislen) + thislen = mtd->oobsize; + thislen = min_t(int, thislen, len); + this->read_buf(mtd, &buf[i], thislen); + i += thislen; + col += thislen; + /* Delay between pages */ + udelay (this->chip_delay); } /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); @@ -780,45 +837,54 @@ return 0; } +#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0 + /* * Use NAND write ECC */ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { - return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 0)); + return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); } /* * NAND write with ECC */ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel) + size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) { - int i, page, col, cnt, ret = 0, oob = 0, written = 0; + int page, ret = 0, oob = 0, written = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Do not allow write past end of device */ if ((to + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } + /* reject writes, which are not page aligned */ + if (NOTALIGNED (to) || NOTALIGNED(len)) { + printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } + + // if oobsel is NULL, use chip defaults + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Shift to get page */ page = ((int) to) >> this->page_shift; - /* Get the starting column */ - col = to & (mtd->oobblock - 1); - /* Grab the lock and see if the device is available */ nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR_R) & 0x80)) { + if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); ret = -EIO; goto out; @@ -826,42 +892,27 @@ /* Loop until all data is written */ while (written < len) { - /* - * Check, if we have a full page write, then we can - * use the given buffer, else we have to copy - */ - if (!col && (len - written) >= mtd->oobblock) { - this->data_poi = (u_char*) &buf[written]; - cnt = mtd->oobblock; - } else { - cnt = 0; - for (i = col; i < len && i < mtd->oobblock; i++) { - this->data_buf[i] = buf[written + i]; - cnt++; - } - this->data_poi = this->data_buf; - } - /* We use the same function for write and writev !) */ + int cnt = mtd->oobblock; + this->data_poi = (u_char*) &buf[written]; + /* We use the same function for write and writev */ if (eccbuf) { - ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel); + ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel); oob += mtd->oobsize; } else - ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel); + ret = nand_write_page (mtd, this, page, NULL, oobsel); if (ret) goto out; /* Update written bytes count */ written += cnt; - /* Next write is aligned */ - col = 0; /* Increment page address */ page++; } out: /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); @@ -873,13 +924,21 @@ return ret; } +static u_char ffchars[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + /* * NAND write out-of-band */ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { - int i, column, page, status, ret = 0; + int column, page, status, ret = 0; struct nand_chip *this = mtd->priv; +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + int i; +#endif DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -902,27 +961,31 @@ nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); + + /* Reset the chip. Some chips (like the Toshiba TC5832DC found + in one of my DiskOnChip 2000 test units) will clear the whole + data page too if we don't do this. I have no clue why, but + I seem to have 'fixed' it in the doc2000 driver in + August 1999. dwmw2. */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR_R) & 0x80)) { + if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); ret = -EIO; goto out; } - /* Write out desired data */ this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); + /* prepad 0xff for partial programming */ - for (i = 0; i < column; i++) - writeb (0xff, this->IO_ADDR_W); + this->write_buf(mtd, ffchars, column); /* write data */ - for (i = 0; i < len; i++) - writeb (buf[i], this->IO_ADDR_W); + this->write_buf(mtd, buf, len); /* postpad 0xff for partial programming */ - for (i = len + column; i < mtd->oobsize; i++) - writeb (0xff, this->IO_ADDR_W); + this->write_buf(mtd, ffchars, mtd->oobsize - (len+column)); /* Send command to program the OOB data */ this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); @@ -944,7 +1007,7 @@ /* Loop through and verify the data */ for (i = 0; i < len; i++) { - if (buf[i] != readb (this->IO_ADDR_R)) { + if (buf[i] != this->read_byte(mtd)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; @@ -954,7 +1017,7 @@ out: /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); @@ -976,9 +1039,9 @@ } static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, - loff_t to, size_t * retlen, u_char *eccbuf, int oobsel) + loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { - int i, page, col, cnt, len, total_len, ret = 0, written = 0; + int i, page, len, total_len, ret = 0, written = 0; struct nand_chip *this = mtd->priv; /* Calculate total length of data */ @@ -995,39 +1058,42 @@ return -EINVAL; } + /* reject writes, which are not page aligned */ + if (NOTALIGNED (to) || NOTALIGNED(total_len)) { + printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } + + // if oobsel is NULL, use chip defaults + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Shift to get page */ page = ((int) to) >> this->page_shift; - /* Get the starting column */ - col = to & (mtd->oobblock - 1); - /* Grab the lock and see if the device is available */ nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR_R) & 0x80)) { + if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Loop until all iovecs' data has been written */ - cnt = col; len = 0; - while (count) { /* - * Check, if we write from offset 0 and if the tuple - * gives us not enough data for a full page write. Then we - * can use the iov direct, else we have to copy into - * data_buf. + * Check, if the tuple gives us not enough data for a + * full page write. Then we can use the iov direct, + * else we have to copy into data_buf. */ - if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) { - cnt = mtd->oobblock; + if ((vecs->iov_len - len) >= mtd->oobblock) { this->data_poi = (u_char *) vecs->iov_base; this->data_poi += len; len += mtd->oobblock; @@ -1042,6 +1108,7 @@ * Read data out of each tuple until we have a full page * to write or we've read all the tuples. */ + int cnt = 0; while ((cnt < mtd->oobblock) && count) { if (vecs->iov_base != NULL && vecs->iov_len) { this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; @@ -1057,15 +1124,12 @@ } /* We use the same function for write and writev !) */ - ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel); + ret = nand_write_page (mtd, this, page, NULL, oobsel); if (ret) goto out; /* Update written bytes count */ - written += (cnt - col); - - /* Reset written byte counter and column */ - col = cnt = 0; + written += mtd->oobblock;; /* Increment page address */ page++; @@ -1073,7 +1137,7 @@ out: /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); @@ -1125,11 +1189,11 @@ pages_per_block = mtd->erasesize / mtd->oobblock; /* Select the NAND device */ - nand_select (); + this->select_chip(mtd, 0); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR_R) & 0x80)) { + if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -1142,8 +1206,7 @@ while (len) { /* Check if we have a bad block, we do not erase bad blocks ! */ - this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page); - if (readb (this->IO_ADDR_R) != 0xff) { + if (this->block_bad(mtd, page)) { printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -1179,7 +1242,7 @@ if (this->state == FL_ERASING || this->state == FL_READY) { /* Select the NAND device again, if we were interrupted */ this->state = FL_ERASING; - nand_select (); + this->select_chip(mtd, 0); continue; } else { set_current_state (TASK_UNINTERRUPTIBLE); @@ -1194,7 +1257,7 @@ erase_exit: /* De-select the NAND device */ - nand_deselect (); + this->select_chip(mtd, -1); spin_unlock_bh (&this->chip_lock); ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;; @@ -1205,6 +1268,7 @@ /* The device is ready */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; + wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); /* Return more or less happy */ @@ -1259,7 +1323,7 @@ /* * Scan for the NAND device */ -int nand_scan (struct mtd_info *mtd) +int nand_scan (struct mtd_info *mtd, int maxchips) { int i, nand_maf_id, nand_dev_id; struct nand_chip *this = mtd->priv; @@ -1276,23 +1340,38 @@ if (this->waitfunc == NULL) this->waitfunc = nand_wait; + if (!this->block_bad) + this->block_bad = nand_block_bad; + if (!this->select_chip) + this->select_chip = nand_select_chip; + if (!this->write_byte) + this->write_byte = nand_write_byte; + if (!this->read_byte) + this->read_byte = nand_read_byte; + if (!this->write_buf) + this->write_buf = nand_write_buf; + if (!this->read_buf) + this->read_buf = nand_read_buf; + if (!this->verify_buf) + this->verify_buf = nand_verify_buf; + /* Select the device */ - nand_select (); + this->select_chip(mtd, 0); /* Send the command for reading device ID */ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ - nand_maf_id = readb (this->IO_ADDR_R); - nand_dev_id = readb (this->IO_ADDR_R); + nand_maf_id = this->read_byte(mtd); + nand_dev_id = this->read_byte(mtd); /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; - mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; + this->chipshift = nand_flash_ids[i].chipshift; if (nand_flash_ids[i].page256) { mtd->oobblock = 256; mtd->oobsize = 8; @@ -1307,13 +1386,34 @@ if (nand_manuf_ids[i].id == nand_maf_id) break; } - printk (KERN_INFO "NAND device: Manufacture ID:" + printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[i].name , mtd->name); break; } } + if (!mtd->name) { + printk (KERN_WARNING "No NAND device found!!!\n"); + return 1; + } + + for (i=1; i < maxchips; i++) { + this->select_chip(mtd, i); + + /* Send the command for reading device ID */ + this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + if (nand_maf_id != this->read_byte(mtd) || + nand_dev_id != this->read_byte(mtd)) + break; + } + if (i > 1) + printk(KERN_INFO "%d NAND chips detected\n", i); + + mtd->size = (1 << this->chipshift) /* * i when we fix the rest of the code */; + /* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize @@ -1324,6 +1424,7 @@ switch (this->eccmode) { case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: if (mtd->oobblock == 256) { printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; @@ -1340,6 +1441,7 @@ BUG(); case NAND_ECC_NONE: + printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); this->eccmode = NAND_ECC_NONE; break; @@ -1352,25 +1454,18 @@ printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); BUG(); } - + /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; init_waitqueue_head (&this->wq); spin_lock_init (&this->chip_lock); /* De-select the device */ - nand_deselect (); - - /* Print warning message for no device */ - if (!mtd->size) { - printk (KERN_WARNING "No NAND device found!!!\n"); - return 1; - } + this->select_chip(mtd, -1); /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; - mtd->module = THIS_MODULE; mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; @@ -1389,6 +1484,7 @@ mtd->unlock = NULL; mtd->suspend = NULL; mtd->resume = NULL; + mtd->owner = THIS_MODULE; /* Return happy */ return 0; @@ -1397,5 +1493,5 @@ EXPORT_SYMBOL (nand_scan); MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("Steven J. Hill , Thomas Gleixner "); +MODULE_AUTHOR ("Steven J. Hill , Thomas Gleixner "); MODULE_DESCRIPTION ("Generic NAND flash driver code"); diff -Nru a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c --- a/drivers/mtd/nand/nand_ecc.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/nand_ecc.c Thu Dec 4 16:24:25 2003 @@ -1,10 +1,10 @@ /* * drivers/mtd/nand_ecc.c * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * Toshiba America Electronics Components, Inc. * - * $Id: nand_ecc.c,v 1.8 2002/09/16 09:19:53 dwmw2 Exp $ + * $Id: nand_ecc.c,v 1.10 2003/07/01 23:31:15 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -17,6 +17,7 @@ #include #include #include +#include /* * Pre-calculated 256-way 1 byte column parity @@ -84,7 +85,7 @@ /* * Calculate 3 byte ECC code for 256 byte block */ -void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) +void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { u_char idx, reg1, reg2, reg3; int j; @@ -119,7 +120,7 @@ /* * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) +int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { u_char a, b, c, d1, d2, d3, add, bit, i; @@ -209,5 +210,5 @@ EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill "); +MODULE_AUTHOR("Steven J. Hill "); MODULE_DESCRIPTION("Generic NAND ECC support"); diff -Nru a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c --- a/drivers/mtd/nand/nand_ids.c Thu Dec 4 16:24:26 2003 +++ b/drivers/mtd/nand/nand_ids.c Thu Dec 4 16:24:26 2003 @@ -4,7 +4,7 @@ * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * * - * $Id: nand_ids.c,v 1.1 2002/12/02 22:06:04 gleixner Exp $ + * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $ * * 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 @@ -18,21 +18,21 @@ * Chip ID list */ struct nand_flash_dev nand_flash_ids[] = { - {"NAND 1MB 5V", 0x6e, 20, 0x1000, 1}, // 1Mb 5V - {"NAND 2MB 5V", 0x64, 21, 0x1000, 1}, // 2Mb 5V - {"NAND 4MB 5V", 0x6b, 22, 0x2000, 0}, // 4Mb 5V - {"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1}, // 1Mb 3.3V - {"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1}, // 1Mb 3.3V - {"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1}, // 2Mb 3.3V - {"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0}, // 4Mb 3.3V - {"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0}, // 4Mb 3.3V - {"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0}, // 4Mb 3.3V - {"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0}, // 8Mb 3.3V - {"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0}, // 8Mb 3.3V - {"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V - {"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V - {"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V - {"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V + {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1}, + {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1}, + {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0}, + {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1}, + {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1}, + {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1}, + {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0}, + {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0}, + {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0}, + {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0}, + {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0}, + {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0}, + {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0}, + {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0}, + {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0}, {NULL,} }; diff -Nru a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c --- a/drivers/mtd/nand/spia.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nand/spia.c Thu Dec 4 16:24:25 2003 @@ -1,14 +1,14 @@ /* * drivers/mtd/nand/spia.c * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * * * 10-29-2001 TG change to support hardwarespecific access * to controllines (due to change in nand.c) * page_cache added * - * $Id: spia.c,v 1.16 2002/03/05 13:50:47 dwmw2 Exp $ + * $Id: spia.c,v 1.21 2003/07/11 15:12:29 dwmw2 Exp $ * * 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 @@ -20,6 +20,8 @@ * a 64Mibit (8MiB x 8 bits) NAND flash device. */ +#include +#include #include #include #include @@ -35,14 +37,14 @@ /* * Values specific to the SPIA board (used with EP7212 processor) */ -#define SPIA_IO_ADDR = 0xd0000000 /* Start of EP7212 IO address space */ -#define SPIA_FIO_ADDR = 0xf0000000 /* Address where flash is mapped */ -#define SPIA_PEDR = 0x0080 /* +#define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */ +#define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */ +#define SPIA_PEDR 0x0080 /* * IO offset to Port E data register * where the CLE, ALE and NCE pins * are wired to. */ -#define SPIA_PEDDR = 0x00c0 /* +#define SPIA_PEDDR 0x00c0 /* * IO offset to Port E data direction * register so we can control the IO * lines. @@ -62,21 +64,20 @@ MODULE_PARM(spia_pedr, "i"); MODULE_PARM(spia_peddr, "i"); -__setup("spia_io_base=",spia_io_base); -__setup("spia_fio_base=",spia_fio_base); -__setup("spia_pedr=",spia_pedr); -__setup("spia_peddr=",spia_peddr); - /* * Define partitions for flash device */ const static struct mtd_partition partition_info[] = { - { name: "SPIA flash partition 1", - offset: 0, - size: 2*1024*1024 }, - { name: "SPIA flash partition 2", - offset: 2*1024*1024, - size: 6*1024*1024 } + { + .name = "SPIA flash partition 1", + .offset = 0, + .size = 2*1024*1024 + }, + { + .name = "SPIA flash partition 2", + .offset = 2*1024*1024, + .size = 6*1024*1024 + } }; #define NUM_PARTITIONS 2 @@ -84,7 +85,7 @@ /* * hardware specific access to control-lines */ -void spia_hwcontrol(int cmd){ +static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ switch(cmd){ @@ -139,7 +140,7 @@ this->chip_delay = 15; /* Scan to find existence of the device */ - if (nand_scan (spia_mtd)) { + if (nand_scan (spia_mtd, 1)) { kfree (spia_mtd); return -ENXIO; } @@ -152,16 +153,6 @@ return -ENOMEM; } - /* Allocate memory for internal data buffer */ - this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL); - if (!this->data_cache) { - printk ("Unable to allocate NAND data cache for SPIA.\n"); - kfree (this->data_buf); - kfree (spia_mtd); - return = -ENOMEM; - } - this->cache_page = -1; - /* Register the partitions */ add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS); @@ -183,7 +174,6 @@ /* Free internal data buffer */ kfree (this->data_buf); - kfree (this->page_cache); /* Free the MTD device structure */ kfree (spia_mtd); @@ -192,5 +182,5 @@ #endif MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill */ -/* $Id: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU General @@ -23,15 +23,13 @@ #include #include #include -#include +#include -#ifdef CONFIG_KMOD #include -#endif #include #include #include -#include +#include /* maximum number of loops while examining next block, to have a chance to detect consistency problems (they should never happen @@ -39,189 +37,97 @@ #define MAX_LOOPS 10000 -/* NFTL block device stuff */ -#define MAJOR_NR NFTL_MAJOR -#define DEVICE_REQUEST nftl_request -#define DEVICE_OFF(device) - - -#include -#include - -/* Linux-specific block device functions */ - -/* I _HATE_ the Linux block device setup more than anything else I've ever - * encountered, except ... - */ - -static int nftl_sizes[256]; -static int nftl_blocksizes[256]; - -/* .. for the Linux partition table handling. */ -struct hd_struct part_table[256]; - -#if LINUX_VERSION_CODE < 0x20328 -static void dummy_init (struct gendisk *crap) -{} -#endif - -static struct gendisk nftl_gendisk = { - major: MAJOR_NR, - major_name: "nftl", - minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */ - max_p: (1<mtd == mtd) { - /* This is a Spare Media Header for an NFTL we've already found */ - DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n"); - return; - } - } - if (firstfree == -1) { - printk(KERN_WARNING "No more NFTL slot available\n"); + if (mtd->ecctype != MTD_ECC_RS_DiskOnChip) return; - } + + DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); + if (!nftl) { - printk(KERN_WARNING "Out of memory for NFTL data structures\n"); + printk(KERN_WARNING "NFTL: out of memory for data structures\n"); return; } + memset(nftl, 0, sizeof(*nftl)); - init_MUTEX(&nftl->mutex); - - nftl->mtd = mtd; + nftl->mbd.mtd = mtd; + nftl->mbd.devnum = -1; + nftl->mbd.blksize = 512; + nftl->mbd.tr = tr; if (NFTL_mount(nftl) < 0) { - printk(KERN_WARNING "Could not mount NFTL device\n"); + printk(KERN_WARNING "NFTL: could not mount device\n"); kfree(nftl); return; } /* OK, it's a new one. Set up all the data structures. */ -#ifdef PSYCHO_DEBUG - printk("Found new NFTL nftl%c\n", firstfree + 'a'); -#endif - /* linux stuff */ - nftl->usecount = 0; + /* Calculate geometry */ nftl->cylinders = 1024; nftl->heads = 16; temp = nftl->cylinders * nftl->heads; - nftl->sectors = nftl->nr_sects / temp; - if (nftl->nr_sects % temp) { + nftl->sectors = nftl->mbd.size / temp; + if (nftl->mbd.size % temp) { nftl->sectors++; temp = nftl->cylinders * nftl->sectors; - nftl->heads = nftl->nr_sects / temp; + nftl->heads = nftl->mbd.size / temp; - if (nftl->nr_sects % temp) { + if (nftl->mbd.size % temp) { nftl->heads++; temp = nftl->heads * nftl->sectors; - nftl->cylinders = nftl->nr_sects / temp; + nftl->cylinders = nftl->mbd.size / temp; } } - if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) { - printk(KERN_WARNING "Cannot calculate an NFTL geometry to " - "match size of 0x%x.\n", nftl->nr_sects); - printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", - nftl->cylinders, nftl->heads , nftl->sectors, - (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors ); + if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { + /* + Oh no we don't have + mbd.size == heads * cylinders * sectors + */ + printk(KERN_WARNING "NFTL: cannot calculate a geometry to " + "match size of 0x%lx.\n", nftl->mbd.size); + printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " + "(== 0x%lx sects)\n", + nftl->cylinders, nftl->heads , nftl->sectors, + (long)nftl->cylinders * (long)nftl->heads * + (long)nftl->sectors ); + } - /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */ + if (add_mtd_blktrans_dev(&nftl->mbd)) { + if (nftl->ReplUnitTable) + kfree(nftl->ReplUnitTable); + if (nftl->EUNtable) + kfree(nftl->EUNtable); + kfree(nftl); + return; } - NFTLs[firstfree] = nftl; - /* Finally, set up the block device sizes */ - nftl_sizes[firstfree * 16] = nftl->nr_sects; - //nftl_blocksizes[firstfree*16] = 512; - part_table[firstfree * 16].nr_sects = nftl->nr_sects; - - nftl_gendisk.nr_real++; - - /* partition check ... */ -#if LINUX_VERSION_CODE < 0x20328 - resetup_one_dev(&nftl_gendisk, firstfree); -#else - grok_partitions(&nftl_gendisk, firstfree, 1<nr_sects); +#ifdef PSYCHO_DEBUG + printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); #endif } -static void NFTL_unsetup(int i) +static void nftl_remove_dev(struct mtd_blktrans_dev *dev) { - struct NFTLrecord *nftl = NFTLs[i]; + struct NFTLrecord *nftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i); - - NFTLs[i] = NULL; - + DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); + + del_mtd_blktrans_dev(dev); if (nftl->ReplUnitTable) kfree(nftl->ReplUnitTable); if (nftl->EUNtable) kfree(nftl->EUNtable); - - nftl_gendisk.nr_real--; kfree(nftl); } -/* Search the MTD device for NFTL partitions */ -static void NFTL_notify_add(struct mtd_info *mtd) -{ - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name); - - if (mtd) { - if (!mtd->read_oob) { - /* If this MTD doesn't have out-of-band data, - then there's no point continuing */ - DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n"); - return; - } - DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", - mtd->read, mtd->size, mtd->erasesize); - - NFTL_setup(mtd); - } -} - -static void NFTL_notify_remove(struct mtd_info *mtd) -{ - int i; - - for (i = 0; i < MAX_NFTLS; i++) { - if (NFTLs[i] && NFTLs[i]->mtd == mtd) - NFTL_unsetup(i); - } -} - #ifdef CONFIG_NFTL_RW /* Actual NFTL access routines */ @@ -303,7 +209,7 @@ targetEUN = thisEUN; for (block = 0; block < nftl->EraseSize / 512; block ++) { - MTD_READOOB(nftl->mtd, + MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + (block * 512), 16 , &retlen, (char *)&oob); if (block == 2) { @@ -420,7 +326,7 @@ chain by selecting the longer one */ oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); oob.u.c.unused = 0xffffffff; - MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 8, &retlen, (char *)&oob.u); } @@ -444,16 +350,16 @@ if (BlockMap[block] == BLOCK_NIL) continue; - ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), + ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); if (ret < 0) { - ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); if (ret != -EIO) printk("Error went away on retry.\n"); } - MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512), + MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); } @@ -462,7 +368,7 @@ = cpu_to_le16(thisVUC); oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; - MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 8, &retlen, (char *)&oob.u); /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ @@ -582,7 +488,7 @@ lastEUN = writeEUN; - MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, + MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", @@ -670,12 +576,12 @@ nftl->ReplUnitTable[writeEUN] = BLOCK_NIL; /* ... and on the flash itself */ - MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, + MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, &retlen, (char *)&oob.u); oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); - MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, + MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, &retlen, (char *)&oob.u); /* we link the new block to the chain only after the @@ -685,13 +591,13 @@ /* Both in our cache... */ nftl->ReplUnitTable[lastEUN] = writeEUN; /* ... and on the flash itself */ - MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, + MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, 8, &retlen, (char *)&oob.u); oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = cpu_to_le16(writeEUN); - MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, 8, &retlen, (char *)&oob.u); } @@ -704,8 +610,10 @@ return 0xffff; } -static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer) +static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) { + struct NFTLrecord *nftl = (void *)mbd; u16 writeEUN; unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); size_t retlen; @@ -720,7 +628,7 @@ return 1; } - MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, + MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP); /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */ @@ -728,8 +636,10 @@ } #endif /* CONFIG_NFTL_RW */ -static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer) +static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) { + struct NFTLrecord *nftl = (void *)mbd; u16 lastgoodEUN; u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)]; unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); @@ -742,7 +652,7 @@ if (thisEUN != BLOCK_NIL) { while (thisEUN < nftl->nb_blocks) { - if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs, + if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci) < 0) status = SECTOR_IGNORE; else @@ -761,13 +671,13 @@ case SECTOR_IGNORE: break; default: - printk("Unknown status for block %d in EUN %d: %x\n", + printk("Unknown status for block %ld in EUN %d: %x\n", block, thisEUN, status); break; } if (!silly--) { - printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", + printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n", block / (nftl->EraseSize / 512)); return 1; } @@ -783,264 +693,22 @@ loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; size_t retlen; u_char eccbuf[6]; - if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP)) + if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP)) return -EIO; } return 0; } -static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) -{ - struct NFTLrecord *nftl; - int p; - - nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS]; - - if (!nftl) return -EINVAL; - - switch (cmd) { - case HDIO_GETGEO: { - struct hd_geometry g; - - g.heads = nftl->heads; - g.sectors = nftl->sectors; - g.cylinders = nftl->cylinders; - g.start = part_table[MINOR(inode->i_rdev)].start_sect; - return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; - } - case BLKGETSIZE: /* Return device size */ - return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, - (unsigned long *) arg); - -#ifdef BLKGETSIZE64 - case BLKGETSIZE64: - return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9, - (u64 *)arg); -#endif - - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - if (nftl->mtd->sync) - nftl->mtd->sync(nftl->mtd); - return 0; - - case BLKRRPART: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (nftl->usecount > 1) return -EBUSY; - /* - * We have to flush all buffers and invalidate caches, - * or we won't be able to re-use the partitions, - * if there was a change and we don't want to reboot - */ - p = (1< 0) { - kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p); - if (part_table[p].nr_sects > 0) - invalidate_device (devp, 1); - - part_table[MINOR(inode->i_dev)+p].start_sect = 0; - part_table[MINOR(inode->i_dev)+p].nr_sects = 0; - } - -#if LINUX_VERSION_CODE < 0x20328 - resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS); -#else - grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS, - 1<nr_sects); -#endif - return 0; - -#if (LINUX_VERSION_CODE < 0x20303) - RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */ -#else - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - return blk_ioctl(inode->i_rdev, cmd, arg); -#endif - - default: - return -EINVAL; - } -} - -void nftl_request(RQFUNC_ARG) -{ - unsigned int dev, block, nsect; - struct NFTLrecord *nftl; - char *buffer; - struct request *req; - int res; - - while (1) { - INIT_REQUEST; /* blk.h */ - req = CURRENT; - - /* We can do this because the generic code knows not to - touch the request at the head of the queue */ - spin_unlock_irq(&io_request_lock); - - DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n"); - DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n", - (req->cmd == READ) ? "Read " : "Write", - req->sector, req->current_nr_sectors); - - dev = MINOR(req->rq_dev); - block = req->sector; - nsect = req->current_nr_sectors; - buffer = req->buffer; - res = 1; /* succeed */ - - if (dev >= MAX_NFTLS * (1<rq_dev)); - res = 0; /* fail */ - goto repeat; - } - - nftl = NFTLs[dev / (1<mutex); - DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n"); - - if (block + nsect > part_table[dev].nr_sects) { - /* access past the end of device */ - printk("nftl%c%d: bad access: block = %d, count = %d\n", - (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); - up(&nftl->mutex); - res = 0; /* fail */ - goto repeat; - } - - block += part_table[dev].start_sect; - - if (req->cmd == READ) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x " - "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors); - - for ( ; nsect > 0; nsect-- , block++, buffer += 512) { - /* Read a single sector to req->buffer + (512 * i) */ - if (NFTL_readblock(nftl, block, buffer)) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - } - - DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n"); - up(&nftl->mutex); - goto repeat; - } else if (req->cmd == WRITE) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x " - "(req->nr_sectors == %lx)\n", nsect, block, - req->nr_sectors); -#ifdef CONFIG_NFTL_RW - for ( ; nsect > 0; nsect-- , block++, buffer += 512) { - /* Read a single sector to req->buffer + (512 * i) */ - if (NFTL_writeblock(nftl, block, buffer)) { - DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - } - DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n"); -#else - res = 0; /* Writes always fail */ -#endif /* CONFIG_NFTL_RW */ - up(&nftl->mutex); - goto repeat; - } else { - DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - repeat: - DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res); - spin_lock_irq(&io_request_lock); - end_request(res); - } -} - -static int nftl_open(struct inode *ip, struct file *fp) -{ - int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS; - struct NFTLrecord *thisNFTL; - thisNFTL = NFTLs[nftlnum]; - - DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n"); - -#ifdef CONFIG_KMOD - if (!thisNFTL && nftlnum == 0) { - request_module("docprobe"); - thisNFTL = NFTLs[nftlnum]; - } -#endif - if (!thisNFTL) { - DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", - nftlnum, ip->i_rdev, ip, fp); - return -ENODEV; - } - -#ifndef CONFIG_NFTL_RW - if (fp->f_mode & FMODE_WRITE) - return -EROFS; -#endif /* !CONFIG_NFTL_RW */ - - thisNFTL->usecount++; - BLK_INC_USE_COUNT; - if (!get_mtd_device(thisNFTL->mtd, -1)) { - BLK_DEC_USE_COUNT; - return -ENXIO; - } - - return 0; -} - -static int nftl_release(struct inode *inode, struct file *fp) +static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { - struct NFTLrecord *thisNFTL; - - thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; - - DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); + struct NFTLrecord *nftl = (void *)dev; - if (thisNFTL->mtd->sync) - thisNFTL->mtd->sync(thisNFTL->mtd); - thisNFTL->usecount--; - BLK_DEC_USE_COUNT; - - put_mtd_device(thisNFTL->mtd); + geo->heads = nftl->heads; + geo->sectors = nftl->sectors; + geo->cylinders = nftl->cylinders; return 0; } -#if LINUX_VERSION_CODE < 0x20326 -static struct file_operations nftl_fops = { - read: block_read, - write: block_write, - ioctl: nftl_ioctl, - open: nftl_open, - release: nftl_release, - fsync: block_fsync, -}; -#else -static struct block_device_operations nftl_fops = -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) - owner: THIS_MODULE, -#endif - open: nftl_open, - release: nftl_release, - ioctl: nftl_ioctl -}; -#endif - - /**************************************************************************** * @@ -1048,49 +716,33 @@ * ****************************************************************************/ -static struct mtd_notifier nftl_notifier = { - add: NFTL_notify_add, - remove: NFTL_notify_remove + +struct mtd_blktrans_ops nftl_tr = { + .name = "nftl", + .major = NFTL_MAJOR, + .part_bits = NFTL_PARTN_BITS, + .getgeo = nftl_getgeo, + .readsect = nftl_readblock, +#ifdef CONFIG_NFTL_RW + .writesect = nftl_writeblock, +#endif + .add_mtd = nftl_add_mtd, + .remove_dev = nftl_remove_dev, + .owner = THIS_MODULE, }; extern char nftlmountrev[]; int __init init_nftl(void) { - int i; - -#ifdef PRERELEASE - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.87 $, nftlmount.c %s\n", nftlmountrev); -#endif - - if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ - printk("unable to register NFTL block device on major %d\n", MAJOR_NR); - return -EBUSY; - } else { - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev); - /* set block size to 1kB each */ - for (i = 0; i < 256; i++) { - nftl_blocksizes[i] = 1024; - } - blksize_size[MAJOR_NR] = nftl_blocksizes; - - add_gendisk(&nftl_gendisk); - } - - register_mtd_user(&nftl_notifier); - - return 0; + return register_mtd_blktrans(&nftl_tr); } static void __exit cleanup_nftl(void) { - unregister_mtd_user(&nftl_notifier); - unregister_blkdev(MAJOR_NR, "nftl"); - - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - - del_gendisk(&nftl_gendisk); + deregister_mtd_blktrans(&nftl_tr); } module_init(init_nftl); diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c --- a/drivers/mtd/nftlmount.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/nftlmount.c Thu Dec 4 16:24:25 2003 @@ -4,7 +4,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.31 2002/11/15 16:34:43 dwmw2 Exp $ + * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $ * * 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 @@ -21,26 +21,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define __NO_VERSION__ #include -#include #include -#include -#include -#include -#include #include #include -#include -#include #include #include #include -#include #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.31 $"; +char nftlmountrev[]="$Revision: 1.34 $"; /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update @@ -59,8 +50,8 @@ /* Assume logical EraseSize == physical erasesize for starting the scan. We'll sort it out later if we find a MediaHeader which says otherwise */ - nftl->EraseSize = nftl->mtd->erasesize; - nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize; + nftl->EraseSize = nftl->mbd.mtd->erasesize; + nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; nftl->MediaUnit = BLOCK_NIL; nftl->SpareMediaUnit = BLOCK_NIL; @@ -71,12 +62,12 @@ /* Check for ANAND header first. Then can whinge if it's found but later checks fail */ - if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { + if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { static int warncount = 5; if (warncount) { printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); if (!--warncount) printk(KERN_WARNING "Further failures for this block will not be printed\n"); } @@ -87,16 +78,16 @@ /* ANAND\0 not found. Continue */ #if 0 printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", - block * nftl->EraseSize, nftl->mtd->index); + block * nftl->EraseSize, nftl->mbd.mtd->index); #endif continue; } /* To be safer with BIOS, also use erase mark as discriminant */ - if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, - 8, &retlen, (char *)&h1)) < 0) { + if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, + 8, &retlen, (char *)&h1) < 0)) { printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); continue; } @@ -106,23 +97,23 @@ */ if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", - block * nftl->EraseSize, nftl->mtd->index, + block * nftl->EraseSize, nftl->mbd.mtd->index, le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); continue; } /* Finally reread to check ECC */ - if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, - &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) { + if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, + &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); continue; } /* Paranoia. Check the ANAND header is still there after the ECC read */ if (memcmp(buf, "ANAND", 6)) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n", - block * nftl->EraseSize, nftl->mtd->index); + block * nftl->EraseSize, nftl->mbd.mtd->index); printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); continue; @@ -137,7 +128,11 @@ printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n", nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize); /* if (debug) Print both side by side */ - return -1; + if (boot_record_count < 2) { + /* We haven't yet seen two real ones */ + return -1; + } + continue; } if (boot_record_count == 1) nftl->SpareMediaUnit = block; @@ -163,8 +158,8 @@ } else if (mh->UnitSizeFactor != 0xff) { printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", mh->UnitSizeFactor); - nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor); - nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize; + nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); + nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; } nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { @@ -182,7 +177,7 @@ return -1; } - nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); + nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); /* If we're not using the last sectors in the device for some reason, reduce nb_blocks accordingly so we forget they're there */ @@ -220,7 +215,7 @@ for (i = 0; i < nftl->nb_blocks; i++) { if ((i & (SECTORSIZE - 1)) == 0) { /* read one sector for every SECTORSIZE of blocks */ - if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize + + if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize + i + SECTORSIZE, SECTORSIZE, &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) { printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n", @@ -263,16 +258,16 @@ for (i = 0; i < len; i += SECTORSIZE) { /* we want to read the sector without ECC check here since a free sector does not have ECC syndrome on it yet */ - if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0) + if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) return -1; if (memcmpb(buf, 0xff, SECTORSIZE) != 0) return -1; if (check_oob) { - if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize, + if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize, &retlen, buf) < 0) return -1; - if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0) + if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0) return -1; } address += SECTORSIZE; @@ -297,7 +292,7 @@ struct erase_info *instr = &nftl->instr; /* Read the Unit Control Information #1 for Wear-Leveling */ - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) goto default_uci1; @@ -314,7 +309,7 @@ /* XXX: use async erase interface, XXX: test return code */ instr->addr = block * nftl->EraseSize; instr->len = nftl->EraseSize; - MTD_ERASE(nftl->mtd, instr); + MTD_ERASE(nftl->mbd.mtd, instr); if (instr->state == MTD_ERASE_FAILED) { /* could not format, FixMe: We should update the BadUnitTable @@ -337,7 +332,7 @@ return -1; uci.WearInfo = le32_to_cpu(nb_erases); - if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) return -1; return 0; @@ -363,7 +358,7 @@ block = first_block; for (;;) { for (i = 0; i < sectors_per_block; i++) { - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE, 8, &retlen, (char *)&bci) < 0) status = SECTOR_IGNORE; else @@ -383,7 +378,7 @@ /* sector not free actually : mark it as SECTOR_IGNORE */ bci.Status = SECTOR_IGNORE; bci.Status1 = SECTOR_IGNORE; - MTD_WRITEOOB(nftl->mtd, + MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE, 8, &retlen, (char *)&bci); } @@ -476,7 +471,7 @@ size_t retlen; /* check erase mark. */ - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; @@ -491,7 +486,7 @@ h1.EraseMark = cpu_to_le16(ERASE_MARK); h1.EraseMark1 = cpu_to_le16(ERASE_MARK); h1.WearInfo = cpu_to_le32(0); - if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; } else { @@ -503,7 +498,7 @@ SECTORSIZE, 0) != 0) return -1; - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i, 16, &retlen, buf) < 0) return -1; if (i == SECTORSIZE) { @@ -533,7 +528,7 @@ struct nftl_uci2 uci; size_t retlen; - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) return 0; @@ -572,9 +567,9 @@ for (;;) { /* read the block header. If error, we format the chain */ - if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8, + if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, &retlen, (char *)&h0) < 0 || - MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8, + MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) { s->ReplUnitTable[block] = BLOCK_NIL; do_format_chain = 1; diff -Nru a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c --- a/drivers/mtd/redboot.c Thu Dec 4 16:24:25 2003 +++ b/drivers/mtd/redboot.c Thu Dec 4 16:24:25 2003 @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $ + * $Id: redboot.c,v 1.12 2003/06/25 16:08:10 dwmw2 Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -34,7 +35,9 @@ return 1; } -int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts) +static int parse_redboot_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + unsigned long fis_origin) { int nrparts = 0; struct fis_image_desc *buf; @@ -43,7 +46,9 @@ int ret, i; size_t retlen; char *names; + char *nullname; int namelen = 0; + static char nullstring[] = "unallocated"; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); @@ -90,7 +95,11 @@ goto out; } new_fl->img = &buf[i]; - buf[i].flash_base &= master->size-1; + if (fis_origin) { + buf[i].flash_base -= fis_origin; + } else { + buf[i].flash_base &= master->size-1; + } /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ @@ -110,18 +119,24 @@ if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base) nrparts++; } - parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL); + parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL); if (!parts) { ret = -ENOMEM; goto out; } - names = (char *)&parts[nrparts]; + memset(parts, 0, sizeof(*parts)*nrparts + namelen); + + /* FIXME: Include nullname only if it's used */ + nullname = (char *)&parts[nrparts]; + sprintf(nullname, nullstring); + names = nullname + sizeof(nullstring); + i=0; if (fl->img->flash_base) { - parts[0].name = "unallocated space"; + parts[0].name = nullname; parts[0].size = fl->img->flash_base; parts[0].offset = 0; } @@ -133,11 +148,11 @@ strcpy(names, fl->img->name); names += strlen(names)+1; - if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) { + 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 = "unallocated space"; + parts[i].name = nullname; } tmp_fl = fl; fl = fl->next; @@ -155,7 +170,24 @@ return ret; } -EXPORT_SYMBOL(parse_redboot_partitions); +static struct mtd_part_parser redboot_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_redboot_partitions, + .name = "RedBoot", +}; + +static int __init redboot_parser_init(void) +{ + return register_mtd_parser(&redboot_parser); +} + +static void __exit redboot_parser_exit(void) +{ + deregister_mtd_parser(&redboot_parser); +} + +module_init(redboot_parser_init); +module_exit(redboot_parser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse "); diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/net/Makefile Thu Dec 4 16:24:25 2003 @@ -20,6 +20,8 @@ net_init.o mii.o list-multi := rcpci.o rcpci-objs := rcpci45.o rclanmtl.o +e1000-objs := e1000_main.o e1000_mac.o e1000_phy.o e1000_proc.o + ifeq ($(CONFIG_TULIP),y) obj-y += tulip/tulip.o @@ -259,4 +261,7 @@ rcpci.o: $(rcpci-objs) $(LD) -r -o $@ $(rcpci-objs) + +e1000.o: $(e1000-objs) + $(LD) -r -o $@ $(e1000-objs) diff -Nru a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e1000/e1000_proc.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,744 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, + or the Intel BSD + Patent License, the text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU General Public License 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + General Public License 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU General + Public License 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + 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 MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* + * Proc fs support. + * + * Read-only files created by driver (if CONFIG_PROC_FS): + * + * /proc/net/PRO_LAN_Adapters/.info + * /proc/net/PRO_LAN_Adapters// + * + * where is the system device name, i.e eth0. + * is the driver attribute name. + * + * There is one file for each driver attribute, where the contents + * of the file is the attribute value. The ethx.info file contains + * a list of all driver attributes in one file. + * + */ + +#include "e1000.h" + +#ifdef CONFIG_PROC_FS + +#include + +#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" +#define TAG_MAX_LENGTH 32 +#define LINE_MAX_LENGTH 80 +#define FIELD_MAX_LENGTH LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3 + +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; + +/* + * The list of driver proc attributes is stored in a proc_list link + * list. The list is build with proc_list_setup and is used to + * build the proc fs nodes. The private data for each node is the + * corresponding link in the link list. + */ + +struct proc_list { + struct list_head list; /* link list */ + char tag[TAG_MAX_LENGTH + 1]; /* attribute name */ + void *data; /* attribute data */ + size_t len; /* sizeof data */ + char *(*func)(void *, size_t, char *); /* format data func */ +}; + +static int +e1000_proc_read(char *page, char **start, off_t off, int count, int *eof) +{ + int len = strlen(page); + + page[len++] = '\n'; + + if(len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if(len > count) + len = count; + if(len < 0) + len = 0; + + return len; +} + +static int +e1000_proc_info_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *proc_list_head = data, *curr; + struct proc_list *elem; + char *p = page; + char buf[FIELD_MAX_LENGTH + 1]; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + + if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE) + break; + + if(!strlen(elem->tag)) + p += sprintf(p, "\n"); + else + p += sprintf(p, "%-*.*s %.*s\n", + TAG_MAX_LENGTH, TAG_MAX_LENGTH, + elem->tag, FIELD_MAX_LENGTH, + elem->func(elem->data, elem->len, buf)); + } + + *p = '\0'; + + return e1000_proc_read(page, start, off, count, eof); +} + +static int +e1000_proc_single_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct proc_list *elem = data; + + sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data, + elem->len, page)); + + return e1000_proc_read(page, start, off, count, eof); +} + +static void __devexit +e1000_proc_dirs_free(char *name, struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR))) + break; + } + + if(!intel_proc_dir) + return; + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + if ((proc_dir->namelen == strlen(name)) && + !memcmp(proc_dir->name, name, strlen(name))) + break; + } + + if(proc_dir) { + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + remove_proc_entry(elem->tag, proc_dir); + } + + strcpy(info_name, name); + strcat(info_name, ".info"); + + remove_proc_entry(info_name, intel_proc_dir); + remove_proc_entry(name, intel_proc_dir); + } + + /* If the intel dir is empty, remove it */ + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + + /* ignore . and .. */ + + if(*(proc_dir->name) == '.') + continue; + break; + } + + if(!proc_dir) + remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); +} + + +static int __devinit +e1000_proc_singles_create(struct proc_dir_entry *parent, + struct list_head *proc_list_head) +{ + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + struct proc_dir_entry *proc_entry; + + elem = list_entry(curr, struct proc_list, list); + + if(!strlen(elem->tag)) + continue; + + if(!(proc_entry = + create_proc_entry(elem->tag, S_IFREG, parent))) + return 0; + + proc_entry->read_proc = e1000_proc_single_read; + proc_entry->data = elem; + SET_MODULE_OWNER(proc_entry); + } + + return 1; +} + +static void __devinit +e1000_proc_dirs_create(void *data, char *name, + struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR))) + break; + } + + if(!intel_proc_dir) + if(!(intel_proc_dir = + create_proc_entry(ADAPTERS_PROC_DIR, + S_IFDIR, proc_net))) + return; + + if(!(proc_dir = + create_proc_entry(name, S_IFDIR, intel_proc_dir))) + return; + SET_MODULE_OWNER(proc_dir); + + if(!e1000_proc_singles_create(proc_dir, proc_list_head)) + return; + + strcpy(info_name, name); + strcat(info_name, ".info"); + + if(!(info_entry = + create_proc_entry(info_name, S_IFREG, intel_proc_dir))) + return; + SET_MODULE_OWNER(info_entry); + + info_entry->read_proc = e1000_proc_info_read; + info_entry->data = proc_list_head; +} + +static void __devinit +e1000_proc_list_add(struct list_head *proc_list_head, char *tag, + void *data, size_t len, + char *(*func)(void *, size_t, char *)) +{ + struct proc_list *new = (struct proc_list *) + kmalloc(sizeof(struct proc_list), GFP_KERNEL); + + if(!new) + return; + + strncpy(new->tag, tag, TAG_MAX_LENGTH); + new->data = data; + new->len = len; + new->func = func; + + list_add_tail(&new->list, proc_list_head); +} + +static void __devexit +e1000_proc_list_free(struct list_head *proc_list_head) +{ + struct proc_list *elem; + + while(!list_empty(proc_list_head)) { + elem = list_entry(proc_list_head->next, struct proc_list, list); + list_del(&elem->list); + kfree(elem); + } +} + +/* + * General purpose formating functions + */ + +static char * +e1000_proc_str(void *data, size_t len, char *buf) +{ + sprintf(buf, "%s", (char *)data); + return buf; +} + +static char * +e1000_proc_hex(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "0x%02x", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "0x%04x", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "0x%08x", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +static char * +e1000_proc_unsigned(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "%u", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "%u", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "%u", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +/* + * Specific formating functions + */ + +static char * +e1000_proc_part_number(void *data, size_t len, char *buf) +{ + sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8, + *(uint32_t *)data & 0x000000FF); + return buf; +} + +static char * +e1000_proc_slot(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn)); + return buf; +} + +static char * +e1000_proc_bus_type(void *data, size_t len, char *buf) +{ + e1000_bus_type bus_type = *(e1000_bus_type *)data; + sprintf(buf, + bus_type == e1000_bus_type_pci ? "PCI" : + bus_type == e1000_bus_type_pcix ? "PCI-X" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_speed(void *data, size_t len, char *buf) +{ + e1000_bus_speed bus_speed = *(e1000_bus_speed *)data; + sprintf(buf, + bus_speed == e1000_bus_speed_33 ? "33MHz" : + bus_speed == e1000_bus_speed_66 ? "66MHz" : + bus_speed == e1000_bus_speed_100 ? "100MHz" : + bus_speed == e1000_bus_speed_133 ? "133MHz" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_width(void *data, size_t len, char *buf) +{ + e1000_bus_width bus_width = *(e1000_bus_width *)data; + sprintf(buf, + bus_width == e1000_bus_width_32 ? "32-bit" : + bus_width == e1000_bus_width_64 ? "64-bit" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_hwaddr(void *data, size_t len, char *buf) +{ + unsigned char *hwaddr = data; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + return buf; +} + +static char * +e1000_proc_link(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, netif_running(adapter->netdev) ? + netif_carrier_ok(adapter->netdev) ? + "up" : "down" : "N/A"); + return buf; +} + +static char * +e1000_proc_link_speed(void *data, size_t len, char *buf) +{ + uint16_t link_speed = *(uint16_t *)data; + sprintf(buf, link_speed ? "%u" : "N/A", link_speed); + return buf; +} + +static char * +e1000_proc_link_duplex(void *data, size_t len, char *buf) +{ + uint16_t link_duplex = *(uint16_t *)data; + sprintf(buf, + link_duplex == FULL_DUPLEX ? "Full" : + link_duplex == HALF_DUPLEX ? "Half" : + "N/A"); + return buf; +} + +static char * +e1000_proc_state(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down"); + return buf; +} + +static char * +e1000_proc_media_type(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, + adapter->hw.media_type == e1000_media_type_copper ? + "Copper" : "Fiber"); + return buf; +} + +static char * +e1000_proc_cable_length(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_cable_length cable_length = adapter->phy_info.cable_length; + sprintf(buf, "%s%s", + cable_length == e1000_cable_length_50 ? "0-50" : + cable_length == e1000_cable_length_50_80 ? "50-80" : + cable_length == e1000_cable_length_80_110 ? "80-110" : + cable_length == e1000_cable_length_110_140 ? "110-140" : + cable_length == e1000_cable_length_140 ? "> 140" : + "Unknown", + cable_length != e1000_cable_length_undefined ? + " Meters (+/- 20 Meters)" : ""); + return buf; +} + +static char * +e1000_proc_extended(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_10bt_ext_dist_enable dist_enable = + adapter->phy_info.extended_10bt_distance; + sprintf(buf, + dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" : + dist_enable == e1000_10bt_ext_dist_enable_lower ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_cable_polarity(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_rev_polarity polarity = adapter->phy_info.cable_polarity; + sprintf(buf, + polarity == e1000_rev_polarity_normal ? "Normal" : + polarity == e1000_rev_polarity_reversed ? "Reversed" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_polarity_correction(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_polarity_reversal correction = + adapter->phy_info.polarity_correction; + sprintf(buf, + correction == e1000_polarity_reversal_enabled ? "Disabled" : + correction == e1000_polarity_reversal_disabled ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode; + sprintf(buf, + mdix_mode == e1000_auto_x_mode_manual_mdi ? "MDI" : + mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_rx_status(void *data, size_t len, char *buf) +{ + e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data; + sprintf(buf, + rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" : + rx_status == e1000_1000t_rx_status_ok ? "OK" : + "Unknown"); + return buf; +} + +/* + * e1000_proc_list_setup - build link list of proc praramters + * @adapter: board private structure + * + * Order matters - ethx.info entries are ordered in the order links + * are added to list. + */ + +#define LIST_ADD_F(T,D,F) \ + e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F)) +#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL) +#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str) +#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex) +#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned) + +static void __devinit +e1000_proc_list_setup(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct list_head *proc_list_head = &adapter->proc_list_head; + + INIT_LIST_HEAD(proc_list_head); + + LIST_ADD_S("Description", adapter->id_string); + LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number); + LIST_ADD_S("Driver_Name", e1000_driver_name); + LIST_ADD_S("Driver_Version", e1000_driver_version); + LIST_ADD_H("PCI_Vendor", &hw->vendor_id); + LIST_ADD_H("PCI_Device_ID", &hw->device_id); + LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id); + LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id); + LIST_ADD_H("PCI_Revision_ID", &hw->revision_id); + LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number); + LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot); + + if(adapter->hw.mac_type >= e1000_82543) { + LIST_ADD_F("PCI_Bus_Type", + &hw->bus_type, e1000_proc_bus_type); + LIST_ADD_F("PCI_Bus_Speed", + &hw->bus_speed, e1000_proc_bus_speed); + LIST_ADD_F("PCI_Bus_Width", + &hw->bus_width, e1000_proc_bus_width); + } + + LIST_ADD_U("IRQ", &adapter->pdev->irq); + LIST_ADD_S("System_Device_Name", adapter->netdev->name); + LIST_ADD_F("Current_HWaddr", + adapter->netdev->dev_addr, e1000_proc_hwaddr); + LIST_ADD_F("Permanent_HWaddr", + adapter->hw.perm_mac_addr, e1000_proc_hwaddr); + + LIST_ADD_BLANK(); + + LIST_ADD_F("Link", adapter, e1000_proc_link); + LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed); + LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex); + LIST_ADD_F("State", adapter, e1000_proc_state); + + LIST_ADD_BLANK(); + + /* Standard net device stats */ + LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets); + LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets); + LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes); + LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes); + LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors); + LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors); + LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped); + LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped); + + LIST_ADD_U("Multicast", &adapter->net_stats.multicast); + LIST_ADD_U("Collisions", &adapter->net_stats.collisions); + + LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors); + LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors); + LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors); + LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors); + LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors); + LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors); + + LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors); + LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors); + LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors); + LIST_ADD_U("Tx_Heartbeat_Errors", + &adapter->net_stats.tx_heartbeat_errors); + LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors); + + /* 8254x-specific stats */ + LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol); + LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc); + LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc); + LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc); + LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc); + LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc); + + /* The 82542 does not have an alignment error count register */ + if(adapter->hw.mac_type >= e1000_82543) + LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc); + + LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc); + LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc); + LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc); + LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc); + LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good); + LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err); + + LIST_ADD_BLANK(); + + /* Cable diags */ + LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type); + if(adapter->hw.media_type == e1000_media_type_copper) { + LIST_ADD_F("PHY_Cable_Length", + adapter, e1000_proc_cable_length); + LIST_ADD_F("PHY_Extended_10Base_T_Distance", + adapter, e1000_proc_extended); + LIST_ADD_F("PHY_Cable_Polarity", + adapter, e1000_proc_cable_polarity); + LIST_ADD_F("PHY_Disable_Polarity_Correction", + adapter, e1000_proc_polarity_correction); + LIST_ADD_U("PHY_Idle_Errors", + &adapter->phy_stats.idle_errors); + LIST_ADD_U("PHY_Receive_Errors", + &adapter->phy_stats.receive_errors); + LIST_ADD_F("PHY_MDI_X_Enabled", + adapter, e1000_proc_mdi_x_enabled); + LIST_ADD_F("PHY_Local_Receiver_Status", + &adapter->phy_info.local_rx, + e1000_proc_rx_status); + LIST_ADD_F("PHY_Remote_Receiver_Status", + &adapter->phy_info.remote_rx, + e1000_proc_rx_status); + } + +} + +/* + * e1000_proc_dev_setup - create proc fs nodes and link list + * @adapter: board private structure + */ + +void __devinit +e1000_proc_dev_setup(struct e1000_adapter *adapter) +{ + e1000_proc_list_setup(adapter); + + e1000_proc_dirs_create(adapter, + adapter->netdev->name, + &adapter->proc_list_head); +} + +/* + * e1000_proc_dev_free - free proc fs nodes and link list + * @adapter: board private structure + */ + +void __devexit +e1000_proc_dev_free(struct e1000_adapter *adapter) +{ + e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head); + + e1000_proc_list_free(&adapter->proc_list_head); +} + +#else /* CONFIG_PROC_FS */ + +void __devinit e1000_proc_dev_setup(struct e1000_adapter *adapter) {} +void __devexit e1000_proc_dev_free(struct e1000_adapter *adapter) {} + +#endif /* CONFIG_PROC_FS */ + diff -Nru a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in --- a/drivers/net/wireless/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/net/wireless/Config.in Thu Dec 4 16:24:25 2003 @@ -7,6 +7,7 @@ fi tristate ' Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)' CONFIG_HERMES +tristate ' Host AP support for Prism2/2.5/3 IEEE 802.11b' CONFIG_HOSTAP if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate ' Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT $CONFIG_HERMES @@ -15,6 +16,8 @@ if [ "$CONFIG_PCI" = "y" ]; then dep_tristate ' Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL dep_tristate ' Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL + dep_tristate ' Host AP driver for Prism2/2.5/3 in PLX9052 based PCI adaptors' CONFIG_HOSTAP_PLX $CONFIG_HOSTAP + dep_tristate ' Host AP driver for Prism2.5 PCI adaptors' CONFIG_HOSTAP_PCI $CONFIG_HOSTAP fi # If Pcmcia is compiled in, offer Pcmcia cards... @@ -22,6 +25,7 @@ comment 'Wireless Pcmcia cards support' dep_tristate ' Hermes PCMCIA card support' CONFIG_PCMCIA_HERMES $CONFIG_HERMES + dep_tristate ' Host AP driver for Prism2/2.5/3 PC Cards' CONFIG_HOSTAP_CS $CONFIG_HOSTAP $CONFIG_PCMCIA tristate ' Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS fi diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/net/wireless/Makefile Thu Dec 4 16:24:25 2003 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := airo.o orinoco.o hermes.o +export-objs := airo.o orinoco.o hermes.o hostap.o obj-$(CONFIG_HERMES) += orinoco.o hermes.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o @@ -22,5 +22,10 @@ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o + +obj-$(CONFIG_HOSTAP) += hostap.o hostap_crypt_wep.o +obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o +obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o +obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/net/wireless/hostap.c b/drivers/net/wireless/hostap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,1073 @@ +/* + * Host AP (software wireless LAN access point) driver for + * Intersil Prism2/2.5/3 - hostap.o module, common routines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) +#include +#else +#include +#endif +#include +#include +#include "hostap_wext.h" +#include + +#include "hostap_wlan.h" +#include "hostap_80211.h" +#include "hostap_ap.h" +#include "hostap.h" +#include "hostap_crypt.h" + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP common routines"); +MODULE_LICENSE("GPL"); + +#ifndef HOSTAP_CRYPT_MODULE +/* Old hostap_crypt module is now part of hostap module. */ +#include "hostap_crypt.c" +#else /* HOSTAP_CRYPT_MODULE */ +#define hostap_crypto_init() +#define hostap_crypto_deinit() +#endif /* HOSTAP_CRYPT_MODULE */ + +#define TX_TIMEOUT (2 * HZ) + +#define PRISM2_MAX_FRAME_SIZE 2304 +#define PRISM2_MIN_MTU 256 +/* FIX: */ +#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) + + +/* hostap.c */ +static int prism2_wds_add(local_info_t *local, u8 *remote_addr, + int rtnl_locked); +static int prism2_wds_del(local_info_t *local, u8 *remote_addr, + int rtnl_locked, int do_not_remove); + +/* hostap_ap.c */ +#ifdef WIRELESS_EXT +static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], + struct iw_quality qual[], int buf_size, + int aplist); +#if WIRELESS_EXT > 13 +static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); +#endif /* WIRELESS_EXT > 13 */ +#endif /* WIRELESS_EXT */ +static int prism2_hostapd(struct ap_data *ap, + struct prism2_hostapd_param *param); +static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, + struct prism2_crypt_data ***crypt); +static void ap_control_kickall(struct ap_data *ap); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, + u8 *mac); +static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, + u8 *mac); +static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); +static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, + u8 *mac); +#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +#ifdef WIRELESS_EXT +static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; +#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) +#endif /* WIRELESS_EXT */ + + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + + +/* FIX: these could be compiled separately and linked together to hostap.o */ +#include "hostap_ap.c" +#include "hostap_info.c" +#include "hostap_ioctl.c" +#include "hostap_proc.c" +#include "hostap_80211_rx.c" + + +struct net_device * hostap_add_interface(struct local_info *local, + int type, int rtnl_locked, + const char *name) +{ + struct net_device *dev, *mdev; + struct hostap_interface *iface; + int ret; + + dev = alloc_etherdev(sizeof(struct hostap_interface)); + if (dev == NULL) + return NULL; + + iface = dev->priv; + iface->dev = dev; + iface->local = local; + iface->type = type; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + dev->name = iface->name; +#endif + list_add(&iface->list, &local->hostap_interfaces); + + mdev = local->dev; + memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); + dev->base_addr = mdev->base_addr; + dev->irq = mdev->irq; + dev->mem_start = mdev->mem_start; + dev->mem_end = mdev->mem_end; + + hostap_setup_dev(dev, local, 0); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + dev->destructor = free_netdev; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + /* Linux 2.4.x uses dev entry (reads dev->features) after + * dev->destructor has returned, so must not free struct net_device + * here. Set NETIF_F_DYNALLOC flag so that netdev_finish_unregister() + * frees the entry. */ + dev->features |= NETIF_F_DYNALLOC; +#endif + + sprintf(dev->name, "%s%s", mdev->name, name); + if (!rtnl_locked) + rtnl_lock(); + + ret = 0; + if (strchr(dev->name, '%')) + ret = dev_alloc_name(dev, dev->name); + + if (ret >= 0) + ret = register_netdevice(dev); + + if (!rtnl_locked) + rtnl_unlock(); + + if (ret < 0) { + printk(KERN_WARNING "%s: failed to add new netdevice!\n", + dev->name); + free_netdev(dev); + return NULL; + } + + printk(KERN_DEBUG "%s: registered netdevice %s\n", + mdev->name, dev->name); + + return dev; +} + + +void hostap_remove_interface(struct net_device *dev, int rtnl_locked, + int remove_from_list) +{ + if (!dev) + return; + + if (remove_from_list) { + struct hostap_interface *iface; + iface = dev->priv; + list_del(&iface->list); + } + if (rtnl_locked) + unregister_netdevice(dev); + else + unregister_netdev(dev); + + /* dev->destructor = free_netdev() will free the device data, including + * private data, when removing the device */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + /* Except for the compatibility case, which did not use + * dev->destructor.. */ + free_netdev(dev); +#endif +} + + +static inline int prism2_wds_special_addr(u8 *addr) +{ + if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) + return 0; + + return 1; +} + + +static int prism2_wds_add(local_info_t *local, u8 *remote_addr, + int rtnl_locked) +{ + struct net_device *dev; + struct list_head *ptr; + struct hostap_interface *iface, *empty, *match; + + empty = match = NULL; + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type != HOSTAP_INTERFACE_WDS) + continue; + + if (prism2_wds_special_addr(iface->u.wds.remote_addr)) + empty = iface; + else if (memcmp(iface->u.wds.remote_addr, remote_addr, + ETH_ALEN) == 0) { + match = iface; + break; + } + } + if (!match && empty) { + /* take pre-allocated entry into use */ + memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); + } + + if (!match && empty) { + read_unlock_bh(&local->iface_lock); + printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", + local->dev->name, empty->dev->name); + return 0; + } + read_unlock_bh(&local->iface_lock); + + if (!prism2_wds_special_addr(remote_addr)) { + if (match) + return -EEXIST; + hostap_add_sta(local->ap, remote_addr); + } + + if (local->wds_connections >= local->wds_max_connections) + return -ENOBUFS; + + /* verify that there is room for wds# postfix in the interface name */ + if (strlen(local->dev->name) > IFNAMSIZ - 5) { + printk(KERN_DEBUG "'%s' too long base device name\n", + local->dev->name); + return -EINVAL; + } + + dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, + "wds%d"); + if (dev == NULL) + return -ENOMEM; + + iface = dev->priv; + memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); + + local->wds_connections++; + + return 0; +} + + +static int prism2_wds_del(local_info_t *local, u8 *remote_addr, + int rtnl_locked, int do_not_remove) +{ + unsigned long flags; + struct list_head *ptr; + struct hostap_interface *iface, *selected = NULL; + + write_lock_irqsave(&local->iface_lock, flags); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type != HOSTAP_INTERFACE_WDS) + continue; + + if (memcmp(iface->u.wds.remote_addr, remote_addr, + ETH_ALEN) == 0) { + selected = iface; + break; + } + } + if (selected && !do_not_remove) + list_del(&selected->list); + write_unlock_irqrestore(&local->iface_lock, flags); + + if (selected) { + if (do_not_remove) + memset(selected->u.wds.remote_addr, 0, ETH_ALEN); + else { + hostap_remove_interface(selected->dev, rtnl_locked, 0); + local->wds_connections--; + } + } + + return selected ? 0 : -ENODEV; +} + + +u16 hostap_tx_callback_register(local_info_t *local, + void (*func)(struct sk_buff *, int ok, void *), + void *data) +{ + unsigned long flags; + struct hostap_tx_callback_info *entry; + + entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry), + GFP_ATOMIC); + if (entry == NULL) + return 0; + + entry->func = func; + entry->data = data; + + spin_lock_irqsave(&local->lock, flags); + entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; + entry->next = local->tx_callback; + local->tx_callback = entry; + spin_unlock_irqrestore(&local->lock, flags); + + return entry->idx; +} + + +int hostap_tx_callback_unregister(local_info_t *local, u16 idx) +{ + unsigned long flags; + struct hostap_tx_callback_info *cb, *prev = NULL; + + spin_lock_irqsave(&local->lock, flags); + cb = local->tx_callback; + while (cb != NULL && cb->idx != idx) { + prev = cb; + cb = cb->next; + } + if (cb) { + if (prev == NULL) + local->tx_callback = cb->next; + else + prev->next = cb->next; + kfree(cb); + } + spin_unlock_irqrestore(&local->lock, flags); + + return cb ? 0 : -1; +} + + +/* val is in host byte order */ +int hostap_set_word(struct net_device *dev, int rid, u16 val) +{ + struct hostap_interface *iface = dev->priv; + u16 tmp = cpu_to_le16(val); + return iface->local->func->set_rid(dev, rid, &tmp, 2); +} + + +int hostap_set_string(struct net_device *dev, int rid, const char *val) +{ + struct hostap_interface *iface = dev->priv; + char buf[MAX_SSID_LEN + 2]; + int len; + + len = strlen(val); + if (len > MAX_SSID_LEN) + return -1; + memset(buf, 0, sizeof(buf)); + buf[0] = len; /* little endian 16 bit word */ + memcpy(buf + 2, val, len); + + return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); +} + + +u16 hostap_get_porttype(local_info_t *local) +{ + if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) + return HFA384X_PORTTYPE_PSEUDO_IBSS; + if (local->iw_mode == IW_MODE_ADHOC) + return HFA384X_PORTTYPE_IBSS; + if (local->iw_mode == IW_MODE_INFRA) + return HFA384X_PORTTYPE_BSS; + if (local->iw_mode == IW_MODE_REPEAT) + return HFA384X_PORTTYPE_WDS; + if (local->iw_mode == IW_MODE_MONITOR) + return HFA384X_PORTTYPE_PSEUDO_IBSS; + return HFA384X_PORTTYPE_HOSTAP; +} + + +int hostap_set_encryption(local_info_t *local) +{ + u16 val; + int i, keylen, len, idx; + char keybuf[WEP_KEY_LEN + 1]; + enum { NONE, WEP, OTHER } encrypt_type; + + if (local->crypt == NULL || local->crypt->ops == NULL) + encrypt_type = NONE; + else if (strcmp(local->crypt->ops->name, "WEP") == 0) + encrypt_type = WEP; + else + encrypt_type = OTHER; + + if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, + 1) < 0) { + printk(KERN_DEBUG "Could not read current WEP flags.\n"); + goto fail; + } + le16_to_cpus(&val); + + if (encrypt_type != NONE) + val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; + else + val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; + + if (local->open_wep || encrypt_type == NONE || + (local->ieee_802_1x && local->host_decrypt)) + val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; + else + val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; + + if (encrypt_type != NONE && + (encrypt_type == OTHER || local->host_encrypt)) + val |= HFA384X_WEPFLAGS_HOSTENCRYPT; + else + val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; + if (encrypt_type != NONE && + (encrypt_type == OTHER || local->host_decrypt)) + val |= HFA384X_WEPFLAGS_HOSTDECRYPT; + else + val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; + + if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { + printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", + val); + goto fail; + } + + if (encrypt_type != WEP) + return 0; + + /* 104-bit support seems to require that all the keys are set to the + * same keylen */ + keylen = 6; /* first 5 octets */ + idx = local->crypt->ops->get_key_idx(local->crypt->priv); + len = local->crypt->ops->get_key(idx, keybuf, sizeof(keybuf), + local->crypt->priv); + if (idx >= 0 && idx < WEP_KEYS && len > 5) + keylen = WEP_KEY_LEN + 1; /* first 13 octets */ + + for (i = 0; i < WEP_KEYS; i++) { + memset(keybuf, 0, sizeof(keybuf)); + (void) local->crypt->ops->get_key(i, keybuf, sizeof(keybuf), + local->crypt->priv); + if (local->func->set_rid(local->dev, + HFA384X_RID_CNFDEFAULTKEY0 + i, + keybuf, keylen)) { + printk(KERN_DEBUG "Could not set key %d (len=%d)\n", + i, keylen); + goto fail; + } + } + if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { + printk(KERN_DEBUG "Could not set default keyid %d\n", idx); + goto fail; + } + + return 0; + + fail: + printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); + return -1; +} + + +int hostap_set_antsel(local_info_t *local) +{ + u16 val; + int ret = 0; + + if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && + local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, + HFA386X_CR_TX_CONFIGURE, + NULL, &val) == 0) { + val &= ~(BIT(2) | BIT(1)); + switch (local->antsel_tx) { + case HOSTAP_ANTSEL_DIVERSITY: + val |= BIT(1); + break; + case HOSTAP_ANTSEL_LOW: + break; + case HOSTAP_ANTSEL_HIGH: + val |= BIT(2); + break; + } + + if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_TX_CONFIGURE, &val, NULL)) { + printk(KERN_INFO "%s: setting TX AntSel failed\n", + local->dev->name); + ret = -1; + } + } + + if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && + local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, + HFA386X_CR_RX_CONFIGURE, + NULL, &val) == 0) { + val &= ~(BIT(1) | BIT(0)); + switch (local->antsel_rx) { + case HOSTAP_ANTSEL_DIVERSITY: + break; + case HOSTAP_ANTSEL_LOW: + val |= BIT(0); + break; + case HOSTAP_ANTSEL_HIGH: + val |= BIT(0) | BIT(1); + break; + } + + if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_RX_CONFIGURE, &val, NULL)) { + printk(KERN_INFO "%s: setting RX AntSel failed\n", + local->dev->name); + ret = -1; + } + } + + return ret; +} + + +int hostap_set_roaming(local_info_t *local) +{ + u16 val; + + switch (local->host_roaming) { + case 1: + val = HFA384X_ROAMING_HOST; + break; + case 2: + val = HFA384X_ROAMING_DISABLED; + break; + case 0: + default: + val = HFA384X_ROAMING_FIRMWARE; + break; + } + + return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); +} + + +int hostap_set_auth_algs(local_info_t *local) +{ + int val = local->auth_algs; + /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication + * set to include both Open and Shared Key flags. It tries to use + * Shared Key authentication in that case even if WEP keys are not + * configured.. STA f/w v0.7.6 is able to handle such configuration, + * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ + if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && + val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) + val = PRISM2_AUTH_OPEN; + + if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { + printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " + "failed\n", local->dev->name, local->auth_algs); + return -EINVAL; + } + + return 0; +} + + +void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) +{ + u16 status, fc; + + status = __le16_to_cpu(rx->status); + + printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " + "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " + "jiffies=%ld\n", + name, status, (status >> 8) & 0x07, status >> 13, status & 1, + rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); + + fc = __le16_to_cpu(rx->frame_control); + printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " + "data_len=%d%s%s\n", + fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), + __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), + __le16_to_cpu(rx->data_len), + fc & WLAN_FC_TODS ? " [ToDS]" : "", + fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); + + printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" + MACSTR "\n", + MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), + MAC2STR(rx->addr4)); + + printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", + MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), + __be16_to_cpu(rx->len)); +} + + +void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) +{ + u16 fc; + + printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " + "tx_control=0x%04x; jiffies=%ld\n", + name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, + __le16_to_cpu(tx->tx_control), jiffies); + + fc = __le16_to_cpu(tx->frame_control); + printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " + "data_len=%d%s%s\n", + fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), + __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), + __le16_to_cpu(tx->data_len), + fc & WLAN_FC_TODS ? " [ToDS]" : "", + fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); + + printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" + MACSTR "\n", + MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), + MAC2STR(tx->addr4)); + + printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", + MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), + __be16_to_cpu(tx->len)); +} + + +/* TODO: share one netif queue for all interfaces and get rid of these + * functions.. */ +/* wake all netif queues in use */ +void hostap_netif_wake_queues(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct list_head *ptr; + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + netif_wake_queue(iface->dev); + } + read_unlock_bh(&local->iface_lock); +} + + +/* stop all netif queues in use */ +void hostap_netif_stop_queues(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct list_head *ptr; + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + netif_stop_queue(iface->dev); + } + read_unlock_bh(&local->iface_lock); +} + + +int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */ + return ETH_ALEN; +} + + +int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) { + memcpy(haddr, skb->mac.raw + + sizeof(struct linux_wlan_ng_prism_hdr) + 10, + ETH_ALEN); /* addr2 */ + } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */ + memcpy(haddr, skb->mac.raw + + sizeof(struct linux_wlan_ng_cap_hdr) + 10, + ETH_ALEN); /* addr2 */ + } + return ETH_ALEN; +} + + +int hostap_80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case WLAN_FC_TYPE_DATA: + if ((fc & WLAN_FC_FROMDS) && (fc & WLAN_FC_TODS)) + hdrlen = 30; /* Addr4 */ + break; + case WLAN_FC_TYPE_CTRL: + switch (WLAN_FC_GET_STYPE(fc)) { + case WLAN_FC_STYPE_CTS: + case WLAN_FC_STYPE_ACK: + hdrlen = 10; + break; + default: + hdrlen = 16; + break; + } + break; + } + + return hdrlen; +} + + +struct net_device_stats *hostap_get_stats(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + return &iface->stats; +} + + +static int prism2_close(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (!local->hostapd && dev == local->dev && + (!local->func->card_present || local->func->card_present(local)) && + local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) + hostap_deauth_all_stas(dev, local->ap, 1); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + if (local->func->dev_close && local->func->dev_close(local)) + return 0; + + if (local->disable_on_close) { + local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); + } + + if (netif_running(dev)) { + netif_stop_queue(dev); + netif_device_detach(dev); + } + + flush_scheduled_work(); + +#ifdef NEW_MODULE_CODE + module_put(local->hw_module); +#elif MODULE + __MOD_DEC_USE_COUNT(local->hw_module); +#endif + + return 0; +} + + +static int prism2_open(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); + + if (local->func->dev_open && local->func->dev_open(local)) + return 1; + +#ifdef NEW_MODULE_CODE + if (!try_module_get(local->hw_module)) + return -ENODEV; +#elif MODULE + __MOD_INC_USE_COUNT(local->hw_module); +#endif + + if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { + printk(KERN_WARNING "%s: could not enable MAC port\n", + dev->name); + prism2_close(dev); + return 1; + } + if (!local->dev_enabled) + prism2_callback(local, PRISM2_CALLBACK_ENABLE); + local->dev_enabled = 1; + + netif_device_attach(dev); + netif_start_queue(dev); + + return 0; +} + + +#ifdef HAVE_SET_MAC_ADDR +static int prism2_set_mac_address(struct net_device *dev, void *p) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct list_head *ptr; + struct sockaddr *addr = p; + + if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, + ETH_ALEN) < 0 || local->func->reset_port(dev)) + return -EINVAL; + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN); + } + read_unlock_bh(&local->iface_lock); + + return 0; +} +#endif /* HAVE_SET_MAC_ADDR */ + + +/* TODO: to be further implemented as soon as Prism2 fully supports + * GroupAddresses and correct documentation is available */ +void hostap_set_multicast_list_queue(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, + local->is_promisc)) { + printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", + dev->name, local->is_promisc ? "en" : "dis"); + } + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +static void hostap_set_multicast_list(struct net_device *dev) +{ +#if 0 + /* FIX: promiscuous mode seems to be causing a lot of problems with + * some station firmware versions (FCSErr frames, invalid MACPort, etc. + * corrupted incoming frames). This code is now commented out while the + * problems are investigated. */ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { + local->is_promisc = 1; + } else { + local->is_promisc = 0; + } + + PRISM2_SCHEDULE_TASK(&local->set_multicast_list_queue); +#endif +} + + +static int prism2_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; +} + + +#ifdef HAVE_TX_TIMEOUT +static void prism2_tx_timeout(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_regs regs; + + printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); + hostap_netif_stop_queues(dev); + + local->func->read_regs(dev, ®s); + printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " + "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", + dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, + regs.swsupport0); + + local->func->schedule_reset(local); +} +#endif /* HAVE_TX_TIMEOUT */ + + +void hostap_setup_dev(struct net_device *dev, local_info_t *local, + int main_dev) +{ + ether_setup(dev); + + /* kernel callbacks */ + dev->get_stats = hostap_get_stats; +#ifdef WIRELESS_EXT + dev->get_wireless_stats = main_dev ? hostap_get_wireless_stats : NULL; +#if WIRELESS_EXT > 12 + dev->wireless_handlers = + (struct iw_handler_def *) &hostap_iw_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = main_dev ? hostap_ioctl : NULL; +#endif +#endif /* WIRELESS_EXT */ + dev->open = prism2_open; + dev->stop = prism2_close; + if (local->func) + dev->hard_start_xmit = local->func->tx; + else + printk(KERN_WARNING "hostap_setup_dev: local->func == NULL\n"); +#ifdef HAVE_SET_MAC_ADDR + dev->set_mac_address = prism2_set_mac_address; +#endif /* HAVE_SET_MAC_ADDR */ +#ifdef HAVE_MULTICAST + dev->set_multicast_list = hostap_set_multicast_list; +#endif +#ifdef HAVE_CHANGE_MTU + dev->change_mtu = prism2_change_mtu; +#endif +#ifdef HAVE_TX_TIMEOUT + dev->tx_timeout = prism2_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + dev->mtu = local->mtu; + + netif_stop_queue(dev); +} + + +static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) +{ + struct net_device *dev = local->dev; + + if (local->apdev) + return -EEXIST; + + printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); + + local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, + rtnl_locked, "ap"); + if (local->apdev == NULL) + return -ENOMEM; + + local->apdev->hard_start_xmit = local->func->tx_80211; + local->apdev->type = ARPHRD_IEEE80211; + local->apdev->hard_header_parse = hostap_80211_header_parse; + + local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, + rtnl_locked, "sta"); + if (local->stadev == NULL) + return -ENOMEM; + + return 0; +} + + +static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) +{ + struct net_device *dev = local->dev; + + printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); + + hostap_remove_interface(local->apdev, rtnl_locked, 1); + local->apdev = NULL; + + hostap_remove_interface(local->stadev, rtnl_locked, 1); + local->stadev = NULL; + + return 0; +} + + +int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) +{ + if (val < 0 || val > 1) + return -EINVAL; + + if (local->hostapd == val) + return 0; + + local->hostapd = val; + + if (val) + return hostap_enable_hostapd(local, rtnl_locked); + else + return hostap_disable_hostapd(local, rtnl_locked); +} + + +struct proc_dir_entry *hostap_proc; + +static int __init hostap_init(void) +{ + hostap_crypto_init(); + + if (proc_net != NULL) { + hostap_proc = proc_mkdir("hostap", proc_net); + if (!hostap_proc) + printk(KERN_WARNING "Failed to mkdir " + "/proc/net/hostap\n"); + } else + hostap_proc = NULL; + + return 0; +} + + +static void __exit hostap_exit(void) +{ + if (hostap_proc != NULL) { + hostap_proc = NULL; + remove_proc_entry("hostap", proc_net); + } + + hostap_crypto_deinit(); +} + + +EXPORT_SYMBOL(hostap_set_word); +EXPORT_SYMBOL(hostap_set_string); +EXPORT_SYMBOL(hostap_get_porttype); +EXPORT_SYMBOL(hostap_set_encryption); +EXPORT_SYMBOL(hostap_set_antsel); +EXPORT_SYMBOL(hostap_set_roaming); +EXPORT_SYMBOL(hostap_set_auth_algs); +EXPORT_SYMBOL(hostap_dump_rx_header); +EXPORT_SYMBOL(hostap_dump_tx_header); +EXPORT_SYMBOL(hostap_netif_wake_queues); +EXPORT_SYMBOL(hostap_netif_stop_queues); +EXPORT_SYMBOL(hostap_80211_header_parse); +EXPORT_SYMBOL(hostap_80211_prism_header_parse); +EXPORT_SYMBOL(hostap_80211_get_hdrlen); +EXPORT_SYMBOL(hostap_get_stats); +EXPORT_SYMBOL(hostap_setup_dev); +EXPORT_SYMBOL(hostap_proc); +EXPORT_SYMBOL(hostap_set_multicast_list_queue); +EXPORT_SYMBOL(hostap_set_hostapd); +EXPORT_SYMBOL(hostap_add_interface); +EXPORT_SYMBOL(hostap_remove_interface); + +module_init(hostap_init); +module_exit(hostap_exit); diff -Nru a/drivers/net/wireless/hostap.h b/drivers/net/wireless/hostap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,54 @@ +#ifndef HOSTAP_H +#define HOSTAP_H + +/* hostap.c */ + +extern struct proc_dir_entry *hostap_proc; + +u16 hostap_tx_callback_register(local_info_t *local, + void (*func)(struct sk_buff *, int ok, void *), + void *data); +int hostap_tx_callback_unregister(local_info_t *local, u16 idx); +int hostap_set_word(struct net_device *dev, int rid, u16 val); +int hostap_set_string(struct net_device *dev, int rid, const char *val); +u16 hostap_get_porttype(local_info_t *local); +int hostap_set_encryption(local_info_t *local); +int hostap_set_antsel(local_info_t *local); +int hostap_set_roaming(local_info_t *local); +int hostap_set_auth_algs(local_info_t *local); +void hostap_dump_rx_header(const char *name, + const struct hfa384x_rx_frame *rx); +void hostap_dump_tx_header(const char *name, + const struct hfa384x_tx_frame *tx); +void hostap_netif_wake_queues(struct net_device *dev); +void hostap_netif_stop_queues(struct net_device *dev); +int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr); +int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr); +int hostap_80211_get_hdrlen(u16 fc); +struct net_device_stats *hostap_get_stats(struct net_device *dev); +void hostap_setup_dev(struct net_device *dev, local_info_t *local, + int main_dev); +void hostap_set_multicast_list_queue(void *data); +int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); +void hostap_cleanup(local_info_t *local); +void hostap_cleanup_handler(void *data); +struct net_device * hostap_add_interface(struct local_info *local, + int type, int rtnl_locked, + const char *name); +void hostap_remove_interface(struct net_device *dev, int rtnl_locked, + int remove_from_list); + + +/* hostap_proc.c */ + +void hostap_init_proc(local_info_t *local); +void hostap_remove_proc(local_info_t *local); + + +/* hostap_info.c */ + +void hostap_info_init(local_info_t *local); +void hostap_info_process(local_info_t *local, struct sk_buff *skb); + + +#endif /* HOSTAP_H */ diff -Nru a/drivers/net/wireless/hostap_80211.h b/drivers/net/wireless/hostap_80211.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_80211.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,44 @@ +#ifndef HOSTAP_80211_H +#define HOSTAP_80211_H + +struct hostap_ieee80211_hdr { + u16 frame_control; + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + u16 seq_ctrl; + u8 addr4[6]; +} __attribute__ ((packed)); + +#define IEEE80211_MGMT_HDR_LEN 24 +#define IEEE80211_DATA_HDR3_LEN 24 +#define IEEE80211_DATA_HDR4_LEN 30 + + +struct hostap_80211_rx_status { + u32 mac_time; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ +}; + + +void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats); + + +/* prism2_rx_80211 'type' argument */ +enum { + PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, + PRISM2_RX_NULLFUNC_ACK +}; + +int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, int type); +void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats); +void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats); + +#endif /* HOSTAP_80211_H */ diff -Nru a/drivers/net/wireless/hostap_80211_rx.c b/drivers/net/wireless/hostap_80211_rx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_80211_rx.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,860 @@ +#include + +#include "hostap_80211.h" +#include "hostap.h" + +void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct hostap_ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + + printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " + "jiffies=%ld\n", + name, rx_stats->signal, rx_stats->noise, rx_stats->rate, + skb->len, jiffies); + + if (skb->len < 2) + return; + + fc = le16_to_cpu(hdr->frame_control); + printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", + fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), + fc & WLAN_FC_TODS ? " [ToDS]" : "", + fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); + + if (skb->len < IEEE80211_DATA_HDR3_LEN) { + printk("\n"); + return; + } + + printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), + le16_to_cpu(hdr->seq_ctrl)); + + printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, + MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + if (skb->len >= 30) + printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); + printk("\n"); +} + + +/* Send RX frame to netif with 802.11 (and possible prism) header. + * Called from hardware or software IRQ context. */ +int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, int type) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int hdrlen, phdrlen, head_need, tail_need; + u16 fc; + int prism_header, ret; + struct hostap_ieee80211_hdr *hdr; + + dev->last_rx = jiffies; + + if (dev->type == ARPHRD_IEEE80211_PRISM) { + if (local->monitor_type == PRISM2_MONITOR_PRISM) { + prism_header = 1; + phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); + } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ + prism_header = 2; + phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); + } + } else { + prism_header = 0; + phdrlen = 0; + } + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + if (type == PRISM2_RX_MGMT && (fc & WLAN_FC_PVER)) { + printk(KERN_DEBUG "%s: dropped management frame with header " + "version %d\n", dev->name, fc & WLAN_FC_PVER); + dev_kfree_skb_any(skb); + return 0; + } + + hdrlen = hostap_80211_get_hdrlen(fc); + + /* check if there is enough room for extra data; if not, expand skb + * buffer to be large enough for the changes */ + head_need = phdrlen; + tail_need = 0; +#ifdef PRISM2_ADD_BOGUS_CRC + tail_need += 4; +#endif /* PRISM2_ADD_BOGUS_CRC */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + if (head_need > skb_headroom(skb) || tail_need > skb_tailroom(skb)) { + struct sk_buff *nskb; + + nskb = dev_alloc_skb(skb->len + head_need + tail_need); + if (nskb == NULL) { + dev_kfree_skb_any(skb); + return 0; + } + + skb_reserve(nskb, head_need); + memcpy(skb_put(nskb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = nskb; + } +#else /* Linux 2.4.0 or newer */ + head_need -= skb_headroom(skb); + tail_need -= skb_tailroom(skb); + + if (head_need > 0 || tail_need > 0) { + if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, + tail_need > 0 ? tail_need : 0, + GFP_ATOMIC)) { + printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " + "reallocate skb buffer\n", dev->name); + dev_kfree_skb_any(skb); + return 0; + } + } +#endif + + /* We now have an skb with enough head and tail room, so just insert + * the extra data */ + +#ifdef PRISM2_ADD_BOGUS_CRC + memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ +#endif /* PRISM2_ADD_BOGUS_CRC */ + + if (prism_header == 1) { + struct linux_wlan_ng_prism_hdr *hdr; + hdr = (struct linux_wlan_ng_prism_hdr *) + skb_push(skb, phdrlen); + memset(hdr, 0, phdrlen); + hdr->msgcode = LWNG_CAP_DID_BASE; + hdr->msglen = sizeof(*hdr); + memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); +#define LWNG_SETVAL(f,i,s,l,d) \ +hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ +hdr->f.status = s; hdr->f.len = l; hdr->f.data = d + LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); + LWNG_SETVAL(mactime, 2, 0, 0, rx_stats->mac_time); + LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); + LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); + LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); + LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); + LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); + LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); + LWNG_SETVAL(istx, 9, 0, 4, 0); + LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); +#undef LWNG_SETVAL + } else if (prism_header == 2) { + struct linux_wlan_ng_cap_hdr *hdr; + hdr = (struct linux_wlan_ng_cap_hdr *) + skb_push(skb, phdrlen); + memset(hdr, 0, phdrlen); + hdr->version = htonl(LWNG_CAPHDR_VERSION); + hdr->length = htonl(phdrlen); + hdr->mactime = __cpu_to_be64(rx_stats->mac_time); + hdr->hosttime = __cpu_to_be64(jiffies); + hdr->phytype = htonl(4); /* dss_dot11_b */ + hdr->channel = htonl(local->channel); + hdr->datarate = htonl(rx_stats->rate); + hdr->antenna = htonl(0); /* unknown */ + hdr->priority = htonl(0); /* unknown */ + hdr->ssi_type = htonl(3); /* raw */ + hdr->ssi_signal = htonl(rx_stats->signal); + hdr->ssi_noise = htonl(rx_stats->noise); + hdr->preamble = htonl(0); /* unknown */ + hdr->encoding = htonl(1); /* cck */ + } + + ret = skb->len - phdrlen; + skb->dev = dev; + skb->mac.raw = skb->data; + skb_pull(skb, hdrlen); + if (prism_header) + skb_pull(skb, phdrlen); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); + + return ret; +} + + +/* Called only as a tasklet (software IRQ) */ +static void monitor_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct net_device_stats *stats; + int len; + + len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); + stats = hostap_get_stats(dev); + stats->rx_packets++; + stats->rx_bytes += len; +} + + +/* Called only as a tasklet (software IRQ) */ +static struct prism2_frag_entry * +prism2_frag_cache_find(local_info_t *local, unsigned int seq, + unsigned int frag, u8 *src, u8 *dst) +{ + struct prism2_frag_entry *entry; + int i; + + for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { + entry = &local->frag_cache[i]; + if (entry->skb != NULL && + time_after(jiffies, entry->first_frag_time + 2 * HZ)) { + printk(KERN_DEBUG "%s: expiring fragment cache entry " + "seq=%u last_frag=%u\n", + local->dev->name, entry->seq, entry->last_frag); + dev_kfree_skb(entry->skb); + entry->skb = NULL; + } + + if (entry->skb != NULL && entry->seq == seq && + (entry->last_frag + 1 == frag || frag == -1) && + memcmp(entry->src_addr, src, ETH_ALEN) == 0 && + memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) + return entry; + } + + return NULL; +} + + +/* Called only as a tasklet (software IRQ) */ +static struct sk_buff * +prism2_frag_cache_get(local_info_t *local, struct hostap_ieee80211_hdr *hdr) +{ + struct sk_buff *skb = NULL; + u16 sc; + unsigned int frag, seq; + struct prism2_frag_entry *entry; + + sc = le16_to_cpu(hdr->seq_ctrl); + frag = WLAN_GET_SEQ_FRAG(sc); + seq = WLAN_GET_SEQ_SEQ(sc); + + if (frag == 0) { + /* Reserve enough space to fit maximum frame length */ + skb = dev_alloc_skb(local->dev->mtu + + sizeof(struct hostap_ieee80211_hdr) + + 8 /* LLC */ + + 2 /* alignment */ + + 8 /* WEP */ + ETH_ALEN /* WDS */); + if (skb == NULL) + return NULL; + + entry = &local->frag_cache[local->frag_next_idx]; + local->frag_next_idx++; + if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) + local->frag_next_idx = 0; + + if (entry->skb != NULL) + dev_kfree_skb(entry->skb); + + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->last_frag = frag; + entry->skb = skb; + memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); + memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + } else { + /* received a fragment of a frame for which the head fragment + * should have already been received */ + entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, + hdr->addr1); + if (entry != NULL) { + entry->last_frag = frag; + skb = entry->skb; + } + } + + return skb; +} + + +/* Called only as a tasklet (software IRQ) */ +static int prism2_frag_cache_invalidate(local_info_t *local, + struct hostap_ieee80211_hdr *hdr) +{ + u16 sc; + unsigned int seq; + struct prism2_frag_entry *entry; + + sc = le16_to_cpu(hdr->seq_ctrl); + seq = WLAN_GET_SEQ_SEQ(sc); + + entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); + + if (entry == NULL) { + printk(KERN_DEBUG "%s: could not invalidate fragment cache " + "entry (seq=%u)\n", + local->dev->name, seq); + return -1; + } + + entry->skb = NULL; + return 0; +} + + +static inline int +hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, u16 type, + u16 stype) +{ + if (local->iw_mode == IW_MODE_MASTER) { + hostap_update_sta_ps(local, (struct hostap_ieee80211_hdr *) + skb->data); + } + + if (local->hostapd && type == WLAN_FC_TYPE_MGMT) { + if (stype == WLAN_FC_STYPE_BEACON && + local->iw_mode == IW_MODE_MASTER) { + struct sk_buff *skb2; + /* Process beacon frames also in kernel driver to + * update STA(AP) table statistics */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + hostap_rx(skb2->dev, skb2, rx_stats); + } + + /* send management frames to the user space daemon for + * processing */ + local->apdevstats.rx_packets++; + local->apdevstats.rx_bytes += skb->len; + prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); + return 0; + } + + if (local->iw_mode == IW_MODE_MASTER) { + if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { + printk(KERN_DEBUG "%s: unknown management frame " + "(type=0x%02x, stype=0x%02x) dropped\n", + skb->dev->name, type, stype); + return -1; + } + + hostap_rx(skb->dev, skb, rx_stats); + return 0; + } else { + printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " + "received in non-Host AP mode\n", skb->dev->name); + return -1; + } +} + + +/* Called only as a tasklet (software IRQ) */ +static inline struct net_device *prism2_rx_get_wds(local_info_t *local, + u8 *addr) +{ + struct hostap_interface *iface = NULL; + struct list_head *ptr; + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type == HOSTAP_INTERFACE_WDS && + memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) + break; + iface = NULL; + } + read_unlock_bh(&local->iface_lock); + + return iface ? iface->dev : NULL; +} + + +static inline int +hostap_rx_frame_wds(local_info_t *local, struct hostap_ieee80211_hdr *hdr, + u16 fc, struct net_device **wds) +{ + /* FIX: is this really supposed to accept WDS frames only in Master + * mode? What about Repeater or Managed with WDS frames? */ + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) != + (WLAN_FC_TODS | WLAN_FC_FROMDS) && + (local->iw_mode != IW_MODE_MASTER || !(fc & WLAN_FC_TODS))) + return 0; /* not a WDS frame */ + + /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) + * or own non-standard frame with 4th address after payload */ + if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 && + (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || + hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || + hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { + /* RA (or BSSID) is not ours - drop */ + PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " + "not own or broadcast %s=" MACSTR "\n", + local->dev->name, fc & WLAN_FC_FROMDS ? "RA" : "BSSID", + MAC2STR(hdr->addr1)); + return -1; + } + + /* check if the frame came from a registered WDS connection */ + *wds = prism2_rx_get_wds(local, hdr->addr2); + if (*wds == NULL && fc & WLAN_FC_FROMDS && + (local->iw_mode != IW_MODE_INFRA || + !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || + memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { + /* require that WDS link has been registered with TA or the + * frame is from current AP when using 'AP client mode' */ + PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " + "from unknown TA=" MACSTR "\n", + local->dev->name, MAC2STR(hdr->addr2)); + if (local->ap && local->ap->autom_ap_wds) + hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); + return -1; + } + + if (*wds && !(fc & WLAN_FC_FROMDS) && local->ap && + hostap_is_sta_assoc(local->ap, hdr->addr2)) { + /* STA is actually associated with us even though it has a + * registered WDS link. Assume it is in 'AP client' mode. + * Since this is a 3-addr frame, assume it is not (bogus) WDS + * frame and process it like any normal ToDS frame from + * associated STA. */ + *wds = NULL; + } + + return 0; +} + + +static int hostap_is_eapol_frame(local_info_t *local, + struct hostap_ieee80211_hdr *hdr, u8 *buf, + int len) +{ + struct net_device *dev = local->dev; + u16 fc, ethertype; + + fc = le16_to_cpu(hdr->frame_control); + + /* check that the frame is unicast frame to us */ + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (len < 8) + return 0; + + /* check for port access entity Ethernet type */ + ethertype = (buf[6] << 8) | buf[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + + +/* Called only as a tasklet (software IRQ) */ +static inline int +hostap_rx_frame_decrypt(local_info_t *local, int iswep, struct sk_buff *skb) +{ + struct hostap_ieee80211_hdr *hdr; + struct prism2_crypt_data *crypt; + void *sta = NULL; + int ret = 0, olen, len, hdrlen; + char *payload; + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + + len = skb->len - hdrlen; + payload = ((char *) (hdr)) + hdrlen; + crypt = local->crypt; + sta = NULL; + + /* Use station specific key to override default keys if the receiver + * address is a unicast address ("individual RA"). If bcrx_sta_key + * parameter is set, station specific key is used even with + * broad/multicast targets (this is against IEEE 802.11, but makes it + * easier to use different keys with stations that do not support WEP + * key mapping). */ + if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) + (void) hostap_handle_sta_crypto(local, hdr, &crypt, &sta); + + /* allow NULL decrypt to indicate an station specific override for + * default encryption */ + if (crypt && (crypt->ops == NULL || crypt->ops->decrypt == NULL)) + crypt = NULL; + + if (!crypt && iswep) { + printk(KERN_DEBUG "%s: WEP decryption failed (not set) (SA=" + MACSTR ")\n", local->dev->name, MAC2STR(hdr->addr2)); + local->comm_tallies.rx_discards_wep_undecryptable++; + ret = -1; + goto done; + } + + if (!crypt) + goto done; + + if (!iswep && !local->open_wep) { + if (local->ieee_802_1x && + hostap_is_eapol_frame(local, hdr, payload, len)) { + /* pass unencrypted EAPOL frames even if encryption is + * configured */ + printk(KERN_DEBUG "%s: RX: IEEE 802.1X - passing " + "unencrypted EAPOL frame\n", local->dev->name); + goto done; + } + printk(KERN_DEBUG "%s: encryption configured, but RX frame " + "not encrypted (SA=" MACSTR ")\n", + local->dev->name, MAC2STR(hdr->addr2)); + ret = -1; + goto done; + } + + /* decrypt WEP part of the frame: IV (4 bytes), encrypted + * payload (including SNAP header), ICV (4 bytes) */ + atomic_inc(&crypt->refcnt); + olen = crypt->ops->decrypt(payload, len, crypt->priv); + atomic_dec(&crypt->refcnt); + if (olen < 0) { + printk(KERN_DEBUG "%s: WEP decryption failed (SA=" MACSTR + ")\n", local->dev->name, MAC2STR(hdr->addr2)); + local->comm_tallies.rx_discards_wep_undecryptable++; + ret = -1; + goto done; + } + + skb_trim(skb, skb->len - (len - olen)); + + done: + if (sta) + hostap_handle_sta_release(sta); + + return ret; +} + + +/* All received frames are sent to this function. @skb contains the frame in + * IEEE 802.11 format, i.e., in the format it was sent over air. + * This function is called only as a tasklet (software IRQ). */ +void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hostap_ieee80211_hdr *hdr; + size_t hdrlen; + u16 fc, type, stype, sc; + struct net_device *wds = NULL; + struct net_device_stats *stats; + unsigned int frag; + u8 *payload; + struct sk_buff *skb2 = NULL; + u16 ethertype; + int frame_authorized = 0; + int from_assoc_ap = 0; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + stats = hostap_get_stats(dev); + + if (skb->len < 10) + goto rx_dropped; + + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctrl); + frag = WLAN_GET_SEQ_FRAG(sc); + hdrlen = hostap_80211_get_hdrlen(fc); + +#if WIRELESS_EXT > 15 + /* Put this code here so that we avoid duplicating it in all + * Rx paths. - Jean II */ +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + /* If spy monitoring on */ + if (iface->spy_data.spy_number > 0) { + struct iw_quality wstats; + wstats.level = rx_stats->signal; + wstats.noise = rx_stats->noise; + wstats.updated = 6; /* No qual value */ + /* Update spy records */ + wireless_spy_update(dev, hdr->addr2, &wstats); + } +#endif /* IW_WIRELESS_SPY */ +#endif /* WIRELESS_EXT > 15 */ + + if (local->iw_mode == IW_MODE_MONITOR) { + monitor_rx(dev, skb, rx_stats); + return; + } + + if (type != WLAN_FC_TYPE_DATA) { + if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && + fc & WLAN_FC_ISWEP && local->host_decrypt && + hostap_rx_frame_decrypt(local, fc & WLAN_FC_ISWEP, skb)) { + printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " + "from " MACSTR "\n", dev->name, + MAC2STR(hdr->addr2)); + /* TODO: could inform hostapd about this so that it + * could send auth failure report */ + goto rx_dropped; + } + + if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) + goto rx_dropped; + else + goto rx_exit; + } + + /* Data frame - extract src/dst addresses */ + if (skb->len < IEEE80211_DATA_HDR3_LEN) + goto rx_dropped; + + switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { + case WLAN_FC_FROMDS: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + break; + case WLAN_FC_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + break; + case WLAN_FC_FROMDS | WLAN_FC_TODS: + if (skb->len < IEEE80211_DATA_HDR4_LEN) + goto rx_dropped; + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + break; + case 0: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + break; + } + + if (hostap_rx_frame_wds(local, hdr, fc, &wds)) + goto rx_dropped; + if (wds) { + skb->dev = dev = wds; + stats = hostap_get_stats(dev); + } + + if (local->iw_mode == IW_MODE_MASTER && !wds && + (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && + local->stadev && + memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { + /* Frame from BSSID of the AP for which we are a client */ + skb->dev = dev = local->stadev; + stats = hostap_get_stats(dev); + from_assoc_ap = 1; + } + + dev->last_rx = jiffies; + + if (local->iw_mode == IW_MODE_MASTER && !from_assoc_ap) { + switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, + wds != NULL)) { + case AP_RX_CONTINUE_NOT_AUTHORIZED: + frame_authorized = 0; + break; + case AP_RX_CONTINUE: + frame_authorized = 1; + break; + case AP_RX_DROP: + goto rx_dropped; + case AP_RX_EXIT: + goto rx_exit; + } + } else if (local->iw_mode == IW_MODE_REPEAT || + local->wds_type & HOSTAP_WDS_AP_CLIENT) + hostap_update_rx_stats(local->ap, hdr, rx_stats); + + /* Nullfunc frames may have PS-bit set, so they must be passed to + * hostap_handle_sta_rx() before being dropped here. */ + if (stype != WLAN_FC_STYPE_DATA && + stype != WLAN_FC_STYPE_DATA_CFACK && + stype != WLAN_FC_STYPE_DATA_CFPOLL && + stype != WLAN_FC_STYPE_DATA_CFACKPOLL) { + if (stype != WLAN_FC_STYPE_NULLFUNC) + printk(KERN_DEBUG "%s: RX: dropped data frame " + "with no data (type=0x%02x, subtype=0x%02x)\n", + dev->name, type, stype); + goto rx_dropped; + } + + /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ + + if (local->host_decrypt && + hostap_rx_frame_decrypt(local, fc & WLAN_FC_ISWEP, skb)) + goto rx_dropped; + + /* skb: hdr + (possibly fragmented) plaintext payload */ + + if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && + (frag != 0 || (fc & WLAN_FC_MOREFRAG))) { + int flen; + struct sk_buff *frag_skb = + prism2_frag_cache_get(local, hdr); + if (!frag_skb) { + printk(KERN_DEBUG "%s: Rx cannot get skb from " + "fragment cache (morefrag=%d seq=%u frag=%u)\n", + dev->name, (fc & WLAN_FC_MOREFRAG) != 0, + WLAN_GET_SEQ_SEQ(sc), frag); + goto rx_dropped; + } + + flen = skb->len; + if (frag != 0) + flen -= hdrlen; + + if (frag_skb->tail + flen > frag_skb->end) { + printk(KERN_WARNING "%s: host decrypted and " + "reassembled frame did not fit skb\n", + dev->name); + prism2_frag_cache_invalidate(local, hdr); + goto rx_dropped; + } + + if (frag == 0) { + /* copy first fragment (including full headers) into + * beginning of the fragment cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data, flen); + } else { + /* append frame payload to the end of the fragment + * cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, + flen); + } + dev_kfree_skb(skb); + skb = NULL; + + if (fc & WLAN_FC_MOREFRAG) { + /* more fragments expected - leave the skb in fragment + * cache for now; it will be delivered to upper layers + * after all fragments have been received */ + goto rx_exit; + } + + /* this was the last fragment and the frame will be + * delivered, so remove skb from fragment cache */ + skb = frag_skb; + hdr = (struct hostap_ieee80211_hdr *) skb->data; + prism2_frag_cache_invalidate(local, hdr); + } + + /* skb: hdr + (possible reassembled) full plaintext payload */ + + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + /* If IEEE 802.1X is used, check whether the port is authorized to send + * the received frame. */ + if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { + if (ethertype == ETH_P_PAE) { + printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", + dev->name); + if (local->hostapd && local->apdev) { + /* Send IEEE 802.1X frames to the user + * space daemon for processing */ + prism2_rx_80211(local->apdev, skb, rx_stats, + PRISM2_RX_MGMT); + local->apdevstats.rx_packets++; + local->apdevstats.rx_bytes += skb->len; + goto rx_exit; + } + } else if (!frame_authorized) { + printk(KERN_DEBUG "%s: dropped frame from " + "unauthorized port (IEEE 802.1X): " + "ethertype=0x%04x\n", + dev->name, ethertype); + goto rx_dropped; + } + } + + /* convert hdr + possible LLC headers into Ethernet header */ + if (skb->len - hdrlen >= 8 && + ((memcmp(payload, rfc1042_header, 6) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(payload, bridge_tunnel_header, 6) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + skb_pull(skb, hdrlen); + len = htons(skb->len); + memcpy(skb_push(skb, 2), &len, 2); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } + + if (wds && ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS) && + skb->len >= ETH_HLEN + ETH_ALEN) { + /* Non-standard frame: get addr4 from its bogus location after + * the payload */ + memcpy(skb->data + ETH_ALEN, + skb->data + skb->len - ETH_ALEN, ETH_ALEN); + skb_trim(skb, skb->len - ETH_ALEN); + } + + stats->rx_packets++; + stats->rx_bytes += skb->len; + + if (local->iw_mode == IW_MODE_MASTER && !wds && + local->ap->bridge_packets) { + if (dst[0] & 0x01) { + /* copy multicast frame both to the higher layers and + * to the wireless media */ + local->ap->bridged_multicast++; + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL) + printk(KERN_DEBUG "%s: skb_clone failed for " + "multicast frame\n", dev->name); + } else if (hostap_is_sta_assoc(local->ap, dst)) { + /* send frame directly to the associated STA using + * wireless media and not passing to higher layers */ + local->ap->bridged_unicast++; + skb2 = skb; + skb = NULL; + } + } + + if (skb2 != NULL) { + /* send to wireless media */ + skb2->protocol = __constant_htons(ETH_P_802_3); + skb2->mac.raw = skb2->nh.raw = skb2->data; + /* skb2->nh.raw = skb2->data + ETH_HLEN; */ + dev_queue_xmit(skb2); + } + + if (skb) { + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + skb->dev = dev; + netif_rx(skb); + } + + rx_exit: + return; + + rx_dropped: + dev_kfree_skb(skb); + + stats->rx_dropped++; + goto rx_exit; +} + + +EXPORT_SYMBOL(hostap_80211_rx); diff -Nru a/drivers/net/wireless/hostap_ap.c b/drivers/net/wireless/hostap_ap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_ap.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3338 @@ +/* + * Intersil Prism2 driver with Host AP (software access point) support + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * This file is to be included into hostap.c when S/W AP functionality is + * compiled. + * + * AP: FIX: + * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from + * unauthenticated STA, send deauth. frame (8802.11: 5.5) + * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received + * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) + * - if unicast Class 3 received from unauthenticated STA, send deauth. frame + * (8802.11: 5.5) + */ + +static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, + DEF_INTS }; +MODULE_PARM(other_ap_policy, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); + +static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, + DEF_INTS }; +MODULE_PARM(ap_max_inactivity, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " + "inactivity"); + +static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; +MODULE_PARM(ap_bridge_packets, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " + "stations"); + +static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; +MODULE_PARM(autom_ap_wds, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " + "automatically"); + + +static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); +static void hostap_event_expired_sta(struct net_device *dev, + struct sta_info *sta); +static void handle_add_proc_queue(void *data); + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +static void handle_wds_oper_queue(void *data); +static void prism2_send_mgmt(struct net_device *dev, + int type, int subtype, char *body, + int body_len, int txevent, u8 *addr, + u16 tx_cb_idx); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +#ifndef PRISM2_NO_PROCFS_DEBUG +static int ap_debug_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ap_data *ap = (struct ap_data *) data; + + if (off != 0) { + *eof = 1; + return 0; + } + + p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); + p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); + p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ); + p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets); + p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack); + p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds); + p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs); + + return (p - page); +} +#endif /* PRISM2_NO_PROCFS_DEBUG */ + + +static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) +{ + sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; + ap->sta_hash[STA_HASH(sta->addr)] = sta; +} + +static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) +{ + struct sta_info *s; + + s = ap->sta_hash[STA_HASH(sta->addr)]; + if (s == NULL) return; + if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { + ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; + return; + } + + while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) + != 0) + s = s->hnext; + if (s->hnext != NULL) + s->hnext = s->hnext->hnext; + else + printk("AP: could not remove STA " MACSTR " from hash table\n", + MAC2STR(sta->addr)); +} + +static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) +{ + struct sk_buff *skb; + + if (sta->ap && sta->local) + hostap_event_expired_sta(sta->local->dev, sta); + + if (ap->proc != NULL) { + char name[20]; + sprintf(name, MACSTR, MAC2STR(sta->addr)); + remove_proc_entry(name, ap->proc); + } + + if (sta->crypt) { + sta->crypt->ops->deinit(sta->crypt->priv); + kfree(sta->crypt); + sta->crypt = NULL; + } + + while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) + dev_kfree_skb(skb); + + ap->num_sta--; +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (sta->aid > 0) + ap->sta_aid[sta->aid - 1] = NULL; + + if (!sta->ap && sta->u.sta.challenge) + kfree(sta->u.sta.challenge); + del_timer(&sta->timer); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + kfree(sta); +} + + +struct set_tim_data { + struct list_head list; + int aid; + int set; +}; + +static void hostap_set_tim(local_info_t *local, int aid, int set) +{ + struct list_head *ptr; + struct set_tim_data *new_entry; + + new_entry = (struct set_tim_data *) + kmalloc(sizeof(*new_entry), GFP_ATOMIC); + if (new_entry == NULL) { + printk(KERN_DEBUG "%s: hostap_set_tim: kmalloc failed\n", + local->dev->name); + return; + } + memset(new_entry, 0, sizeof(*new_entry)); + new_entry->aid = aid; + new_entry->set = set; + + spin_lock_bh(&local->ap->set_tim_lock); + for (ptr = local->ap->set_tim_list.next; + ptr != &local->ap->set_tim_list; + ptr = ptr->next) { + struct set_tim_data *entry = (struct set_tim_data *) ptr; + if (entry->aid == aid) { + PDEBUG(DEBUG_PS2, "%s: hostap_set_tim: aid=%d " + "set=%d ==> %d\n", + local->dev->name, aid, entry->set, set); + entry->set = set; + kfree(new_entry); + new_entry = NULL; + break; + } + } + if (new_entry) + list_add_tail(&new_entry->list, &local->ap->set_tim_list); + spin_unlock_bh(&local->ap->set_tim_lock); + + PRISM2_SCHEDULE_TASK(&local->ap->set_tim_queue); +} + + +static void handle_set_tim_queue(void *data) +{ + local_info_t *local = (local_info_t *) data; + struct set_tim_data *entry; + u16 val; + + for (;;) { + entry = NULL; + spin_lock_bh(&local->ap->set_tim_lock); + if (!list_empty(&local->ap->set_tim_list)) { + entry = list_entry(local->ap->set_tim_list.next, + struct set_tim_data, list); + list_del(&entry->list); + } + spin_unlock_bh(&local->ap->set_tim_lock); + if (!entry) + break; + + PDEBUG(DEBUG_PS2, "%s: hostap_set_tim_queue: aid=%d set=%d\n", + local->dev->name, entry->aid, entry->set); + + val = entry->aid; + if (entry->set) + val |= 0x8000; + if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { + printk(KERN_DEBUG "%s: set_tim failed (aid=%d " + "set=%d)\n", + local->dev->name, entry->aid, entry->set); + } + + kfree(entry); + } + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) +{ +#if WIRELESS_EXT >= 15 + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); +#endif /* WIRELESS_EXT >= 15 */ +} + + +static void hostap_event_expired_sta(struct net_device *dev, + struct sta_info *sta) +{ +#if WIRELESS_EXT >= 15 + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); +#endif /* WIRELESS_EXT >= 15 */ +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + +static void ap_handle_timer(unsigned long data) +{ + struct sta_info *sta = (struct sta_info *) data; + local_info_t *local; + struct ap_data *ap; + unsigned long next_time = 0; + int was_assoc; + + if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { + PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); + return; + } + + local = sta->local; + ap = local->ap; + was_assoc = sta->flags & WLAN_STA_ASSOC; + + if (atomic_read(&sta->users) != 0) + next_time = jiffies + HZ; + else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) + next_time = jiffies + ap->max_inactivity; + + if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { + /* station activity detected; reset timeout state */ + sta->timeout_next = STA_NULLFUNC; + next_time = sta->last_rx + ap->max_inactivity; + } else if (sta->timeout_next == STA_DISASSOC && + !(sta->flags & WLAN_STA_PENDING_POLL)) { + /* STA ACKed data nullfunc frame poll */ + sta->timeout_next = STA_NULLFUNC; + next_time = jiffies + ap->max_inactivity; + } + + if (next_time) { + sta->timer.expires = next_time; + add_timer(&sta->timer); + return; + } + + if (sta->ap) + sta->timeout_next = STA_DEAUTH; + + if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { + spin_lock(&ap->sta_table_lock); + ap_sta_hash_del(ap, sta); + list_del(&sta->list); + spin_unlock(&ap->sta_table_lock); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + } else if (sta->timeout_next == STA_DISASSOC) + sta->flags &= ~WLAN_STA_ASSOC; + + if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) + hostap_event_expired_sta(local->dev, sta); + + if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && + !skb_queue_empty(&sta->tx_buf)) { + hostap_set_tim(local, sta->aid, 0); + sta->flags &= ~WLAN_STA_TIM; + } + + if (sta->ap) { + if (ap->autom_ap_wds) { + PDEBUG(DEBUG_AP, "%s: removing automatic WDS " + "connection to AP " MACSTR "\n", + local->dev->name, MAC2STR(sta->addr)); + hostap_wds_link_oper(local, sta->addr, WDS_DEL); + } + } else if (sta->timeout_next == STA_NULLFUNC) { + /* send data frame to poll STA and check whether this frame + * is ACKed */ + /* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but + * it is apparently not retried so TX Exc events are not + * received for it */ + sta->flags |= WLAN_STA_PENDING_POLL; + prism2_send_mgmt(local->dev, WLAN_FC_TYPE_DATA, + WLAN_FC_STYPE_DATA, NULL, 0, 1, + sta->addr, ap->tx_callback_poll); + } else { + int deauth = sta->timeout_next == STA_DEAUTH; + u16 resp; + PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR + "(last=%lu, jiffies=%lu)\n", + local->dev->name, + deauth ? "deauthentication" : "disassociation", + MAC2STR(sta->addr), sta->last_rx, jiffies); + + resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + prism2_send_mgmt(local->dev, WLAN_FC_TYPE_MGMT, + (deauth ? WLAN_FC_STYPE_DEAUTH : + WLAN_FC_STYPE_DISASSOC), + (char *) &resp, 2, 1, sta->addr, 0); + } + + if (sta->timeout_next == STA_DEAUTH) { + if (sta->flags & WLAN_STA_PERM) { + PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been " + "removed, but it has 'perm' flag\n", + local->dev->name, MAC2STR(sta->addr)); + } else + ap_free_sta(ap, sta); + return; + } + + if (sta->timeout_next == STA_NULLFUNC) { + sta->timeout_next = STA_DISASSOC; + sta->timer.expires = jiffies + AP_DISASSOC_DELAY; + } else { + sta->timeout_next = STA_DEAUTH; + sta->timer.expires = jiffies + AP_DEAUTH_DELAY; + } + + add_timer(&sta->timer); +} + + +void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, + int resend) +{ + u8 addr[ETH_ALEN]; + u16 resp; + int i; + + PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); + memset(addr, 0xff, ETH_ALEN); + + resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); + + /* deauth message sent; try to resend it few times; the message is + * broadcast, so it may be delayed until next DTIM; there is not much + * else we can do at this point since the driver is going to be shut + * down */ + for (i = 0; i < 5; i++) { + prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH, + (char *) &resp, 2, 1, addr, 0); + + if (!resend || ap->num_sta <= 0) + return; + + mdelay(50); + } +} + + +static int ap_control_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ap_data *ap = (struct ap_data *) data; + char *policy_txt; + struct list_head *ptr; + struct mac_entry *entry; + + if (off != 0) { + *eof = 1; + return 0; + } + + switch (ap->mac_restrictions.policy) { + case MAC_POLICY_OPEN: + policy_txt = "open"; + break; + case MAC_POLICY_ALLOW: + policy_txt = "allow"; + break; + case MAC_POLICY_DENY: + policy_txt = "deny"; + break; + default: + policy_txt = "unknown"; + break; + }; + p += sprintf(p, "MAC policy: %s\n", policy_txt); + p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); + p += sprintf(p, "MAC list:\n"); + spin_lock_bh(&ap->mac_restrictions.lock); + for (ptr = ap->mac_restrictions.mac_list.next; + ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) { + if (p - page > PAGE_SIZE - 80) { + p += sprintf(p, "All entries did not fit one page.\n"); + break; + } + + entry = list_entry(ptr, struct mac_entry, list); + p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); + } + spin_unlock_bh(&ap->mac_restrictions.lock); + + return (p - page); +} + + +static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, + u8 *mac) +{ + struct mac_entry *entry; + + entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); + if (entry == NULL) + return -1; + + memcpy(entry->addr, mac, ETH_ALEN); + + spin_lock_bh(&mac_restrictions->lock); + list_add_tail(&entry->list, &mac_restrictions->mac_list); + mac_restrictions->entries++; + spin_unlock_bh(&mac_restrictions->lock); + + return 0; +} + + +static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, + u8 *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + + spin_lock_bh(&mac_restrictions->lock); + for (ptr = mac_restrictions->mac_list.next; + ptr != &mac_restrictions->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, list); + + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + list_del(ptr); + kfree(entry); + mac_restrictions->entries--; + spin_unlock_bh(&mac_restrictions->lock); + return 0; + } + } + spin_unlock_bh(&mac_restrictions->lock); + return -1; +} + + +static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, + u8 *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + int found = 0; + + if (mac_restrictions->policy == MAC_POLICY_OPEN) + return 0; + + spin_lock_bh(&mac_restrictions->lock); + for (ptr = mac_restrictions->mac_list.next; + ptr != &mac_restrictions->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, list); + + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + found = 1; + break; + } + } + spin_unlock_bh(&mac_restrictions->lock); + + if (mac_restrictions->policy == MAC_POLICY_ALLOW) + return !found; + else + return found; +} + + +static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) +{ + struct list_head *ptr, *n; + struct mac_entry *entry; + + if (mac_restrictions->entries == 0) + return; + + spin_lock_bh(&mac_restrictions->lock); + for (ptr = mac_restrictions->mac_list.next, n = ptr->next; + ptr != &mac_restrictions->mac_list; + ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct mac_entry, list); + list_del(ptr); + kfree(entry); + } + mac_restrictions->entries = 0; + spin_unlock_bh(&mac_restrictions->lock); +} + + +static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, + u8 *mac) +{ + struct sta_info *sta; + u16 resp; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, mac); + if (sta) { + ap_sta_hash_del(ap, sta); + list_del(&sta->list); + } + spin_unlock_bh(&ap->sta_table_lock); + + if (!sta) + return -EINVAL; + + resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); + prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH, + (char *) &resp, 2, 1, sta->addr, 0); + + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) + hostap_event_expired_sta(dev, sta); + + ap_free_sta(ap, sta); + + return 0; +} + +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +static void ap_control_kickall(struct ap_data *ap) +{ + struct list_head *ptr, *n; + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; + ptr = n, n = ptr->next) { + sta = list_entry(ptr, struct sta_info, list); + ap_sta_hash_del(ap, sta); + list_del(&sta->list); + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) + hostap_event_expired_sta(sta->local->dev, sta); + ap_free_sta(ap, sta); + } + spin_unlock_bh(&ap->sta_table_lock); +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + +#define PROC_LIMIT (PAGE_SIZE - 80) + +static int prism2_ap_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ap_data *ap = (struct ap_data *) data; + struct list_head *ptr; + int i; + + if (off > PROC_LIMIT) { + *eof = 1; + return 0; + } + + p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); + spin_lock_bh(&ap->sta_table_lock); + for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { + struct sta_info *sta = (struct sta_info *) ptr; + + if (!sta->ap) + continue; + + p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), + sta->u.ap.channel, sta->last_rx_signal, + sta->last_rx_silence, sta->last_rx_rate); + for (i = 0; i < sta->u.ap.ssid_len; i++) + p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && + sta->u.ap.ssid[i] < 127) ? + "%c" : "<%02x>"), + sta->u.ap.ssid[i]); + p += sprintf(p, "'"); + if (sta->capability & WLAN_CAPABILITY_ESS) + p += sprintf(p, " [ESS]"); + if (sta->capability & WLAN_CAPABILITY_IBSS) + p += sprintf(p, " [IBSS]"); + if (sta->capability & WLAN_CAPABILITY_PRIVACY) + p += sprintf(p, " [WEP]"); + p += sprintf(p, "\n"); + + if ((p - page) > PROC_LIMIT) { + printk(KERN_DEBUG "hostap: ap proc did not fit\n"); + break; + } + } + spin_unlock_bh(&ap->sta_table_lock); + + if ((p - page) <= off) { + *eof = 1; + return 0; + } + + *start = page + off; + + return (p - page - off); +} +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) +{ + if (!ap) + return; + + if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { + PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " + "firmware upgrade recommended\n"); + ap->nullfunc_ack = 1; + } else + ap->nullfunc_ack = 0; + + if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { + printk(KERN_WARNING "%s: Warning: secondary station firmware " + "version 1.4.2 does not seem to work in Host AP mode\n", + ap->local->dev->name); + } +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) +{ + struct ap_data *ap = data; + u16 fc; + struct hostap_ieee80211_hdr *hdr; + + if (!ap->local->hostapd || !ap->local->apdev) { + dev_kfree_skb(skb); + return; + } + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + /* Pass the TX callback frame to the hostapd; use 802.11 header version + * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ + + fc &= ~WLAN_FC_PVER; + fc |= ok ? BIT(1) : BIT(0); + hdr->frame_control = cpu_to_le16(fc); + + skb->dev = ap->local->apdev; + skb_pull(skb, hostap_80211_get_hdrlen(fc)); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +/* Called only as a tasklet (software IRQ) */ +static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) +{ + struct ap_data *ap = data; + struct net_device *dev = ap->local->dev; + struct hostap_ieee80211_hdr *hdr; + u16 fc, *pos, auth_alg, auth_transaction, status; + struct sta_info *sta = NULL; + char *txt = NULL; + + if (ap->local->hostapd) { + dev_kfree_skb(skb); + return; + } + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_AUTH || + skb->len < IEEE80211_MGMT_HDR_LEN + 6) { + printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " + "frame\n", dev->name); + dev_kfree_skb(skb); + return; + } + + if (!ok) { + txt = "frame was not ACKed"; + goto done; + } + + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, hdr->addr1); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&ap->sta_table_lock); + + if (!sta) { + txt = "STA not found"; + goto done; + } + + pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + auth_alg = le16_to_cpu(*pos++); + auth_transaction = le16_to_cpu(*pos++); + status = le16_to_cpu(*pos++); + if (status == WLAN_STATUS_SUCCESS && + ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || + (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { + txt = "STA authenticated"; + sta->flags |= WLAN_STA_AUTH; + sta->last_auth = jiffies; + } else if (status != WLAN_STATUS_SUCCESS) + txt = "authentication failed"; + + done: + if (sta) + atomic_dec(&sta->users); + if (txt) { + PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - %s\n", + dev->name, MAC2STR(hdr->addr1), txt); + } + dev_kfree_skb(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) +{ + struct ap_data *ap = data; + struct net_device *dev = ap->local->dev; + struct hostap_ieee80211_hdr *hdr; + u16 fc, *pos, status; + struct sta_info *sta = NULL; + char *txt = NULL; + + if (ap->local->hostapd) { + dev_kfree_skb(skb); + return; + } + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ASSOC_RESP && + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_REASSOC_RESP) || + skb->len < IEEE80211_MGMT_HDR_LEN + 4) { + printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " + "frame\n", dev->name); + dev_kfree_skb(skb); + return; + } + + if (!ok) { + txt = "frame was not ACKed"; + goto done; + } + + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, hdr->addr1); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&ap->sta_table_lock); + + if (!sta) { + txt = "STA not found"; + goto done; + } + + pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + pos++; + status = le16_to_cpu(*pos++); + if (status == WLAN_STATUS_SUCCESS) { + if (!(sta->flags & WLAN_STA_ASSOC)) + hostap_event_new_sta(dev, sta); + txt = "STA associated"; + sta->flags |= WLAN_STA_ASSOC; + sta->last_assoc = jiffies; + } else + txt = "association failed"; + + done: + if (sta) + atomic_dec(&sta->users); + if (txt) { + PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", + dev->name, MAC2STR(hdr->addr1), txt); + } + dev_kfree_skb(skb); +} + +/* Called only as a tasklet (software IRQ); TX callback for poll frames used + * in verifying whether the STA is still present. */ +static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) +{ + struct ap_data *ap = data; + struct net_device *dev = ap->local->dev; + struct hostap_ieee80211_hdr *hdr; + struct sta_info *sta; + + if (skb->len < 24) + goto fail; + hdr = (struct hostap_ieee80211_hdr *) skb->data; + if (ok) { + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, hdr->addr1); + if (sta) + sta->flags &= ~WLAN_STA_PENDING_POLL; + spin_unlock(&ap->sta_table_lock); + } else { + PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " + "poll frame\n", dev->name, MAC2STR(hdr->addr1)); + } + + fail: + dev_kfree_skb(skb); +} +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +void hostap_init_data(local_info_t *local) +{ + struct ap_data *ap = local->ap; + + if (ap == NULL) { + printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); + return; + } + memset(ap, 0, sizeof(struct ap_data)); + ap->local = local; + + ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); + ap->proc = local->proc; + ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); + ap->max_inactivity = + GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; + ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); + + spin_lock_init(&ap->sta_table_lock); + INIT_LIST_HEAD(&ap->sta_list); + +#ifndef PRISM2_NO_PROCFS_DEBUG + if (ap->proc != NULL) { + create_proc_read_entry("ap_debug", 0, ap->proc, + ap_debug_proc_read, ap); + } +#endif /* PRISM2_NO_PROCFS_DEBUG */ + + /* Initialize task queue structure for AP management */ + INIT_WORK(&local->ap->set_tim_queue, handle_set_tim_queue, local); + INIT_LIST_HEAD(&ap->set_tim_list); + spin_lock_init(&ap->set_tim_lock); + + INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); + + ap->tx_callback_idx = + hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); + if (ap->tx_callback_idx == 0) + printk(KERN_WARNING "%s: failed to register TX callback for " + "AP\n", local->dev->name); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); + + ap->tx_callback_auth = + hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); + ap->tx_callback_assoc = + hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); + ap->tx_callback_poll = + hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); + if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || + ap->tx_callback_poll == 0) + printk(KERN_WARNING "%s: failed to register TX callback for " + "AP\n", local->dev->name); + + spin_lock_init(&ap->mac_restrictions.lock); + INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); + if (ap->proc != NULL) { + create_proc_read_entry("ap_control", 0, ap->proc, + ap_control_proc_read, ap); + } + + create_proc_read_entry("ap", 0, ap->proc, + prism2_ap_proc_read, ap); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + ap->initialized = 1; +} + +void hostap_free_data(struct ap_data *ap) +{ + struct list_head *ptr, *n; + + if (ap == NULL || !ap->initialized) { + printk(KERN_DEBUG "hostap_free_data: ap has not yet been " + "initialized - skip resource freeing\n"); + return; + } + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (ap->crypt) + ap->crypt->deinit(ap->crypt_priv); + ap->crypt = ap->crypt_priv = NULL; +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + ptr = ap->sta_list.next; + while (ptr != NULL && ptr != &ap->sta_list) { + struct sta_info *sta = (struct sta_info *) ptr; + ptr = ptr->next; + ap_sta_hash_del(ap, sta); + list_del(&sta->list); + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) + hostap_event_expired_sta(sta->local->dev, sta); + ap_free_sta(ap, sta); + } + + for (ptr = ap->set_tim_list.next, n = ptr->next; + ptr != &ap->set_tim_list; ptr = n, n = ptr->next) { + struct set_tim_data *entry; + entry = list_entry(ptr, struct set_tim_data, list); + list_del(&entry->list); + kfree(entry); + } + +#ifndef PRISM2_NO_PROCFS_DEBUG + if (ap->proc != NULL) { + remove_proc_entry("ap_debug", ap->proc); + } +#endif /* PRISM2_NO_PROCFS_DEBUG */ + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (ap->proc != NULL) { + remove_proc_entry("ap", ap->proc); + remove_proc_entry("ap_control", ap->proc); + } + ap_control_flush_macs(&ap->mac_restrictions); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + ap->initialized = 0; +} + + +/* caller should have mutex for AP STA list handling */ +static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) +{ + struct sta_info *s; + + s = ap->sta_hash[STA_HASH(sta)]; + while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0) + s = s->hnext; + return s; +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + +/* Called from timer handler and from scheduled AP queue handlers */ +static void prism2_send_mgmt(struct net_device *dev, + int type, int subtype, char *body, + int body_len, int txevent, u8 *addr, + u16 tx_cb_idx) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_tx_frame *txdesc; + u16 fc, tx_control; + struct sk_buff *skb; + + if (!(dev->flags & IFF_UP)) { + PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " + "cannot send frame\n", dev->name); + return; + } + + skb = dev_alloc_skb(sizeof(*txdesc) + body_len); + if (skb == NULL) { + PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " + "skb\n", dev->name); + return; + } + + txdesc = (struct hfa384x_tx_frame *) skb_put(skb, sizeof(*txdesc)); + if (body) + memcpy(skb_put(skb, body_len), body, body_len); + + memset(txdesc, 0, sizeof(*txdesc)); + /* FIX: set tx_rate if f/w does not know how to do it */ + tx_control = txevent ? local->tx_control : HFA384X_TX_CTRL_802_11; + if (tx_cb_idx) + tx_control |= HFA384X_TX_CTRL_TX_OK; + txdesc->sw_support = cpu_to_le16(tx_cb_idx); + txdesc->tx_control = cpu_to_le16(tx_control); + txdesc->data_len = cpu_to_le16(body_len); + + fc = (type << 2) | (subtype << 4); + + memcpy(txdesc->addr1, addr, ETH_ALEN); /* DA / RA */ + if (type == WLAN_FC_TYPE_DATA) { + fc |= WLAN_FC_FROMDS; + memcpy(txdesc->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ + memcpy(txdesc->addr3, dev->dev_addr, ETH_ALEN); /* SA */ + } else if (type == WLAN_FC_TYPE_CTRL) { + /* control:ACK does not have addr2 or addr3 */ + memset(txdesc->addr2, 0, ETH_ALEN); + memset(txdesc->addr3, 0, ETH_ALEN); + } else { + memcpy(txdesc->addr2, dev->dev_addr, ETH_ALEN); /* SA */ + memcpy(txdesc->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ + } + + txdesc->frame_control = cpu_to_le16(fc); + + /* FIX: is it OK to call dev_queue_xmit() here? This can be called in + * interrupt context, but not in hard interrupt (like prism2_rx() that + * required bridge_list. If needed, bridge_list could be used also here + * when prism2_send_mgmt is called in interrupt context. */ + + skb->protocol = __constant_htons(ETH_P_HOSTAP); + skb->dev = dev; + skb->mac.raw = skb->nh.raw = skb->data; + dev_queue_xmit(skb); +} +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +static int prism2_sta_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct sta_info *sta = (struct sta_info *) data; + int i; + + /* FIX: possible race condition.. the STA data could have just expired, + * but proc entry was still here so that the read could have started; + * some locking should be done here.. */ + + if (off != 0) { + *eof = 1; + return 0; + } + + p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" + "flags=0x%04x%s%s%s%s%s%s%s\n" + "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", + sta->ap ? "AP" : "STA", + MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, + sta->flags, + sta->flags & WLAN_STA_AUTH ? " AUTH" : "", + sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", + sta->flags & WLAN_STA_PS ? " PS" : "", + sta->flags & WLAN_STA_TIM ? " TIM" : "", + sta->flags & WLAN_STA_PERM ? " PERM" : "", + sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", + sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", + sta->capability, sta->listen_interval); + /* supported_rates: 500 kbit/s units with msb ignored */ + for (i = 0; i < sizeof(sta->supported_rates); i++) + if (sta->supported_rates[i] != 0) + p += sprintf(p, "%d%sMbps ", + (sta->supported_rates[i] & 0x7f) / 2, + sta->supported_rates[i] & 1 ? ".5" : ""); + p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" + "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" + "tx_packets=%lu\n" + "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" + "last_rx: silence=%d signal=%d rate=%d\n" + "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" + "tx[11M]=%d\n" + "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", + jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, + sta->last_tx, + sta->rx_packets, sta->tx_packets, sta->rx_bytes, + sta->tx_bytes, skb_queue_len(&sta->tx_buf), + sta->last_rx_silence, + sta->last_rx_signal, sta->last_rx_rate, + sta->tx_rate, sta->tx_count[0], sta->tx_count[1], + sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], + sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); + if (sta->crypt && sta->crypt->ops) + p += sprintf(p, "crypt=%s\n", sta->crypt->ops->name); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (sta->ap) { + if (sta->u.ap.channel >= 0) + p += sprintf(p, "channel=%d\n", sta->u.ap.channel); + p += sprintf(p, "ssid="); + for (i = 0; i < sta->u.ap.ssid_len; i++) + p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && + sta->u.ap.ssid[i] < 127) ? + "%c" : "<%02x>"), + sta->u.ap.ssid[i]); + p += sprintf(p, "\n"); + } +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + return (p - page); +} + + +static void handle_add_proc_queue(void *data) +{ + struct ap_data *ap = (struct ap_data *) data; + struct sta_info *sta; + char name[20]; + struct add_sta_proc_data *entry, *prev; + + entry = ap->add_sta_proc_entries; + ap->add_sta_proc_entries = NULL; + + while (entry) { + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, entry->addr); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&ap->sta_table_lock); + + if (sta) { + sprintf(name, MACSTR, MAC2STR(sta->addr)); + sta->proc = create_proc_read_entry( + name, 0, ap->proc, + prism2_sta_proc_read, sta); + + atomic_dec(&sta->users); + } + + prev = entry; + entry = entry->next; + kfree(prev); + } + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) +{ + struct sta_info *sta; + + sta = (struct sta_info *) + kmalloc(sizeof(struct sta_info), GFP_ATOMIC); + if (sta == NULL) { + PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); + return NULL; + } + + /* initialize STA info data */ + memset(sta, 0, sizeof(struct sta_info)); + sta->local = ap->local; + skb_queue_head_init(&sta->tx_buf); + memcpy(sta->addr, addr, ETH_ALEN); + + atomic_inc(&sta->users); + spin_lock_bh(&ap->sta_table_lock); + list_add(&sta->list, &ap->sta_list); + ap->num_sta++; + ap_sta_hash_add(ap, sta); + spin_unlock_bh(&ap->sta_table_lock); + + if (ap->proc) { + struct add_sta_proc_data *entry; + /* schedule a non-interrupt context process to add a procfs + * entry for the STA since procfs code use GFP_KERNEL */ + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (entry) { + memcpy(entry->addr, sta->addr, ETH_ALEN); + entry->next = ap->add_sta_proc_entries; + ap->add_sta_proc_entries = entry; + PRISM2_SCHEDULE_TASK(&ap->add_sta_proc_queue); + } else + printk(KERN_DEBUG "Failed to add STA proc data\n"); + } + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + init_timer(&sta->timer); + sta->timer.expires = jiffies + ap->max_inactivity; + sta->timer.data = (unsigned long) sta; + sta->timer.function = ap_handle_timer; + if (!ap->local->hostapd) + add_timer(&sta->timer); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + return sta; +} + + +static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, + local_info_t *local) +{ + if (rateidx > sta->tx_max_rate || + !(sta->tx_supp_rates & (1 << rateidx))) + return 0; + + if (local->tx_rate_control != 0 && + !(local->tx_rate_control & (1 << rateidx))) + return 0; + + return 1; +} + + +static void prism2_check_tx_rates(struct sta_info *sta) +{ + int i; + + sta->tx_supp_rates = 0; + for (i = 0; i < sizeof(sta->supported_rates); i++) { + if ((sta->supported_rates[i] & 0x7f) == 2) + sta->tx_supp_rates |= WLAN_RATE_1M; + if ((sta->supported_rates[i] & 0x7f) == 4) + sta->tx_supp_rates |= WLAN_RATE_2M; + if ((sta->supported_rates[i] & 0x7f) == 11) + sta->tx_supp_rates |= WLAN_RATE_5M5; + if ((sta->supported_rates[i] & 0x7f) == 22) + sta->tx_supp_rates |= WLAN_RATE_11M; + } + sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; + if (sta->tx_supp_rates & WLAN_RATE_1M) { + sta->tx_max_rate = 0; + if (ap_tx_rate_ok(0, sta, sta->local)) { + sta->tx_rate = 10; + sta->tx_rate_idx = 0; + } + } + if (sta->tx_supp_rates & WLAN_RATE_2M) { + sta->tx_max_rate = 1; + if (ap_tx_rate_ok(1, sta, sta->local)) { + sta->tx_rate = 20; + sta->tx_rate_idx = 1; + } + } + if (sta->tx_supp_rates & WLAN_RATE_5M5) { + sta->tx_max_rate = 2; + if (ap_tx_rate_ok(2, sta, sta->local)) { + sta->tx_rate = 55; + sta->tx_rate_idx = 2; + } + } + if (sta->tx_supp_rates & WLAN_RATE_11M) { + sta->tx_max_rate = 3; + if (ap_tx_rate_ok(3, sta, sta->local)) { + sta->tx_rate = 110; + sta->tx_rate_idx = 3; + } + } +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + +static void ap_crypt_init(struct ap_data *ap) +{ + ap->crypt = hostap_get_crypto_ops("WEP"); + + if (ap->crypt) { + if (ap->crypt->init) { + ap->crypt_priv = ap->crypt->init(); + if (ap->crypt_priv == NULL) + ap->crypt = NULL; + else { + u8 key[WEP_KEY_LEN]; + get_random_bytes(key, WEP_KEY_LEN); + ap->crypt->set_key(0, key, WEP_KEY_LEN, + ap->crypt_priv); + } + } + } + + if (ap->crypt == NULL) { + printk(KERN_WARNING "AP could not initialize WEP: load module " + "hostap_crypt_wep.o\n"); + } +} + + +/* Generate challenge data for shared key authentication. IEEE 802.11 specifies + * that WEP algorithm is used for generating challange. This should be unique, + * but otherwise there is not really need for randomness etc. Initialize WEP + * with pseudo random key and then use increasing IV to get unique challenge + * streams. + * + * Called only as a scheduled task for pending AP frames. + */ +static char * ap_auth_make_challenge(struct ap_data *ap) +{ + char *tmpbuf; + int olen; + + if (ap->crypt == NULL) { + ap_crypt_init(ap); + if (ap->crypt == NULL) + return NULL; + } + + tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN + + ap->crypt->extra_prefix_len + + ap->crypt->extra_postfix_len, + GFP_ATOMIC); + if (tmpbuf == NULL) { + PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); + return NULL; + } + memset(tmpbuf, 0, WLAN_AUTH_CHALLENGE_LEN + + ap->crypt->extra_prefix_len + ap->crypt->extra_postfix_len); + olen = ap->crypt->encrypt(tmpbuf, WLAN_AUTH_CHALLENGE_LEN, + ap->crypt_priv); + if (olen < 0) { + kfree(tmpbuf); + return NULL; + } + memmove(tmpbuf, tmpbuf + 4, WLAN_AUTH_CHALLENGE_LEN); + return tmpbuf; +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_authen(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct net_device *dev = local->dev; + struct hostap_ieee80211_hdr *hdr = + (struct hostap_ieee80211_hdr *) skb->data; + struct ap_data *ap = local->ap; + char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; + int len, olen; + u16 auth_alg, auth_transaction, status_code, *pos; + u16 resp = WLAN_STATUS_SUCCESS, fc; + struct sta_info *sta = NULL; + struct prism2_crypt_data *crypt; + char *txt = ""; + + len = skb->len - IEEE80211_MGMT_HDR_LEN; + + fc = le16_to_cpu(hdr->frame_control); + + if (len < 6) { + PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " + "(len=%d) from " MACSTR "\n", dev->name, len, + MAC2STR(hdr->addr2)); + return; + } + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&local->ap->sta_table_lock); + + if (sta && sta->crypt) + crypt = sta->crypt; + else + crypt = local->crypt; + + if (crypt && local->host_decrypt && (fc & WLAN_FC_ISWEP)) { + atomic_inc(&crypt->refcnt); + olen = crypt->ops->decrypt( + (u8 *) (skb->data + IEEE80211_MGMT_HDR_LEN), len, + crypt->priv); + atomic_dec(&crypt->refcnt); + if (olen < 0) { + if (sta) + atomic_dec(&sta->users); + PDEBUG(DEBUG_AP, "%s: handle_authen: auth frame from " + "STA " MACSTR " could not be decrypted\n", + dev->name, MAC2STR(hdr->addr2)); + return; + } + if (olen < 6) { + PDEBUG(DEBUG_AP, "%s: handle_authen - too short " + "payload (len=%d, decrypted len=%d) from " + MACSTR "\n", + dev->name, len, olen, MAC2STR(hdr->addr2)); + return; + } + len = olen; + } + + pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + auth_alg = __le16_to_cpu(*pos); + pos++; + auth_transaction = __le16_to_cpu(*pos); + pos++; + status_code = __le16_to_cpu(*pos); + pos++; + + if (ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { + txt = "authentication denied"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + + if (((local->auth_algs & PRISM2_AUTH_OPEN) && + auth_alg == WLAN_AUTH_OPEN) || + ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && + crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { + } else { + txt = "unsupported algorithm"; + resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + goto fail; + } + + if (len >= 8) { + u8 *u = (u8 *) pos; + if (*u == WLAN_EID_CHALLENGE) { + if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { + txt = "invalid challenge len"; + resp = WLAN_STATUS_CHALLENGE_FAIL; + goto fail; + } + if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { + txt = "challenge underflow"; + resp = WLAN_STATUS_CHALLENGE_FAIL; + goto fail; + } + challenge = (char *) (u + 2); + } + } + + if (sta && sta->ap) { + if (time_after(jiffies, sta->u.ap.last_beacon + + (10 * sta->listen_interval * HZ) / 1024)) { + PDEBUG(DEBUG_AP, "%s: no beacons received for a while," + " assuming AP " MACSTR " is now STA\n", + dev->name, MAC2STR(sta->addr)); + sta->ap = 0; + sta->flags = 0; + sta->u.sta.challenge = NULL; + } else { + txt = "AP trying to authenticate?"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + } + + if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || + (auth_alg == WLAN_AUTH_SHARED_KEY && + (auth_transaction == 1 || + (auth_transaction == 3 && sta != NULL && + sta->u.sta.challenge != NULL)))) { + } else { + txt = "unknown authentication transaction number"; + resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + goto fail; + } + + if (sta == NULL) { + txt = "new STA"; + + if (local->ap->num_sta >= MAX_STA_COUNT) { + /* FIX: might try to remove some old STAs first? */ + txt = "no more room for new STAs"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + + sta = ap_add_sta(local->ap, hdr->addr2); + if (sta == NULL) { + txt = "ap_add_sta failed"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + } + + hostap_ap_update_sq(sta, rx_stats); + + switch (auth_alg) { + case WLAN_AUTH_OPEN: + txt = "authOK"; + /* IEEE 802.11 standard is not completely clear about + * whether STA is considered authenticated after + * authentication OK frame has been send or after it + * has been ACKed. In order to reduce interoperability + * issues, mark the STA authenticated before ACK. */ + sta->flags |= WLAN_STA_AUTH; + break; + + case WLAN_AUTH_SHARED_KEY: + if (auth_transaction == 1) { + if (sta->u.sta.challenge == NULL) { + sta->u.sta.challenge = + ap_auth_make_challenge(local->ap); + if (sta->u.sta.challenge == NULL) { + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + } + } else { + if (sta->u.sta.challenge == NULL || + challenge == NULL || + memcmp(sta->u.sta.challenge, challenge, + WLAN_AUTH_CHALLENGE_LEN) != 0 || + !(fc & WLAN_FC_ISWEP)) { + txt = "challenge response incorrect"; + resp = WLAN_STATUS_CHALLENGE_FAIL; + goto fail; + } + + txt = "challenge OK - authOK"; + /* IEEE 802.11 standard is not completely clear about + * whether STA is considered authenticated after + * authentication OK frame has been send or after it + * has been ACKed. In order to reduce interoperability + * issues, mark the STA authenticated before ACK. */ + sta->flags |= WLAN_STA_AUTH; + kfree(sta->u.sta.challenge); + sta->u.sta.challenge = NULL; + } + break; + } + + fail: + pos = (u16 *) body; + *pos = cpu_to_le16(auth_alg); + pos++; + *pos = cpu_to_le16(auth_transaction + 1); + pos++; + *pos = cpu_to_le16(resp); /* status_code */ + pos++; + olen = 6; + + if (resp == WLAN_STATUS_SUCCESS && sta != NULL && + sta->u.sta.challenge != NULL && + auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { + u8 *tmp = (u8 *) pos; + *tmp++ = WLAN_EID_CHALLENGE; + *tmp++ = WLAN_AUTH_CHALLENGE_LEN; + pos++; + memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); + olen += 2 + WLAN_AUTH_CHALLENGE_LEN; + } + + prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_AUTH, + body, olen, 1, hdr->addr2, ap->tx_callback_auth); + + if (sta) { + sta->last_rx = jiffies; + atomic_dec(&sta->users); + } + +#if 0 + PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d stat=%d len=%d" + " fc=%04x) ==> %d (%s)\n", dev->name, MAC2STR(hdr->addr2), + auth_alg, auth_transaction, status_code, len, fc, resp, txt); +#endif +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_assoc(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, int reassoc) +{ + struct net_device *dev = local->dev; + struct hostap_ieee80211_hdr *hdr = + (struct hostap_ieee80211_hdr *) skb->data; + char body[12], *p, *lpos; + int len, left; + u16 *pos; + u16 resp = WLAN_STATUS_SUCCESS; + struct sta_info *sta = NULL; + int send_deauth = 0; + char *txt = ""; + u8 prev_ap[ETH_ALEN]; + + left = len = skb->len - IEEE80211_MGMT_HDR_LEN; + + if (len < (reassoc ? 10 : 4)) { + PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " + "(len=%d, reassoc=%d) from " MACSTR "\n", + dev->name, len, reassoc, MAC2STR(hdr->addr2)); + return; + } + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { + spin_unlock_bh(&local->ap->sta_table_lock); + txt = "trying to associate before authentication"; + send_deauth = 1; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + sta = NULL; /* do not decrement sta->users */ + goto fail; + } + atomic_inc(&sta->users); + spin_unlock_bh(&local->ap->sta_table_lock); + + hostap_ap_update_sq(sta, rx_stats); + + pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + sta->capability = __le16_to_cpu(*pos); + pos++; left -= 2; + sta->listen_interval = __le16_to_cpu(*pos); + pos++; left -= 2; + + if (reassoc) { + memcpy(prev_ap, pos, ETH_ALEN); + pos++; pos++; pos++; left -= 6; + } else + memset(prev_ap, 0, ETH_ALEN); + + if (left >= 2) { + unsigned int ileft; + unsigned char *u = (unsigned char *) pos; + + if (*u == WLAN_EID_SSID) { + u++; left--; + ileft = *u; + u++; left--; + + if (ileft > left || ileft > MAX_SSID_LEN) { + txt = "SSID overflow"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + + if (ileft != strlen(local->essid) || + memcmp(local->essid, u, ileft) != 0) { + txt = "not our SSID"; + resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; + goto fail; + } + + u += ileft; + left -= ileft; + } + + if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { + u++; left--; + ileft = *u; + u++; left--; + + if (ileft > left || ileft == 0 || + ileft > WLAN_SUPP_RATES_MAX) { + txt = "SUPP_RATES len error"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + + memset(sta->supported_rates, 0, + sizeof(sta->supported_rates)); + memcpy(sta->supported_rates, u, ileft); + prism2_check_tx_rates(sta); + + u += ileft; + left -= ileft; + } + + if (left > 0) { + PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" + " data (%d bytes) [", + dev->name, MAC2STR(hdr->addr2), left); + while (left > 0) { + PDEBUG2(DEBUG_AP, "<%02x>", *u); + u++; left--; + } + PDEBUG2(DEBUG_AP, "]\n"); + } + } else { + txt = "frame underflow"; + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + + /* get a unique AID */ + if (sta->aid > 0) + txt = "OK, old AID"; + else { + spin_lock_bh(&local->ap->sta_table_lock); + for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) + if (local->ap->sta_aid[sta->aid - 1] == NULL) + break; + if (sta->aid > MAX_AID_TABLE_SIZE) { + sta->aid = 0; + spin_unlock_bh(&local->ap->sta_table_lock); + resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + txt = "no room for more AIDs"; + } else { + local->ap->sta_aid[sta->aid - 1] = sta; + spin_unlock_bh(&local->ap->sta_table_lock); + txt = "OK, new AID"; + } + } + + fail: + pos = (u16 *) body; + + if (send_deauth) { + *pos = __constant_cpu_to_le16( + WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); + pos++; + } else { + /* FIX: CF-Pollable and CF-PollReq should be set to match the + * values in beacons/probe responses */ + /* FIX: how about privacy and WEP? */ + /* capability */ + *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); + pos++; + + /* status_code */ + *pos = __cpu_to_le16(resp); + pos++; + + *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | + BIT(14) | BIT(15)); /* AID */ + pos++; + + /* Supported rates (Information element) */ + p = (char *) pos; + *p++ = WLAN_EID_SUPP_RATES; + lpos = p; + *p++ = 0; /* len */ + if (local->tx_rate_control & WLAN_RATE_1M) { + *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; + (*lpos)++; + } + if (local->tx_rate_control & WLAN_RATE_2M) { + *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; + (*lpos)++; + } + if (local->tx_rate_control & WLAN_RATE_5M5) { + *p++ = local->basic_rates & WLAN_RATE_5M5 ? + 0x8b : 0x0b; + (*lpos)++; + } + if (local->tx_rate_control & WLAN_RATE_11M) { + *p++ = local->basic_rates & WLAN_RATE_11M ? + 0x96 : 0x16; + (*lpos)++; + } + pos = (u16 *) p; + } + + prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, + (send_deauth ? WLAN_FC_STYPE_DEAUTH : + (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : + WLAN_FC_STYPE_ASSOC_RESP)), + body, (u8 *) pos - (u8 *) body, 1, + hdr->addr2, + send_deauth ? 0 : local->ap->tx_callback_assoc); + + if (sta) { + if (resp == WLAN_STATUS_SUCCESS) { + sta->last_rx = jiffies; + /* STA will be marked associated from TX callback, if + * AssocResp is ACKed */ + } + atomic_dec(&sta->users); + } + +#if 0 + PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR + ") => %d(%d) (%s)\n", + dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, + MAC2STR(prev_ap), resp, send_deauth, txt); +#endif +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_deauth(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct net_device *dev = local->dev; + struct hostap_ieee80211_hdr *hdr = + (struct hostap_ieee80211_hdr *) skb->data; + char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); + int len; + u16 reason_code, *pos; + struct sta_info *sta = NULL; + + len = skb->len - IEEE80211_MGMT_HDR_LEN; + + if (len < 2) { + printk("handle_deauth - too short payload (len=%d)\n", len); + return; + } + + pos = (u16 *) body; + reason_code = __le16_to_cpu(*pos); + + PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " + "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + reason_code); + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta != NULL) { + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) + hostap_event_expired_sta(local->dev, sta); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + hostap_ap_update_sq(sta, rx_stats); + } + spin_unlock_bh(&local->ap->sta_table_lock); + if (sta == NULL) { + printk("%s: deauthentication from " MACSTR ", " + "reason_code=%d, but STA not authenticated\n", dev->name, + MAC2STR(hdr->addr2), reason_code); + } +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_disassoc(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct net_device *dev = local->dev; + struct hostap_ieee80211_hdr *hdr = + (struct hostap_ieee80211_hdr *) skb->data; + char *body = skb->data + IEEE80211_MGMT_HDR_LEN; + int len; + u16 reason_code, *pos; + struct sta_info *sta = NULL; + + len = skb->len - IEEE80211_MGMT_HDR_LEN; + + if (len < 2) { + printk("handle_disassoc - too short payload (len=%d)\n", len); + return; + } + + pos = (u16 *) body; + reason_code = __le16_to_cpu(*pos); + + PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " + "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + reason_code); + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta != NULL) { + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) + hostap_event_expired_sta(local->dev, sta); + sta->flags &= ~WLAN_STA_ASSOC; + hostap_ap_update_sq(sta, rx_stats); + } + spin_unlock_bh(&local->ap->sta_table_lock); + if (sta == NULL) { + printk("%s: disassociation from " MACSTR ", " + "reason_code=%d, but STA not authenticated\n", + dev->name, MAC2STR(hdr->addr2), reason_code); + } +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void ap_handle_data_nullfunc(local_info_t *local, + struct hostap_ieee80211_hdr *hdr) +{ + struct net_device *dev = local->dev; + + /* some STA f/w's seem to require control::ACK frame for + * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does + * not send this.. + * send control::ACK for the data::nullfunc */ + + printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); + prism2_send_mgmt(dev, WLAN_FC_TYPE_CTRL, WLAN_FC_STYPE_ACK, + NULL, 0, 0, hdr->addr2, 0); +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void ap_handle_dropped_data(local_info_t *local, + struct hostap_ieee80211_hdr *hdr) +{ + struct net_device *dev = local->dev; + struct sta_info *sta; + u16 reason; + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&local->ap->sta_table_lock); + + if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { + PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); + atomic_dec(&sta->users); + return; + } + + reason = __constant_cpu_to_le16( + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, + ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? + WLAN_FC_STYPE_DEAUTH : WLAN_FC_STYPE_DISASSOC), + (char *) &reason, sizeof(reason), 1, + hdr->addr2, 0); + + if (sta) + atomic_dec(&sta->users); +} + +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +/* Called only as a scheduled task for pending AP frames. */ +static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, + struct sk_buff *skb) +{ + if (!(sta->flags & WLAN_STA_PS)) { + /* Station has moved to non-PS mode, so send all buffered + * frames using normal device queue. */ + dev_queue_xmit(skb); + return; + } + + /* add a flag for hostap_handle_sta_tx() to know that this skb should + * be passed through even though STA is using PS */ + memcpy(skb->cb, AP_SKB_CB_MAGIC, AP_SKB_CB_MAGIC_LEN); + skb->cb[AP_SKB_CB_MAGIC_LEN] = AP_SKB_CB_BUFFERED_FRAME; + if (!skb_queue_empty(&sta->tx_buf)) { + /* indicate to STA that more frames follow */ + skb->cb[AP_SKB_CB_MAGIC_LEN] |= AP_SKB_CB_ADD_MOREDATA; + } + if (skb->dev->hard_start_xmit(skb, skb->dev)) { + PDEBUG(DEBUG_AP, "%s: TX failed for buffered frame (PS Poll)" + "\n", skb->dev->name); + dev_kfree_skb(skb); + } +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_pspoll(local_info_t *local, + struct hostap_ieee80211_hdr *hdr, + struct hostap_80211_rx_status *rx_stats) +{ + struct net_device *dev = local->dev; + struct sta_info *sta; + u16 aid; + struct sk_buff *skb; + + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR + " PWRMGT=%d\n", + MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), + !!(le16_to_cpu(hdr->frame_control) & WLAN_FC_PWRMGT)); + + if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { + PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR + " not own MAC\n", MAC2STR(hdr->addr1)); + return; + } + + aid = __le16_to_cpu(hdr->duration_id); + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { + PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); + return; + } + aid &= ~BIT(15) & ~BIT(14); + if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { + PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); + return; + } + PDEBUG(DEBUG_PS2, " aid=%d\n", aid); + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&local->ap->sta_table_lock); + + if (sta == NULL) { + PDEBUG(DEBUG_PS, " STA not found\n"); + return; + } + hostap_ap_update_sq(sta, rx_stats); + if (sta->aid != aid) { + PDEBUG(DEBUG_PS, " received aid=%i does not match with " + "assoc.aid=%d\n", aid, sta->aid); + return; + } + + /* FIX: todo: + * - add timeout for buffering (clear aid in TIM vector if buffer timed + * out (expiry time must be longer than ListenInterval for + * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" + * - what to do, if buffered, pspolled, and sent frame is not ACKed by + * sta; store buffer for later use and leave TIM aid bit set? use + * TX event to check whether frame was ACKed? + */ + + while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { + /* send buffered frame .. */ + PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" + " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); + + pspoll_send_buffered(local, sta, skb); + + if (sta->flags & WLAN_STA_PS) { + /* send only one buffered packet per PS Poll */ + /* FIX: should ignore further PS Polls until the + * buffered packet that was just sent is acknowledged + * (Tx or TxExc event) */ + break; + } + } + + if (skb_queue_empty(&sta->tx_buf)) { + /* try to clear aid from TIM */ + if (!(sta->flags & WLAN_STA_TIM)) + PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", + aid); + hostap_set_tim(local, aid, 0); + sta->flags &= ~WLAN_STA_TIM; + } + + atomic_dec(&sta->users); +} + + +void hostap_ap_update_sq(struct sta_info *sta, + struct hostap_80211_rx_status *rx_stats) +{ + sta->last_rx_silence = rx_stats->noise; + sta->last_rx_signal = rx_stats->signal; + sta->last_rx_rate = rx_stats->rate; + sta->last_rx_updated = 7; + if (rx_stats->rate == 10) + sta->rx_count[0]++; + else if (rx_stats->rate == 20) + sta->rx_count[1]++; + else if (rx_stats->rate == 55) + sta->rx_count[2]++; + else if (rx_stats->rate == 110) + sta->rx_count[3]++; +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + +static void handle_wds_oper_queue(void *data) +{ + local_info_t *local = data; + struct wds_oper_data *entry, *prev; + + spin_lock_bh(&local->lock); + entry = local->ap->wds_oper_entries; + local->ap->wds_oper_entries = NULL; + spin_unlock_bh(&local->lock); + + while (entry) { + PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " + "to AP " MACSTR "\n", + local->dev->name, + entry->type == WDS_ADD ? "adding" : "removing", + MAC2STR(entry->addr)); + if (entry->type == WDS_ADD) + prism2_wds_add(local, entry->addr, 0); + else if (entry->type == WDS_DEL) + prism2_wds_del(local, entry->addr, 0, 1); + + prev = entry; + entry = entry->next; + kfree(prev); + } + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +/* Called only as a scheduled task for pending AP frames. */ +static void handle_beacon(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct hostap_ieee80211_hdr *hdr = + (struct hostap_ieee80211_hdr *) skb->data; + char *body = skb->data + IEEE80211_MGMT_HDR_LEN; + int len, left; + u16 *pos, beacon_int, capability; + char *ssid = NULL; + unsigned char *supp_rates = NULL; + int ssid_len = 0, supp_rates_len = 0; + struct sta_info *sta = NULL; + int new_sta = 0, channel = -1; + + len = skb->len - IEEE80211_MGMT_HDR_LEN; + + if (len < 8 + 2 + 2) { + printk(KERN_DEBUG "handle_beacon - too short payload " + "(len=%d)\n", len); + return; + } + + pos = (u16 *) body; + left = len; + + /* Timestamp (8 octets) */ + pos += 4; left -= 8; + /* Beacon interval (2 octets) */ + beacon_int = __le16_to_cpu(*pos); + pos++; left -= 2; + /* Capability information (2 octets) */ + capability = __le16_to_cpu(*pos); + pos++; left -= 2; + + if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && + capability & WLAN_CAPABILITY_IBSS) + return; + + if (left >= 2) { + unsigned int ileft; + unsigned char *u = (unsigned char *) pos; + + if (*u == WLAN_EID_SSID) { + u++; left--; + ileft = *u; + u++; left--; + + if (ileft > left || ileft > MAX_SSID_LEN) { + PDEBUG(DEBUG_AP, "SSID: overflow\n"); + return; + } + + if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && + (ileft != strlen(local->essid) || + memcmp(local->essid, u, ileft) != 0)) { + /* not our SSID */ + return; + } + + ssid = u; + ssid_len = ileft; + + u += ileft; + left -= ileft; + } + + if (*u == WLAN_EID_SUPP_RATES) { + u++; left--; + ileft = *u; + u++; left--; + + if (ileft > left || ileft == 0 || ileft > 8) { + PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); + return; + } + + supp_rates = u; + supp_rates_len = ileft; + + u += ileft; + left -= ileft; + } + + if (*u == WLAN_EID_DS_PARAMS) { + u++; left--; + ileft = *u; + u++; left--; + + if (ileft > left || ileft != 1) { + PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); + return; + } + + channel = *u; + + u += ileft; + left -= ileft; + } + } + + spin_lock_bh(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta != NULL) + atomic_inc(&sta->users); + spin_unlock_bh(&local->ap->sta_table_lock); + + if (sta == NULL) { + /* add new AP */ + new_sta = 1; + sta = ap_add_sta(local->ap, hdr->addr2); + if (sta == NULL) { + printk(KERN_INFO "prism2: kmalloc failed for AP " + "data structure\n"); + return; + } + hostap_event_new_sta(local->dev, sta); + + /* mark APs authentication and associated for pseudo ad-hoc + * style communication */ + sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; + + if (local->ap->autom_ap_wds) { + hostap_wds_link_oper(local, sta->addr, WDS_ADD); + } + } + + sta->ap = 1; + if (ssid) { + sta->u.ap.ssid_len = ssid_len; + memcpy(sta->u.ap.ssid, ssid, ssid_len); + sta->u.ap.ssid[ssid_len] = '\0'; + } else { + sta->u.ap.ssid_len = 0; + sta->u.ap.ssid[0] = '\0'; + } + sta->u.ap.channel = channel; + sta->rx_packets++; + sta->rx_bytes += len; + sta->u.ap.last_beacon = sta->last_rx = jiffies; + sta->capability = capability; + sta->listen_interval = beacon_int; + hostap_ap_update_sq(sta, rx_stats); + + atomic_dec(&sta->users); + + if (new_sta) { + memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); + memcpy(sta->supported_rates, supp_rates, supp_rates_len); + prism2_check_tx_rates(sta); + } +} + +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +/* Called only as a tasklet. */ +static void handle_ap_item(local_info_t *local, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + struct net_device *dev = local->dev; +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + u16 fc, type, stype; + struct hostap_ieee80211_hdr *hdr; + + /* FIX: should give skb->len to handler functions and check that the + * buffer is long enough */ + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (!local->hostapd && type == WLAN_FC_TYPE_DATA) { + PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); + + if (!(fc & WLAN_FC_TODS) || (fc & WLAN_FC_FROMDS)) { + if (stype == WLAN_FC_STYPE_NULLFUNC) { + /* no ToDS nullfunc seems to be used to check + * AP association; so send reject message to + * speed up re-association */ + ap_handle_dropped_data(local, hdr); + goto done; + } + PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", + fc); + goto done; + } + + if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" + MACSTR " not own MAC\n", + MAC2STR(hdr->addr1)); + goto done; + } + + if (local->ap->nullfunc_ack && stype == WLAN_FC_STYPE_NULLFUNC) + ap_handle_data_nullfunc(local, hdr); + else + ap_handle_dropped_data(local, hdr); + goto done; + } + + if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_BEACON) { + handle_beacon(local, skb, rx_stats); + goto done; + } +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + if (type == WLAN_FC_TYPE_CTRL && stype == WLAN_FC_STYPE_PSPOLL) { + handle_pspoll(local, hdr, rx_stats); + goto done; + } + + if (local->hostapd) { + PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " + "subtype=0x%02x\n", type, stype); + goto done; + } + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (type != WLAN_FC_TYPE_MGMT) { + PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); + goto done; + } + + if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR + " not own MAC\n", MAC2STR(hdr->addr1)); + goto done; + } + + if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR + " not own MAC\n", MAC2STR(hdr->addr3)); + goto done; + } + + switch (stype) { + case WLAN_FC_STYPE_ASSOC_REQ: + handle_assoc(local, skb, rx_stats, 0); + break; + case WLAN_FC_STYPE_ASSOC_RESP: + PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); + break; + case WLAN_FC_STYPE_REASSOC_REQ: + handle_assoc(local, skb, rx_stats, 1); + break; + case WLAN_FC_STYPE_REASSOC_RESP: + PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); + break; + case WLAN_FC_STYPE_ATIM: + PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); + break; + case WLAN_FC_STYPE_DISASSOC: + handle_disassoc(local, skb, rx_stats); + break; + case WLAN_FC_STYPE_AUTH: + handle_authen(local, skb, rx_stats); + break; + case WLAN_FC_STYPE_DEAUTH: + handle_deauth(local, skb, rx_stats); + break; + default: + PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", stype); + break; + } +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + done: + dev_kfree_skb(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +void hostap_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 fc; + struct hostap_ieee80211_hdr *hdr; + + if (skb->len < 16) + goto drop; + + local->stats.rx_packets++; + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) + goto drop; + + skb->protocol = __constant_htons(ETH_P_HOSTAP); + handle_ap_item(local, skb, rx_stats); + return; + + drop: + dev_kfree_skb(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +static void schedule_packet_send(local_info_t *local, struct sta_info *sta) +{ + struct sk_buff *skb; + struct hostap_ieee80211_hdr *hdr; + struct hostap_80211_rx_status rx_stats; + + if (skb_queue_empty(&sta->tx_buf)) + return; + + skb = dev_alloc_skb(16); + if (skb == NULL) { + printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " + "failed\n", local->dev->name); + return; + } + + hdr = (struct hostap_ieee80211_hdr *) skb_put(skb, 16); + + /* Generate a fake pspoll frame to start packet delivery */ + hdr->frame_control = __constant_cpu_to_le16( + (WLAN_FC_TYPE_CTRL << 2) | (WLAN_FC_STYPE_PSPOLL << 4)); + memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); + memcpy(hdr->addr2, sta->addr, ETH_ALEN); + hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); + + PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " + "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); + + skb->dev = local->dev; + + memset(&rx_stats, 0, sizeof(rx_stats)); + hostap_rx(local->dev, skb, &rx_stats); +} + + +#ifdef WIRELESS_EXT +static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], + struct iw_quality qual[], int buf_size, + int aplist) +{ + struct ap_data *ap = local->ap; + struct list_head *ptr; + int count = 0; + + spin_lock_bh(&ap->sta_table_lock); + + for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; + ptr = ptr->next) { + struct sta_info *sta = (struct sta_info *) ptr; + + if (aplist && !sta->ap) + continue; + 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; + 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].updated = sta->last_rx_updated; + + sta->last_rx_updated = 0; + + count++; + if (count >= buf_size) + break; + } + spin_unlock_bh(&ap->sta_table_lock); + + return count; +} + + +#if WIRELESS_EXT > 13 +/* Translate our list of Access Points & Stations to a card independant + * format that the Wireless Tools will understand - Jean II */ +static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct ap_data *ap = local->ap; + struct list_head *ptr; + struct iw_event iwe; + char *current_ev = buffer; + char *end_buf = buffer + IW_SCAN_MAX_DATA; +#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) && (WIRELESS_EXT > 14) + char buf[64]; +#endif + + spin_lock_bh(&ap->sta_table_lock); + + for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; + ptr = ptr->next) { + struct sta_info *sta = (struct sta_info *) ptr; + + /* First entry *MUST* be the AP MAC address */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); + iwe.len = IW_EV_ADDR_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); + + /* Use the mode to indicate if it's a station or + * an Access Point */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (sta->ap) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_INFRA; + iwe.len = IW_EV_UINT_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + + /* Some quality */ + 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; + 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.updated = sta->last_rx_updated; + iwe.len = IW_EV_QUAL_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_QUAL_LEN); + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (sta->ap) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = sta->u.ap.ssid_len; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, + sta->u.ap.ssid); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (sta->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = + IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, + sta->u.ap.ssid + /* 0 byte memcpy */); + + if (sta->u.ap.channel > 0 && + sta->u.ap.channel <= FREQ_COUNT) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] + * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event( + current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + } + +#if WIRELESS_EXT > 14 + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "beacon_interval=%d", + sta->listen_interval); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); +#endif /* WIRELESS_EXT > 14 */ + } +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + sta->last_rx_updated = 0; + + /* To be continued, we should make good use of IWEVCUSTOM */ + } + + spin_unlock_bh(&ap->sta_table_lock); + + return current_ev - buffer; +} +#endif /* WIRELESS_EXT > 13 */ +#endif /* WIRELESS_EXT */ + + +static int prism2_hostapd_add_sta(struct ap_data *ap, + struct prism2_hostapd_param *param) +{ + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, param->sta_addr); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&ap->sta_table_lock); + + if (sta == NULL) { + sta = ap_add_sta(ap, param->sta_addr); + if (sta == NULL) + return -1; + } + + if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) + hostap_event_new_sta(sta->local->dev, sta); + + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + sta->last_rx = jiffies; + sta->aid = param->u.add_sta.aid; + sta->capability = param->u.add_sta.capability; + sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; + if (sta->tx_supp_rates & WLAN_RATE_1M) + sta->supported_rates[0] = 2; + if (sta->tx_supp_rates & WLAN_RATE_2M) + sta->supported_rates[1] = 4; + if (sta->tx_supp_rates & WLAN_RATE_5M5) + sta->supported_rates[2] = 11; + if (sta->tx_supp_rates & WLAN_RATE_11M) + sta->supported_rates[3] = 22; + prism2_check_tx_rates(sta); + atomic_dec(&sta->users); + return 0; +} + + +static int prism2_hostapd_remove_sta(struct ap_data *ap, + struct prism2_hostapd_param *param) +{ + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, param->sta_addr); + if (sta) { + ap_sta_hash_del(ap, sta); + list_del(&sta->list); + } + spin_unlock_bh(&ap->sta_table_lock); + + if (!sta) + return -ENOENT; + + if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) + hostap_event_expired_sta(sta->local->dev, sta); + ap_free_sta(ap, sta); + + return 0; +} + + +static int prism2_hostapd_get_info_sta(struct ap_data *ap, + struct prism2_hostapd_param *param) +{ + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, param->sta_addr); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&ap->sta_table_lock); + + if (!sta) + return -ENOENT; + + param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; + + atomic_dec(&sta->users); + + return 1; +} + + +static int prism2_hostapd_set_flags_sta(struct ap_data *ap, + struct prism2_hostapd_param *param) +{ + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, param->sta_addr); + if (sta) { + sta->flags |= param->u.set_flags_sta.flags_or; + sta->flags &= param->u.set_flags_sta.flags_and; + } + spin_unlock_bh(&ap->sta_table_lock); + + if (!sta) + return -ENOENT; + + return 0; +} + + +static int prism2_hostapd(struct ap_data *ap, + struct prism2_hostapd_param *param) +{ + switch (param->cmd) { + case PRISM2_HOSTAPD_FLUSH: + ap_control_kickall(ap); + return 0; + case PRISM2_HOSTAPD_ADD_STA: + return prism2_hostapd_add_sta(ap, param); + case PRISM2_HOSTAPD_REMOVE_STA: + return prism2_hostapd_remove_sta(ap, param); + case PRISM2_HOSTAPD_GET_INFO_STA: + return prism2_hostapd_get_info_sta(ap, param); + case PRISM2_HOSTAPD_SET_FLAGS_STA: + return prism2_hostapd_set_flags_sta(ap, param); + default: + printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", + param->cmd); + return -EOPNOTSUPP; + } +} + + +/* Update station info for host-based TX rate control and return current + * TX rate */ +static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) +{ + int ret = sta->tx_rate; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + sta->tx_count[sta->tx_rate_idx]++; + sta->tx_since_last_failure++; + sta->tx_consecutive_exc = 0; + if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && + sta->tx_rate_idx < sta->tx_max_rate) { + /* use next higher rate */ + int old_rate, new_rate; + old_rate = new_rate = sta->tx_rate_idx; + while (new_rate < sta->tx_max_rate) { + new_rate++; + if (ap_tx_rate_ok(new_rate, sta, local)) { + sta->tx_rate_idx = new_rate; + break; + } + } + if (old_rate != sta->tx_rate_idx) { + switch (sta->tx_rate_idx) { + case 0: sta->tx_rate = 10; break; + case 1: sta->tx_rate = 20; break; + case 2: sta->tx_rate = 55; break; + case 3: sta->tx_rate = 110; break; + default: sta->tx_rate = 0; break; + } + PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" + " %d\n", dev->name, MAC2STR(sta->addr), + sta->tx_rate); + } + sta->tx_since_last_failure = 0; + } + + return ret; +} + + +/* Called only from software IRQ. Called for each TX frame prior possible + * encryption and transmit. */ +ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct sk_buff *skb, + struct hfa384x_tx_frame *txdesc, int wds, + int host_encrypt, + struct prism2_crypt_data **crypt, + void **sta_ptr) +{ + struct sta_info *sta = NULL; + int set_tim, ret; + + ret = AP_TX_CONTINUE; + if (local->ap == NULL) + goto out; + + if (txdesc->addr1[0] & 0x01) { + /* broadcast/multicast frame - no AP related processing */ + goto out; + } + + /* unicast packet - check whether destination STA is associated */ + spin_lock(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, txdesc->addr1); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&local->ap->sta_table_lock); + + if (local->iw_mode == IW_MODE_MASTER && sta == NULL && !wds) { + printk(KERN_DEBUG "AP: drop packet to non-associated STA " + MACSTR "\n", MAC2STR(txdesc->addr1)); + ret = AP_TX_DROP; + goto out; + } + + if (sta == NULL) + goto out; + + if (!(sta->flags & WLAN_STA_AUTHORIZED)) + ret = AP_TX_CONTINUE_NOT_AUTHORIZED; + + /* Set tx_rate if using host-based TX rate control */ + if (!local->fw_tx_rate_control) + local->ap->last_tx_rate = txdesc->tx_rate = + ap_update_sta_tx_rate(sta, local->dev); + + if (local->iw_mode != IW_MODE_MASTER) + goto out; + + if (!(sta->flags & WLAN_STA_PS)) + goto out; + + if (memcmp(skb->cb, AP_SKB_CB_MAGIC, AP_SKB_CB_MAGIC_LEN) == 0) { + if (skb->cb[AP_SKB_CB_MAGIC_LEN] & AP_SKB_CB_ADD_MOREDATA) { + /* indicate to STA that more frames follow */ + txdesc->frame_control |= + __constant_cpu_to_le16(WLAN_FC_MOREDATA); + } + + if (skb->cb[AP_SKB_CB_MAGIC_LEN] & AP_SKB_CB_BUFFERED_FRAME) { + /* packet was already buffered and now send due to + * PS poll, so do not rebuffer it */ + goto out; + } + } + + if (skb->len == 0 && skb->protocol == __constant_htons(ETH_P_HOSTAP) && + skb_headroom(skb) >= sizeof(*txdesc)) { + /* Copy original TX desc back to the skb so that prism2_tx() + * is able to send it when STA wakes up. */ + memcpy(skb_push(skb, sizeof(*txdesc)), + txdesc, sizeof(*txdesc)); + } + if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { + PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS " + "mode buffer\n", local->dev->name, MAC2STR(sta->addr)); + /* Make sure that TIM is set for the station (it might not be + * after AP wlan hw reset). */ + hostap_set_tim(local, sta->aid, 1); + sta->flags |= WLAN_STA_TIM; + ret = AP_TX_DROP; + goto out; + } + + /* STA in PS mode, buffer frame for later delivery */ + set_tim = skb_queue_empty(&sta->tx_buf); + skb_queue_tail(&sta->tx_buf, skb); + /* FIX: could save RX time to skb and expire buffered frames after + * some time if STA does not poll for them */ + + if (set_tim) { + if (sta->flags & WLAN_STA_TIM) + PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", + sta->aid); + hostap_set_tim(local, sta->aid, 1); + sta->flags |= WLAN_STA_TIM; + } + + ret = AP_TX_BUFFERED; + + out: + if (sta != NULL) { + if (ret == AP_TX_CONTINUE || + ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { + sta->tx_packets++; + sta->tx_bytes += le16_to_cpu(txdesc->data_len) + 36; + sta->last_tx = jiffies; + } + + if ((ret == AP_TX_CONTINUE || + ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && + sta->crypt && host_encrypt) { + *crypt = sta->crypt; + *sta_ptr = sta; /* hostap_handle_sta_release() will be + * called to release sta info later */ + } else + atomic_dec(&sta->users); + } + + return ret; +} + + +void hostap_handle_sta_release(void *ptr) +{ + struct sta_info *sta = ptr; + atomic_dec(&sta->users); +} + + +/* Called only as a tasklet (software IRQ) */ +void hostap_handle_sta_tx_exc(local_info_t *local, + struct hfa384x_tx_frame *txdesc) +{ + struct sta_info *sta; + + spin_lock(&local->ap->sta_table_lock); + /* FIX: is addr1 correct for all frame types? */ + sta = ap_get_sta(local->ap, txdesc->addr1); + if (!sta) { + spin_unlock(&local->ap->sta_table_lock); + PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this " + "TX error (@%lu)\n", + local->dev->name, MAC2STR(txdesc->addr1), jiffies); + return; + } + + sta->tx_since_last_failure = 0; + sta->tx_consecutive_exc++; + + if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && + sta->tx_rate_idx > 0 && txdesc->tx_rate <= sta->tx_rate) { + /* use next lower rate */ + int old, rate; + old = rate = sta->tx_rate_idx; + while (rate > 0) { + rate--; + if (ap_tx_rate_ok(rate, sta, local)) { + sta->tx_rate_idx = rate; + break; + } + } + if (old != sta->tx_rate_idx) { + switch (sta->tx_rate_idx) { + case 0: sta->tx_rate = 10; break; + case 1: sta->tx_rate = 20; break; + case 2: sta->tx_rate = 55; break; + case 3: sta->tx_rate = 110; break; + default: sta->tx_rate = 0; break; + } + PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered " + "to %d\n", local->dev->name, MAC2STR(sta->addr), + sta->tx_rate); + } + sta->tx_consecutive_exc = 0; + } + spin_unlock(&local->ap->sta_table_lock); +} + + +static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, + int pwrmgt, int type, int stype) +{ + if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { + sta->flags |= WLAN_STA_PS; + PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS " + "mode (type=0x%02X, stype=0x%02X)\n", + MAC2STR(sta->addr), type, stype); + } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { + sta->flags &= ~WLAN_STA_PS; + PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use " + "PS mode (type=0x%02X, stype=0x%02X)\n", + MAC2STR(sta->addr), type, stype); + if (type != WLAN_FC_TYPE_CTRL || stype != WLAN_FC_STYPE_PSPOLL) + schedule_packet_send(local, sta); + } +} + + +/* Called only as a tasklet (software IRQ). Called for each RX frame to update + * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ +int hostap_update_sta_ps(local_info_t *local, struct hostap_ieee80211_hdr *hdr) +{ + struct sta_info *sta; + u16 fc; + + spin_lock(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&local->ap->sta_table_lock); + + if (!sta) + return -1; + + fc = le16_to_cpu(hdr->frame_control); + hostap_update_sta_ps2(local, sta, fc & WLAN_FC_PWRMGT, + WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc)); + + atomic_dec(&sta->users); + return 0; +} + + +/* Called only as a tasklet (software IRQ). Called for each RX frame after + * getting RX header and payload from hardware. */ +ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, + struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, + int wds) +{ + int ret; + struct sta_info *sta; + u16 fc, type, stype; + struct hostap_ieee80211_hdr *hdr; + + if (local->ap == NULL) + return AP_RX_CONTINUE; + + hdr = (struct hostap_ieee80211_hdr *) skb->data; + + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + spin_lock(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&local->ap->sta_table_lock); + + if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) + ret = AP_RX_CONTINUE_NOT_AUTHORIZED; + else + ret = AP_RX_CONTINUE; + + + if (fc & WLAN_FC_TODS) { + if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { + if (local->hostapd) { + prism2_rx_80211(local->apdev, skb, rx_stats, + PRISM2_RX_NON_ASSOC); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + printk(KERN_DEBUG "%s: dropped received packet" + " from non-associated STA " MACSTR + " (type=0x%02x, subtype=0x%02x)\n", + dev->name, MAC2STR(hdr->addr2), type, + stype); + hostap_rx(dev, skb, rx_stats); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } + ret = AP_RX_EXIT; + goto out; + } + } else if (fc & WLAN_FC_FROMDS) { + if (!wds) { + /* FromDS frame - not for us; probably + * broadcast/multicast in another BSS - drop */ + if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + printk(KERN_DEBUG "Odd.. FromDS packet " + "received with own BSSID\n"); + hostap_dump_rx_80211(dev->name, skb, rx_stats); + } + ret = AP_RX_DROP; + goto out; + } + } else if (stype == WLAN_FC_STYPE_NULLFUNC && sta == NULL && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + + if (local->hostapd) { + prism2_rx_80211(local->apdev, skb, rx_stats, + PRISM2_RX_NON_ASSOC); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + /* At least Lucent f/w seems to send data::nullfunc + * frames with no ToDS flag when the current AP returns + * after being unavailable for some time. Speed up + * re-association by informing the station about it not + * being associated. */ + printk(KERN_DEBUG "%s: rejected received nullfunc " + "frame without ToDS from not associated STA " + MACSTR "\n", + dev->name, MAC2STR(hdr->addr2)); + hostap_rx(dev, skb, rx_stats); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } + ret = AP_RX_EXIT; + goto out; + } else if (stype == WLAN_FC_STYPE_NULLFUNC) { + /* At least Lucent cards seem to send periodic nullfunc + * frames with ToDS. Let these through to update SQ + * stats and PS state. Nullfunc frames do not contain + * any data and they will be dropped below. */ + } else { + /* If BSSID (Addr3) is foreign, this frame is a normal + * broadcast frame from an IBSS network. Drop it silently. + * If BSSID is own, report the dropping of this frame. */ + if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + printk(KERN_DEBUG "%s: dropped received packet from " + MACSTR " with no ToDS flag (type=0x%02x, " + "subtype=0x%02x)\n", dev->name, + MAC2STR(hdr->addr2), type, stype); + hostap_dump_rx_80211(dev->name, skb, rx_stats); + } + ret = AP_RX_DROP; + goto out; + } + + if (sta) { + hostap_ap_update_sq(sta, rx_stats); + + hostap_update_sta_ps2(local, sta, fc & WLAN_FC_PWRMGT, + type, stype); + + sta->rx_packets++; + sta->rx_bytes += skb->len; + sta->last_rx = jiffies; + } + + if (local->ap->nullfunc_ack && stype == WLAN_FC_STYPE_NULLFUNC && + fc & WLAN_FC_TODS) { + if (local->hostapd) { + prism2_rx_80211(local->apdev, skb, rx_stats, + PRISM2_RX_NULLFUNC_ACK); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + /* some STA f/w's seem to require control::ACK frame + * for data::nullfunc, but Prism2 f/w 0.8.0 (at least + * from Compaq) does not send this.. Try to generate + * ACK for these frames from the host driver to make + * power saving work with, e.g., Lucent WaveLAN f/w */ + hostap_rx(dev, skb, rx_stats); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } + ret = AP_RX_EXIT; + goto out; + } + + out: + if (sta) + atomic_dec(&sta->users); + + return ret; +} + + +/* Called only as a tasklet (software IRQ) */ +int hostap_handle_sta_crypto(local_info_t *local, + struct hostap_ieee80211_hdr *hdr, + struct prism2_crypt_data **crypt, void **sta_ptr) +{ + struct sta_info *sta; + + spin_lock(&local->ap->sta_table_lock); + sta = ap_get_sta(local->ap, hdr->addr2); + if (sta) + atomic_inc(&sta->users); + spin_unlock(&local->ap->sta_table_lock); + + if (!sta) + return -1; + + if (sta->crypt) { + *crypt = sta->crypt; + *sta_ptr = sta; + /* hostap_handle_sta_release() will be called to release STA + * info */ + } else + atomic_dec(&sta->users); + + return 0; +} + + +/* Called only as a tasklet (software IRQ) */ +int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) +{ + struct sta_info *sta; + int ret = 0; + + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, sta_addr); + if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) + ret = 1; + spin_unlock(&ap->sta_table_lock); + + return ret; +} + + +/* Called only as a tasklet (software IRQ) */ +int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) +{ + struct sta_info *sta; + int ret = 1; + + if (!ap) + return -1; + + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, sta_addr); + if (sta) + ret = 0; + spin_unlock(&ap->sta_table_lock); + + if (ret == 1) { + sta = ap_add_sta(ap, sta_addr); + if (!sta) + ret = -1; + sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; + sta->ap = 1; + memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); + /* No way of knowing which rates are supported since we did not + * get supported rates element from beacon/assoc req. Assume + * that remote end supports all 802.11b rates. */ + sta->supported_rates[0] = 0x82; + sta->supported_rates[1] = 0x84; + sta->supported_rates[2] = 0x0b; + sta->supported_rates[3] = 0x16; + sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | + WLAN_RATE_5M5 | WLAN_RATE_11M; + sta->tx_rate = 110; + sta->tx_max_rate = sta->tx_rate_idx = 3; + } + + return ret; +} + + +/* Called only as a tasklet (software IRQ) */ +int hostap_update_rx_stats(struct ap_data *ap, + struct hostap_ieee80211_hdr *hdr, + struct hostap_80211_rx_status *rx_stats) +{ + struct sta_info *sta; + + if (!ap) + return -1; + + spin_lock(&ap->sta_table_lock); + sta = ap_get_sta(ap, hdr->addr2); + if (sta) + hostap_ap_update_sq(sta, rx_stats); + spin_unlock(&ap->sta_table_lock); + + return sta ? 0 : -1; +} + + +void hostap_update_rates(local_info_t *local) +{ + struct list_head *ptr; + struct ap_data *ap = local->ap; + + if (!ap) + return; + + spin_lock_bh(&ap->sta_table_lock); + for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { + struct sta_info *sta = (struct sta_info *) ptr; + prism2_check_tx_rates(sta); + } + spin_unlock_bh(&ap->sta_table_lock); +} + + +static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, + struct prism2_crypt_data ***crypt) +{ + struct sta_info *sta; + + spin_lock_bh(&ap->sta_table_lock); + sta = ap_get_sta(ap, addr); + if (sta) + atomic_inc(&sta->users); + spin_unlock_bh(&ap->sta_table_lock); + + if (!sta && permanent) + sta = ap_add_sta(ap, addr); + + if (!sta) + return NULL; + + if (permanent) + sta->flags |= WLAN_STA_PERM; + + *crypt = &sta->crypt; + + return sta; +} + + +void hostap_add_wds_links(local_info_t *local) +{ + struct ap_data *ap = local->ap; + struct list_head *ptr; + + spin_lock_bh(&ap->sta_table_lock); + list_for_each(ptr, &ap->sta_list) { + struct sta_info *sta = list_entry(ptr, struct sta_info, list); + if (sta->ap) + hostap_wds_link_oper(local, sta->addr, WDS_ADD); + } + spin_unlock_bh(&ap->sta_table_lock); + + PRISM2_SCHEDULE_TASK(&local->ap->wds_oper_queue); +} + + +void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) +{ + struct wds_oper_data *entry; + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return; + memcpy(entry->addr, addr, ETH_ALEN); + entry->type = type; + spin_lock_bh(&local->lock); + entry->next = local->ap->wds_oper_entries; + local->ap->wds_oper_entries = entry; + spin_unlock_bh(&local->lock); + + PRISM2_SCHEDULE_TASK(&local->ap->wds_oper_queue); +} + + +EXPORT_SYMBOL(hostap_init_data); +EXPORT_SYMBOL(hostap_free_data); +EXPORT_SYMBOL(hostap_check_sta_fw_version); +EXPORT_SYMBOL(hostap_handle_sta_tx); +EXPORT_SYMBOL(hostap_handle_sta_release); +EXPORT_SYMBOL(hostap_handle_sta_tx_exc); +EXPORT_SYMBOL(hostap_update_sta_ps); +EXPORT_SYMBOL(hostap_handle_sta_rx); +EXPORT_SYMBOL(hostap_is_sta_assoc); +EXPORT_SYMBOL(hostap_add_sta); +EXPORT_SYMBOL(hostap_update_rates); +EXPORT_SYMBOL(hostap_add_wds_links); +EXPORT_SYMBOL(hostap_wds_link_oper); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +EXPORT_SYMBOL(hostap_deauth_all_stas); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff -Nru a/drivers/net/wireless/hostap_ap.h b/drivers/net/wireless/hostap_ap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_ap.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,272 @@ +#ifndef HOSTAP_AP_H +#define HOSTAP_AP_H + +/* AP data structures for STAs */ + +/* maximum number of frames to buffer per STA */ +#define STA_MAX_TX_BUFFER 32 + +/* Flags used in skb->cb[6] to control how the packet is handled in TX path. + * skb->cb[0..5] must contain magic value 'hostap' to indicate that cb[6] is + * used. */ +#define AP_SKB_CB_MAGIC "hostap" +#define AP_SKB_CB_MAGIC_LEN 6 +#define AP_SKB_CB_BUFFERED_FRAME BIT(0) +#define AP_SKB_CB_ADD_MOREDATA BIT(1) + + +/* STA flags */ +#define WLAN_STA_AUTH BIT(0) +#define WLAN_STA_ASSOC BIT(1) +#define WLAN_STA_PS BIT(2) +#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ +#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ +#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is + * controlling whether STA is authorized to + * send and receive non-IEEE 802.1X frames + */ +#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ + +#define WLAN_RATE_1M BIT(0) +#define WLAN_RATE_2M BIT(1) +#define WLAN_RATE_5M5 BIT(2) +#define WLAN_RATE_11M BIT(3) +#define WLAN_RATE_COUNT 4 + +/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, + * but some pre-standard IEEE 802.11g products use longer elements. */ +#define WLAN_SUPP_RATES_MAX 32 + +/* Try to increase TX rate after # successfully sent consecutive packets */ +#define WLAN_RATE_UPDATE_COUNT 50 + +/* Decrease TX rate after # consecutive dropped packets */ +#define WLAN_RATE_DECREASE_THRESHOLD 2 + +struct sta_info { + struct list_head list; + struct sta_info *hnext; /* next entry in hash table list */ + atomic_t users; /* number of users (do not remove if > 0) */ + struct proc_dir_entry *proc; + + u8 addr[6]; + u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ + u32 flags; + u16 capability; + u16 listen_interval; /* or beacon_int for APs */ + u8 supported_rates[WLAN_SUPP_RATES_MAX]; + + unsigned long last_auth; + unsigned long last_assoc; + unsigned long last_rx; + unsigned long last_tx; + unsigned long rx_packets, tx_packets; + unsigned long rx_bytes, tx_bytes; + struct sk_buff_head tx_buf; + /* FIX: timeout buffers with an expiry time somehow derived from + * listen_interval */ + + u8 last_rx_silence; + u8 last_rx_signal; + u8 last_rx_rate; + u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ + + u8 tx_supp_rates; /* bit field of supported TX rates */ + u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ + u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ + u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ + u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ + u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) + */ + u32 tx_since_last_failure; + u32 tx_consecutive_exc; + + struct prism2_crypt_data *crypt; + + int ap; /* whether this station is an AP */ + + local_info_t *local; + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + union { + struct { + char *challenge; /* shared key authentication + * challenge */ + } sta; + struct { + int ssid_len; + unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ + int channel; + unsigned long last_beacon; /* last RX beacon time */ + } ap; + } u; + + struct timer_list timer; + enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ +}; + + +#define MAX_STA_COUNT 1024 + +/* Maximum number of AIDs to use for STAs; must be 2007 or lower + * (8802.11 limitation) */ +#define MAX_AID_TABLE_SIZE 128 + +#define STA_HASH_SIZE 256 +#define STA_HASH(sta) (sta[5]) + + +/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC + * has passed since last received frame from the station, a nullfunc data + * frame is sent to the station. If this frame is not acknowledged and no other + * frames have been received, the station will be disassociated after + * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after + * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with + * max inactivity timer. */ +#define AP_MAX_INACTIVITY_SEC (5 * 60) +#define AP_DISASSOC_DELAY (HZ) +#define AP_DEAUTH_DELAY (HZ) + +/* ap_policy: whether to accept frames to/from other APs/IBSS */ +typedef enum { + AP_OTHER_AP_SKIP_ALL = 0, + AP_OTHER_AP_SAME_SSID = 1, + AP_OTHER_AP_ALL = 2, + AP_OTHER_AP_EVEN_IBSS = 3 +} ap_policy_enum; + +#define PRISM2_AUTH_OPEN BIT(0) +#define PRISM2_AUTH_SHARED_KEY BIT(1) + + +/* MAC address-based restrictions */ +struct mac_entry { + struct list_head list; + u8 addr[6]; +}; + +struct mac_restrictions { + enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; + unsigned int entries; + struct list_head mac_list; + spinlock_t lock; +}; + + +struct add_sta_proc_data { + u8 addr[ETH_ALEN]; + struct add_sta_proc_data *next; +}; + + +typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; +struct wds_oper_data { + wds_oper_type type; + u8 addr[ETH_ALEN]; + struct wds_oper_data *next; +}; + + +struct ap_data { + int initialized; /* whether ap_data has been initialized */ + local_info_t *local; + int bridge_packets; /* send packet to associated STAs directly to the + * wireless media instead of higher layers in the + * kernel */ + unsigned int bridged_unicast; /* number of unicast frames bridged on + * wireless media */ + unsigned int bridged_multicast; /* number of non-unicast frames + * bridged on wireless media */ + int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ + + spinlock_t sta_table_lock; + int num_sta; /* number of entries in sta_list */ + struct list_head sta_list; /* STA info list head */ + struct sta_info *sta_hash[STA_HASH_SIZE]; + + struct proc_dir_entry *proc; + + ap_policy_enum ap_policy; + unsigned int max_inactivity; + int autom_ap_wds; + + struct mac_restrictions mac_restrictions; /* MAC-based auth */ + int last_tx_rate; + + HOSTAP_QUEUE set_tim_queue; + struct list_head set_tim_list; + spinlock_t set_tim_lock; + + HOSTAP_QUEUE add_sta_proc_queue; + struct add_sta_proc_data *add_sta_proc_entries; + + HOSTAP_QUEUE wds_oper_queue; + struct wds_oper_data *wds_oper_entries; + + u16 tx_callback_idx; + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + /* pointers to STA info; based on allocated AID or NULL if AID free + * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 + * and so on + */ + struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; + + u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; + + /* WEP operations for generating challenges to be used with shared key + * authentication */ + struct hostap_crypto_ops *crypt; + void *crypt_priv; +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ +}; + + +void hostap_rx(struct net_device *dev, struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats); +void hostap_init_data(local_info_t *local); +void hostap_free_data(struct ap_data *ap); +void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); + +typedef enum { + AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, + AP_TX_CONTINUE_NOT_AUTHORIZED +} ap_tx_ret; +ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct sk_buff *skb, + struct hfa384x_tx_frame *txdesc, int wds, + int host_encrypt, + struct prism2_crypt_data **crypt, + void **sta_ptr); +void hostap_handle_sta_release(void *ptr); +void hostap_handle_sta_tx_exc(local_info_t *local, + struct hfa384x_tx_frame *txdesc); +int hostap_update_sta_ps(local_info_t *local, + struct hostap_ieee80211_hdr *hdr); +typedef enum { + AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED +} ap_rx_ret; +ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, + struct sk_buff *skb, + struct hostap_80211_rx_status *rx_stats, + int wds); +int hostap_handle_sta_crypto(local_info_t *local, + struct hostap_ieee80211_hdr *hdr, + struct prism2_crypt_data **crypt, void **sta_ptr); +int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); +int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); +int hostap_update_rx_stats(struct ap_data *ap, + struct hostap_ieee80211_hdr *hdr, + struct hostap_80211_rx_status *rx_stats); +void hostap_update_rates(local_info_t *local); +void hostap_add_wds_links(local_info_t *local); +void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); +void hostap_ap_update_sq(struct sta_info *sta, + struct hostap_80211_rx_status *rx_stats); + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, + int resend); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + +#endif /* HOSTAP_AP_H */ diff -Nru a/drivers/net/wireless/hostap_common.h b/drivers/net/wireless/hostap_common.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_common.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,524 @@ +#ifndef HOSTAP_COMMON_H +#define HOSTAP_COMMON_H + +#define BIT(x) (1 << (x)) + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + + + +/* IEEE 802.11 defines */ + +#define WLAN_FC_PVER (BIT(1) | BIT(0)) +#define WLAN_FC_TODS BIT(8) +#define WLAN_FC_FROMDS BIT(9) +#define WLAN_FC_MOREFRAG BIT(10) +#define WLAN_FC_RETRY BIT(11) +#define WLAN_FC_PWRMGT BIT(12) +#define WLAN_FC_MOREDATA BIT(13) +#define WLAN_FC_ISWEP BIT(14) +#define WLAN_FC_ORDER BIT(15) + +#define WLAN_FC_GET_TYPE(fc) (((fc) & (BIT(3) | BIT(2))) >> 2) +#define WLAN_FC_GET_STYPE(fc) \ + (((fc) & (BIT(7) | BIT(6) | BIT(5) | BIT(4))) >> 4) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) +#define WLAN_GET_SEQ_SEQ(seq) \ + (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) + +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_TYPE_CTRL 1 +#define WLAN_FC_TYPE_DATA 2 + +/* management */ +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_ASSOC_RESP 1 +#define WLAN_FC_STYPE_REASSOC_REQ 2 +#define WLAN_FC_STYPE_REASSOC_RESP 3 +#define WLAN_FC_STYPE_PROBE_REQ 4 +#define WLAN_FC_STYPE_PROBE_RESP 5 +#define WLAN_FC_STYPE_BEACON 8 +#define WLAN_FC_STYPE_ATIM 9 +#define WLAN_FC_STYPE_DISASSOC 10 +#define WLAN_FC_STYPE_AUTH 11 +#define WLAN_FC_STYPE_DEAUTH 12 + +/* control */ +#define WLAN_FC_STYPE_PSPOLL 10 +#define WLAN_FC_STYPE_RTS 11 +#define WLAN_FC_STYPE_CTS 12 +#define WLAN_FC_STYPE_ACK 13 +#define WLAN_FC_STYPE_CFEND 14 +#define WLAN_FC_STYPE_CFENDACK 15 + +/* data */ +#define WLAN_FC_STYPE_DATA 0 +#define WLAN_FC_STYPE_DATA_CFACK 1 +#define WLAN_FC_STYPE_DATA_CFPOLL 2 +#define WLAN_FC_STYPE_DATA_CFACKPOLL 3 +#define WLAN_FC_STYPE_NULLFUNC 4 +#define WLAN_FC_STYPE_CFACK 5 +#define WLAN_FC_STYPE_CFPOLL 6 +#define WLAN_FC_STYPE_CFACKPOLL 7 + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS BIT(0) +#define WLAN_CAPABILITY_IBSS BIT(1) +#define WLAN_CAPABILITY_CF_POLLABLE BIT(2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) +#define WLAN_CAPABILITY_PRIVACY BIT(4) + +/* Status codes */ +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 +#define WLAN_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 +#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 +#define WLAN_STATUS_CHALLENGE_FAIL 15 +#define WLAN_STATUS_AUTH_TIMEOUT 16 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_ASSOC_DENIED_RATES 18 +/* 802.11b */ +#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 + +/* Reason codes */ +#define WLAN_REASON_UNSPECIFIED 1 +#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 +#define WLAN_REASON_DEAUTH_LEAVING 3 +#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define WLAN_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 +#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 + + +/* Information Element IDs */ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARAMS 2 +#define WLAN_EID_DS_PARAMS 3 +#define WLAN_EID_CF_PARAMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARAMS 6 +#define WLAN_EID_CHALLENGE 16 + + +/* HFA384X Configuration RIDs */ +#define HFA384X_RID_CNFPORTTYPE 0xFC00 +#define HFA384X_RID_CNFOWNMACADDR 0xFC01 +#define HFA384X_RID_CNFDESIREDSSID 0xFC02 +#define HFA384X_RID_CNFOWNCHANNEL 0xFC03 +#define HFA384X_RID_CNFOWNSSID 0xFC04 +#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 +#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 +#define HFA384X_RID_CNFMAXDATALEN 0xFC07 +#define HFA384X_RID_CNFWDSADDRESS 0xFC08 +#define HFA384X_RID_CNFPMENABLED 0xFC09 +#define HFA384X_RID_CNFPMEPS 0xFC0A +#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B +#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C +#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D +#define HFA384X_RID_CNFOWNNAME 0xFC0E +#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 +#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ +#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ +#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ +#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ +#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ +#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ +#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ +#define HFA384X_RID_UNKNOWN1 0xFC20 +#define HFA384X_RID_UNKNOWN2 0xFC21 +#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 +#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 +#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 +#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 +#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 +#define HFA384X_RID_CNFWEPFLAGS 0xFC28 +#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 +#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A +#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ +#define HFA384X_RID_CNFTXCONTROL 0xFC2C +#define HFA384X_RID_CNFROAMINGMODE 0xFC2D +#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ +#define HFA384X_RID_CNFRCVCRCERROR 0xFC30 +#define HFA384X_RID_CNFMMLIFE 0xFC31 +#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 +#define HFA384X_RID_CNFBEACONINT 0xFC33 +#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ +#define HFA384X_RID_CNFSTAPCFINFO 0xFC35 +#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 +#define HFA384X_RID_CNFTIMCTRL 0xFC40 +#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ +#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ +#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ +#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ +#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; + * write only */ +#define HFA384X_RID_GROUPADDRESSES 0xFC80 +#define HFA384X_RID_CREATEIBSS 0xFC81 +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 +#define HFA384X_RID_RTSTHRESHOLD 0xFC83 +#define HFA384X_RID_TXRATECONTROL 0xFC84 +#define HFA384X_RID_PROMISCUOUSMODE 0xFC85 +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ +#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ +#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ +#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ +#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 +#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 +#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HFA384X_RID_CNFBASICRATES 0xFCB3 +#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ +#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ +#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ +#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ +#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ +#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ +#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ +#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ +#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ +#define HFA384X_RID_TICKTIME 0xFCE0 +#define HFA384X_RID_SCANREQUEST 0xFCE1 +#define HFA384X_RID_JOINREQUEST 0xFCE2 +#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ +#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ +#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ + +/* HFA384X Information RIDs */ +#define HFA384X_RID_MAXLOADTIME 0xFD00 +#define HFA384X_RID_DOWNLOADBUFFER 0xFD01 +#define HFA384X_RID_PRIID 0xFD02 +#define HFA384X_RID_PRISUPRANGE 0xFD03 +#define HFA384X_RID_CFIACTRANGES 0xFD04 +#define HFA384X_RID_NICSERNUM 0xFD0A +#define HFA384X_RID_NICID 0xFD0B +#define HFA384X_RID_MFISUPRANGE 0xFD0C +#define HFA384X_RID_CFISUPRANGE 0xFD0D +#define HFA384X_RID_CHANNELLIST 0xFD10 +#define HFA384X_RID_REGULATORYDOMAINS 0xFD11 +#define HFA384X_RID_TEMPTYPE 0xFD12 +#define HFA384X_RID_CIS 0xFD13 +#define HFA384X_RID_STAID 0xFD20 +#define HFA384X_RID_STASUPRANGE 0xFD21 +#define HFA384X_RID_MFIACTRANGES 0xFD22 +#define HFA384X_RID_CFIACTRANGES2 0xFD23 +#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; + * only Prism2.5(?) */ +#define HFA384X_RID_PORTSTATUS 0xFD40 +#define HFA384X_RID_CURRENTSSID 0xFD41 +#define HFA384X_RID_CURRENTBSSID 0xFD42 +#define HFA384X_RID_COMMSQUALITY 0xFD43 +#define HFA384X_RID_CURRENTTXRATE 0xFD44 +#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 +#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 +#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 +#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 +#define HFA384X_RID_LONGRETRYLIMIT 0xFD49 +#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A +#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B +#define HFA384X_RID_CFPOLLABLE 0xFD4C +#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D +#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ +#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ +#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ +#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ +#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ +#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ +#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ +#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ +#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ +#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ +#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ +#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ +#define HFA384X_RID_PHYTYPE 0xFDC0 +#define HFA384X_RID_CURRENTCHANNEL 0xFDC1 +#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 +#define HFA384X_RID_CCAMODE 0xFDC3 +#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 +#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ +#define HFA384X_RID_BUILDSEQ 0xFFFE +#define HFA384X_RID_FWID 0xFFFF + + +struct hfa384x_comp_ident +{ + u16 id; + u16 variant; + u16 major; + u16 minor; +} __attribute__ ((packed)); + +#define HFA384X_COMP_ID_PRI 0x15 +#define HFA384X_COMP_ID_STA 0x1f +#define HFA384X_COMP_ID_FW_AP 0x14b + +struct hfa384x_sup_range +{ + u16 role; + u16 id; + u16 variant; + u16 bottom; + u16 top; +} __attribute__ ((packed)); + + +struct hfa384x_build_id +{ + u16 pri_seq; + u16 sec_seq; +} __attribute__ ((packed)); + +/* FD01 - Download Buffer */ +struct hfa384x_rid_download_buffer +{ + u16 page; + u16 offset; + u16 length; +} __attribute__ ((packed)); + +/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ +struct hfa384x_comms_quality { + u16 comm_qual; /* 0 .. 92 */ + u16 signal_level; /* 27 .. 154 */ + u16 noise_level; /* 27 .. 154 */ +} __attribute__ ((packed)); + + +/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ + +#if WIRELESS_EXT >= 12 + +/* New wireless extensions API - SET/GET convention (even ioctl numbers are + * root only) + */ +#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) +#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) +#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) +#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) +#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) +#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) +#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) +#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) +#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) +#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) +#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) +#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) +#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) +#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) + +/* following are not in SIOCGIWPRIV list; check permission in the driver code + */ +#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) +#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) + +#else /* WIRELESS_EXT >= 12 */ + +/* Old wireless extensions API - check permission in the driver code */ +#define PRISM2_IOCTL_MONITOR (SIOCDEVPRIVATE) +#define PRISM2_IOCTL_PRISM2_PARAM (SIOCDEVPRIVATE + 1) +#define PRISM2_IOCTL_READMIF (SIOCDEVPRIVATE + 2) +#define PRISM2_IOCTL_WRITEMIF (SIOCDEVPRIVATE + 3) +#define PRISM2_IOCTL_RESET (SIOCDEVPRIVATE + 4) +#define PRISM2_IOCTL_INQUIRE (SIOCDEVPRIVATE + 5) +#define PRISM2_IOCTL_WDS_ADD (SIOCDEVPRIVATE + 6) +#define PRISM2_IOCTL_WDS_DEL (SIOCDEVPRIVATE + 7) +#define PRISM2_IOCTL_SET_RID_WORD (SIOCDEVPRIVATE + 8) +#define PRISM2_IOCTL_MACCMD (SIOCDEVPRIVATE + 9) +#define PRISM2_IOCTL_ADDMAC (SIOCDEVPRIVATE + 10) +#define PRISM2_IOCTL_DELMAC (SIOCDEVPRIVATE + 11) +#define PRISM2_IOCTL_KICKMAC (SIOCDEVPRIVATE + 12) +#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) +#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) + +#endif /* WIRELESS_EXT >= 12 */ + + +/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ +enum { + PRISM2_PARAM_PTYPE = 1, + PRISM2_PARAM_TXRATECTRL = 2, + PRISM2_PARAM_BEACON_INT = 3, + PRISM2_PARAM_PSEUDO_IBSS = 4, + PRISM2_PARAM_ALC = 5, + PRISM2_PARAM_TXPOWER = 6, + PRISM2_PARAM_DUMP = 7, + PRISM2_PARAM_OTHER_AP_POLICY = 8, + PRISM2_PARAM_AP_MAX_INACTIVITY = 9, + PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, + PRISM2_PARAM_DTIM_PERIOD = 11, + PRISM2_PARAM_AP_NULLFUNC_ACK = 12, + PRISM2_PARAM_MAX_WDS = 13, + PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, + PRISM2_PARAM_AP_AUTH_ALGS = 15, + PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, + PRISM2_PARAM_HOST_ENCRYPT = 17, + PRISM2_PARAM_HOST_DECRYPT = 18, + PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, + PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, + PRISM2_PARAM_HOST_ROAMING = 21, + PRISM2_PARAM_BCRX_STA_KEY = 22, + PRISM2_PARAM_IEEE_802_1X = 23, + PRISM2_PARAM_ANTSEL_TX = 24, + PRISM2_PARAM_ANTSEL_RX = 25, + PRISM2_PARAM_MONITOR_TYPE = 26, + PRISM2_PARAM_WDS_TYPE = 27, + PRISM2_PARAM_HOSTSCAN = 28, + PRISM2_PARAM_AP_SCAN = 29, + PRISM2_PARAM_ENH_SEC = 30, + PRISM2_PARAM_IO_DEBUG = 31, + PRISM2_PARAM_BASIC_RATES = 32, + PRISM2_PARAM_OPER_RATES = 33, + PRISM2_PARAM_HOSTAPD = 34, +}; + +enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, + HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; + + +/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ +enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, + AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, + AP_MAC_CMD_KICKALL = 4 }; + + +/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ +enum { + PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, + /* Note! Old versions of prism2_srec have a fatal error in CRC-16 + * calculation, which will corrupt all non-volatile downloads. + * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to + * prevent use of old versions of prism2_srec for non-volatile + * download. */ + PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, + PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, + /* Persistent versions of volatile download commands (keep firmware + * data in memory and automatically re-download after hw_reset */ + PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, + PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, +}; + +struct prism2_download_param { + u32 dl_cmd; + u32 start_addr; + u32 num_areas; + struct prism2_download_area { + u32 addr; /* wlan card address */ + u32 len; + caddr_t ptr; /* pointer to data in user space */ + } data[0]; +}; + +#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 +#define PRISM2_MAX_DOWNLOAD_LEN 262144 + + +/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ +enum { + PRISM2_HOSTAPD_FLUSH = 1, + PRISM2_HOSTAPD_ADD_STA = 2, + PRISM2_HOSTAPD_REMOVE_STA = 3, + PRISM2_HOSTAPD_GET_INFO_STA = 4, + /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ + PRISM2_SET_ENCRYPTION = 6, + PRISM2_GET_ENCRYPTION = 7, + PRISM2_HOSTAPD_SET_FLAGS_STA = 8, + PRISM2_HOSTAPD_GET_RID = 9, + PRISM2_HOSTAPD_SET_RID = 10, + PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, +}; + +#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 +#define PRISM2_HOSTAPD_RID_HDR_LEN \ +((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) + +/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() + */ +#define HOSTAP_CRYPT_ALG_NAME_LEN 16 + + +struct prism2_hostapd_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u16 aid; + u16 capability; + u8 tx_supp_rates; + } add_sta; + struct { + u32 inactive_sec; + } get_info_sta; + struct { + u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; + u32 flags; + u32 err; + u8 idx; + u16 key_len; + u8 key[0]; + } crypt; + struct { + u32 flags_and; + u32 flags_or; + } set_flags_sta; + struct { + u16 rid; + u16 len; + u8 data[0]; + } rid; + } u; +}; + +#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) +#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) + +#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 +#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 +#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 +#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 + + +#endif /* HOSTAP_COMMON_H */ diff -Nru a/drivers/net/wireless/hostap_compat.h b/drivers/net/wireless/hostap_compat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_compat.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,172 @@ +#ifndef HOSTAP_COMPAT_H +#define HOSTAP_COMPAT_H + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)) +#define NEW_MODULE_CODE +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +/* 2.2 compatibility */ + +#include +#include +#include + +#ifndef spin_lock_bh +#define spin_lock_bh(lock) spin_lock_irq(lock) +#define spin_unlock_bh(lock) spin_unlock_irq(lock) +#endif + +#ifndef read_lock_bh +#define read_lock_bh(lock) read_lock_irq(lock) +#define read_unlock_bh(lock) read_unlock_irq(lock) +#define rwlock_init(l) +#endif + +#ifndef __constant_cpu_to_le16 +#define __constant_cpu_to_le16 __cpu_to_le16 +#endif + +#ifndef dev_get_by_name +#define dev_get_by_name(dev) dev_get(dev) +#endif + +#define PRISM2_NETDEV_EXTRA IFNAMSIZ +#define prism2_set_dev_name(dev, pos) (dev)->name = (char *) (pos) + +#define HOSTAP_QUEUE struct tq_struct + +/* tq_scheduler was removed in 2.4.0-test12 */ +#define PRISM2_SCHEDULE_TASK(q) \ +MOD_INC_USE_COUNT; \ +queue_task((q), &tq_scheduler); + +static inline void flush_scheduled_work(void) +{ + schedule(); + schedule(); +} + +static inline void INIT_WORK(struct tq_struct *tq, + void (*routine)(void *), void *data) +{ + tq->next = NULL; + tq->sync = 0; + tq->routine = routine; + tq->data = data; +} + +#define HOSTAP_TASKLET struct tq_struct + +static inline void tasklet_schedule(struct tq_struct *q) +{ + queue_task(q, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +typedef void (*tasklet_func)(void *); + +#define HOSTAP_TASKLET_INIT(q, f, d) \ +do { memset((q), 0, sizeof(*(q))); \ +(q)->routine = (tasklet_func) (f); \ +(q)->data = (void *) (d); } \ +while (0) + + +static inline void dev_kfree_skb_any(struct sk_buff *skb) +{ + if (in_interrupt()) + dev_kfree_skb_irq(skb); + else + dev_kfree_skb(skb); +} + +static __inline__ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + +/* end 2.2 compatibility */ + +#else /* kernel < 2.4.0 */ + +/* no extra space needed for 2.4.x net_device */ +#define PRISM2_NETDEV_EXTRA 0 +#define prism2_set_dev_name(dev, pos) do { } while (0) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) + +#define HOSTAP_QUEUE struct tq_struct + +#define PRISM2_SCHEDULE_TASK(q) \ +MOD_INC_USE_COUNT; \ +if (schedule_task((q)) == 0) \ + MOD_DEC_USE_COUNT; + +#else /* kernel < 2.5.44 */ + +#define HOSTAP_QUEUE struct work_struct + +#ifdef NEW_MODULE_CODE +#define PRISM2_SCHEDULE_TASK(q) schedule_work(q); +#else /* NEW_MODULE_CODE */ +#define PRISM2_SCHEDULE_TASK(q) \ +MOD_INC_USE_COUNT; \ +if (schedule_work((q)) == 0) \ + MOD_DEC_USE_COUNT; +#endif /* NEW_MODULE_CODE */ + +#endif /* kernel < 2.5.44 */ + +#define HOSTAP_TASKLET struct tasklet_struct + +#define HOSTAP_TASKLET_INIT(q, f, d) \ +do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \ +while (0) + +#endif /* kernel < 2.4.0 */ + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)) +#define yield() schedule() +#endif + + +/* Interrupt handler backwards compatibility for Linux < 2.5.69 */ +#ifndef IRQ_NONE +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +typedef void irqreturn_t; +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(var) +#endif + +#if WIRELESS_EXT > 12 +#if IW_HANDLER_VERSION < 3 +extern void wireless_send_event(struct net_device *dev, + unsigned int cmd, + union iwreq_data *wrqu, + char *extra); +#endif /* IW_HANDLER_VERSION < 3 */ +#endif /* WIRELESS_EXT > 12 */ + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)) +struct net_device; +static inline void free_netdev(struct net_device *dev) +{ + kfree(dev); +} +#endif + +#endif /* HOSTAP_COMPAT_H */ diff -Nru a/drivers/net/wireless/hostap_config.h b/drivers/net/wireless/hostap_config.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_config.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,92 @@ +#ifndef HOSTAP_CONFIG_H +#define HOSTAP_CONFIG_H + +#define PRISM2_VERSION "0.1.2 - 2003-11-02" + +/* In the previous versions of Host AP driver, support for user space version + * of IEEE 802.11 management (hostapd) used to be disabled in the default + * configuration. From now on, support for hostapd is always included and it is + * possible to disable kernel driver version of IEEE 802.11 management with a + * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ +/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ + +/* Maximum number of events handler per one interrupt */ +#define PRISM2_MAX_INTERRUPT_EVENTS 20 + +/* Use PCI bus master to copy data to/from BAP (only available for + * hostap_pci.o). + * + * Note! This is extremely experimental. PCI bus master is not supported by + * Intersil and it seems to have some problems at least on TX path (see below). + * The driver code for implementing bus master support is based on guessing + * and experimenting suitable control bits and these might not be correct. + * This code is included because using bus master makes a huge difference in + * host CPU load (something like 40% host CPU usage to 5-10% when sending or + * receiving at maximum throughput). + * + * Note2! Station firmware version 1.3.5 and primary firmware version 1.0.7 + * have some fixes for PCI corruption and these (or newer) versions are + * recommended especially when using bus mastering. */ +/* #define PRISM2_BUS_MASTER */ + +#ifdef PRISM2_BUS_MASTER + +/* PCI bus master implementation seems to be broken in current + * hardware/firmware versions. Enable this to use enable command to fix + * something before starting bus master operation on TX path. This will add + * some latency and an extra interrupt to each TX packet. */ +#define PRISM2_ENABLE_BEFORE_TX_BUS_MASTER + +#endif /* PRISM2_BUS_MASTER */ + +/* Include code for downloading firmware images. */ +/* #define PRISM2_DOWNLOAD_SUPPORT */ + +/* Allow kernel configuration to enable download support. */ +#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) +#define PRISM2_DOWNLOAD_SUPPORT +#endif + +#ifdef PRISM2_DOWNLOAD_SUPPORT +/* Allow writing firmware images into flash, i.e., to non-volatile storage. + * Before you enable this option, you should make absolutely sure that you are + * using prism2_srec utility that comes with THIS version of the driver! + * In addition, please note that it is possible to kill your card with + * non-volatile download if you are using incorrect image. This feature has not + * been fully tested, so please be careful with it. */ +/* #define PRISM2_NON_VOLATILE_DOWNLOAD */ +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + +/* Include wireless extensions sub-ioctl support even if wireless extensions + * version is less than 15 (actually, only if it is 12 .. 14). If ver >= 15, + * these will be included. Please note, that this requires iwpriv version 25 + * or higher (older versions will segfault due to long ioctl list). */ +/* #define PRISM2_USE_WE_SUB_IOCTLS */ + +/* Use IW_PRIV_TYPE_ADDR with private WE ioctls taking MAC address argument + * (instead of old 18*char). This requires iwpriv ver >= 25. This will be + * automatically included for WIRELESS_EXT >= 15. */ +/* #define PRISM2_USE_WE_TYPE_ADDR */ + +/* Save low-level I/O for debugging. This should not be enabled in normal use. + */ +/* #define PRISM2_IO_DEBUG */ + +/* Following defines can be used to remove unneeded parts of the driver, e.g., + * to limit the size of the kernel module. Definitions can be added here in + * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, + * e.g., + * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' + */ + +/* Do not include debug messages into the driver */ +/* #define PRISM2_NO_DEBUG */ + +/* Do not include /proc/net/prism2/wlan#/{registers,debug} */ +/* #define PRISM2_NO_PROCFS_DEBUG */ + +/* Do not include station functionality (i.e., allow only Master (Host AP) mode + */ +/* #define PRISM2_NO_STATION_MODES */ + +#endif /* HOSTAP_CONFIG_H */ diff -Nru a/drivers/net/wireless/hostap_crypt.c b/drivers/net/wireless/hostap_crypt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_crypt.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,194 @@ +/* + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +#ifdef HOSTAP_CRYPT_MODULE +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "hostap_crypt.h" +#include "hostap_compat.h" + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypto"); +MODULE_LICENSE("GPL"); +#endif /* HOSTAP_CRYPT_MODULE */ + + +struct hostap_crypto_alg { + struct list_head list; + struct hostap_crypto_ops *ops; +}; + + +struct hostap_crypto { + struct list_head algs; + spinlock_t lock; +}; + +static struct hostap_crypto *hcrypt; + + +int hostap_register_crypto_ops(struct hostap_crypto_ops *ops) +{ + unsigned long flags; + struct hostap_crypto_alg *alg; + + if (hcrypt == NULL) + return -1; + + alg = (struct hostap_crypto_alg *) kmalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + memset(alg, 0, sizeof(*alg)); + alg->ops = ops; + + spin_lock_irqsave(&hcrypt->lock, flags); + list_add(&alg->list, &hcrypt->algs); + spin_unlock_irqrestore(&hcrypt->lock, flags); + + printk(KERN_DEBUG "hostap_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} + + +int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops) +{ + unsigned long flags; + struct list_head *ptr; + struct hostap_crypto_alg *del_alg = NULL; + + if (hcrypt == NULL) + return -1; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct hostap_crypto_alg *alg = + (struct hostap_crypto_alg *) ptr; + if (alg->ops == ops) { + list_del(&alg->list); + del_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (del_alg) { + printk(KERN_DEBUG "hostap_crypt: unregistered algorithm " + "'%s'\n", ops->name); + kfree(del_alg); + } + + return del_alg ? 0 : -1; +} + + +struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name) +{ + unsigned long flags; + struct list_head *ptr; + struct hostap_crypto_alg *found_alg = NULL; + + if (hcrypt == NULL) + return NULL; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct hostap_crypto_alg *alg = + (struct hostap_crypto_alg *) ptr; + if (strcmp(alg->ops->name, name) == 0) { + found_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (found_alg) + return found_alg->ops; + else + return NULL; +} + + +static void * hostap_crypt_null_init(void) { return (void *) 1; } +static void hostap_crypt_null_deinit(void *priv) {} + +static struct hostap_crypto_ops hostap_crypt_null = { + .name = "NULL", + .init = hostap_crypt_null_init, + .deinit = hostap_crypt_null_deinit, + .encrypt = NULL, + .decrypt = NULL, + .set_key = NULL, + .get_key = NULL, + .set_key_idx = NULL, + .get_key_idx = NULL, + .extra_prefix_len = 0, + .extra_postfix_len = 0 +}; + + +static int __init hostap_crypto_init(void) +{ + hcrypt = (struct hostap_crypto *) kmalloc(sizeof(*hcrypt), GFP_KERNEL); + if (hcrypt == NULL) + return -ENOMEM; + + memset(hcrypt, 0, sizeof(*hcrypt)); + INIT_LIST_HEAD(&hcrypt->algs); + spin_lock_init(&hcrypt->lock); + + (void) hostap_register_crypto_ops(&hostap_crypt_null); + + return 0; +} + + +static void __exit hostap_crypto_deinit(void) +{ + struct list_head *ptr, *n; + + if (hcrypt == NULL) + return; + + for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; + ptr = n, n = ptr->next) { + struct hostap_crypto_alg *alg = + (struct hostap_crypto_alg *) ptr; + list_del(ptr); + printk(KERN_DEBUG "hostap_crypt: unregistered algorithm " + "'%s' (deinit)\n", alg->ops->name); + kfree(alg); + } + + kfree(hcrypt); +} + + +EXPORT_SYMBOL(hostap_register_crypto_ops); +EXPORT_SYMBOL(hostap_unregister_crypto_ops); +EXPORT_SYMBOL(hostap_get_crypto_ops); + +#ifdef HOSTAP_CRYPT_MODULE +module_init(hostap_crypto_init); +module_exit(hostap_crypto_deinit); +#endif /* HOSTAP_CRYPT_MODULE */ diff -Nru a/drivers/net/wireless/hostap_crypt.h b/drivers/net/wireless/hostap_crypt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_crypt.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,39 @@ +#ifndef PRISM2_CRYPT_H +#define PRISM2_CRYPT_H + +struct hostap_crypto_ops { + char *name; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void * (*init)(void); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit)(void *priv); + + /* encrypt/decrypt return < 0 on error or number of bytes written + * to out_buf; len is number of bytes in in_buf */ + int (*encrypt)(u8 *buf, int len, void *priv); + int (*decrypt)(u8 *buf, int len, void *priv); + + int (*set_key)(int idx, void *key, int len, void *priv); + int (*get_key)(int idx, void *key, int len, void *priv); + + int (*set_key_idx)(int idx, void *priv); + int (*get_key_idx)(void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_prefix_len, extra_postfix_len; +}; + + +int hostap_register_crypto_ops(struct hostap_crypto_ops *ops); +int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops); +struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name); + +#endif /* PRISM2_CRYPT_H */ diff -Nru a/drivers/net/wireless/hostap_crypt_wep.c b/drivers/net/wireless/hostap_crypt_wep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_crypt_wep.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,364 @@ +/* + * Host AP crypt: host-based WEP encryption implementation for Host AP driver + * + * Copyright (c) 2002, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) +#include +#else +#include +#endif +#include + +#include "hostap_crypt.h" +#include "hostap_compat.h" + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: WEP"); +MODULE_LICENSE("GPL"); + + +struct prism2_wep_data { + u32 iv; +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 + u8 keys[WEP_KEYS][WEP_KEY_LEN + 1]; + u8 key_lens[WEP_KEYS]; + int tx_key; +}; + +static const __u32 crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + + +static void * prism2_wep_init(void) +{ + struct prism2_wep_data *priv; + +#ifndef NEW_MODULE_CODE + MOD_INC_USE_COUNT; +#endif + + priv = (struct prism2_wep_data *) kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) { +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif + return NULL; + } + memset(priv, 0, sizeof(*priv)); + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; +} + + +static void prism2_wep_deinit(void *priv) +{ + kfree(priv); +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +/* Perform WEP encryption on given buffer. Buffer needs to has 4 bytes of + * extra space (IV) in the beginning, then len bytes of data, and finally + * 4 bytes of extra space (ICV). Both IV and ICV will be transmitted, so the + * payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int prism2_wep_encrypt(u8 *buf, int len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 i, j, k, crc, klen; + u8 S[256], key[WEP_KEY_LEN + 3]; + u8 kpos, *pos; +#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) + + klen = 3 + wep->key_lens[wep->tx_key]; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + pos = buf; + *pos++ = key[0] = (wep->iv >> 16) & 0xff; + *pos++ = key[1] = (wep->iv >> 8) & 0xff; + *pos++ = key[2] = wep->iv & 0xff; + *pos++ = wep->tx_key << 6; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->keys[wep->tx_key], + wep->key_lens[wep->tx_key]); + + /* Setup RC4 state */ + for (i = 0; i < 256; i++) + S[i] = i; + j = 0; + kpos = 0; + for (i = 0; i < 256; i++) { + j = (j + S[i] + key[kpos]) & 0xff; + kpos++; + if (kpos >= klen) + kpos = 0; + S_SWAP(i, j); + } + + /* Compute CRC32 over unencrypted data and apply RC4 to data */ + crc = ~0; + i = j = 0; + for (k = 0; k < len; k++) { + crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos++ ^= S[(S[i] + S[j]) & 0xff]; + } + crc = ~crc; + + /* Append little-endian CRC32 and encrypt it to produce ICV */ + pos[0] = crc; + pos[1] = crc >> 8; + pos[2] = crc >> 16; + pos[3] = crc >> 24; + for (k = 0; k < 4; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos++ ^= S[(S[i] + S[j]) & 0xff]; + } + + return len + 8; +} + + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload + * is moved to beginning of buf and last 8 bytes of buf should be ignored. + */ +static int prism2_wep_decrypt(u8 *buf, int len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 i, j, k, crc, klen; + u8 S[256], key[WEP_KEY_LEN + 3]; + u8 keyidx, kpos, *dpos, *cpos; + + if (len < 8) + return -1; + + key[0] = buf[0]; + key[1] = buf[1]; + key[2] = buf[2]; + keyidx = buf[3] >> 6; + + klen = 3 + wep->key_lens[keyidx]; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->keys[keyidx], wep->key_lens[keyidx]); + + /* Setup RC4 state */ + for (i = 0; i < 256; i++) + S[i] = i; + j = 0; + kpos = 0; + for (i = 0; i < 256; i++) { + j = (j + S[i] + key[kpos]) & 0xff; + kpos++; + if (kpos >= klen) + kpos = 0; + S_SWAP(i, j); + } + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + dpos = buf; + cpos = buf + 4; + crc = ~0; + i = j = 0; + for (k = 0; k < len - 8; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *dpos = *cpos++ ^ S[(S[i] + S[j]) & 0xff]; + crc = crc32_table[(crc ^ *dpos++) & 0xff] ^ (crc >> 8); + } + crc = ~crc; + + /* Encrypt little-endian CRC32 and verify that it matches with the + * received ICV */ + dpos[0] = crc; + dpos[1] = crc >> 8; + dpos[2] = crc >> 16; + dpos[3] = crc >> 24; + for (k = 0; k < 4; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + if ((*dpos++ ^ S[(S[i] + S[j]) & 0xff]) != *cpos++) { + /* ICV mismatch - drop frame */ + return -1; + } + } + + return len - 8; +} + + +static int prism2_wep_set_key(int idx, void *key, int len, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (idx < 0 || idx >= WEP_KEYS || len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->keys[idx], key, len); + wep->key_lens[idx] = len; + + return 0; +} + + +static int prism2_wep_get_key(int idx, void *key, int len, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (idx < 0 || idx >= WEP_KEYS || len < wep->key_lens[idx]) + return -1; + + memcpy(key, wep->keys[idx], wep->key_lens[idx]); + + return wep->key_lens[idx]; +} + + +static int prism2_wep_set_key_idx(int idx, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (idx < 0 || idx >= WEP_KEYS || wep->key_lens[idx] == 0) + return -1; + + wep->tx_key = idx; + + return 0; +} + + +static int prism2_wep_get_key_idx(void *priv) +{ + struct prism2_wep_data *wep = priv; + return wep->tx_key; +} + + +static struct hostap_crypto_ops hostap_crypt_wep = { + .name = "WEP", + .init = prism2_wep_init, + .deinit = prism2_wep_deinit, + .encrypt = prism2_wep_encrypt, + .decrypt = prism2_wep_decrypt, + .set_key = prism2_wep_set_key, + .get_key = prism2_wep_get_key, + .set_key_idx = prism2_wep_set_key_idx, + .get_key_idx = prism2_wep_get_key_idx, + .extra_prefix_len = 4 /* IV */, + .extra_postfix_len = 4 /* ICV */ +}; + + +static int __init hostap_crypto_wep_init(void) +{ + if (hostap_register_crypto_ops(&hostap_crypt_wep) < 0) + return -1; + + return 0; +} + + +static void __exit hostap_crypto_wep_exit(void) +{ + hostap_unregister_crypto_ops(&hostap_crypt_wep); +} + + +module_init(hostap_crypto_wep_init); +module_exit(hostap_crypto_wep_exit); diff -Nru a/drivers/net/wireless/hostap_cs.c b/drivers/net/wireless/hostap_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_cs.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,877 @@ +#define PRISM2_PCCARD + +#include +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif /* __IN_PCMCIA_PACKAGE__ */ +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) +#include +#else +#include +#endif +#include "hostap_wext.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "hostap_wlan.h" + + +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif /* __IN_PCMCIA_PACKAGE__ */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +/* This behavior changed in some Linux 2.5.x version. I don't remember when and + * don't really care if this does not work with some early 2.5.x versions.. + */ +#define HOSTAP_USE_RELEASE_TIMER +#endif + + +static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static dev_info_t dev_info = "hostap_cs"; +static dev_link_t *dev_list = NULL; + +MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen"); +MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " + "cards (PC Card)."); +MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); +MODULE_LICENSE("GPL"); + + +static unsigned int irq_mask = 0xdeb8; +MODULE_PARM(irq_mask, "i"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); + +static int ignore_cis_vcc = 0; +MODULE_PARM(ignore_cis_vcc, "i"); +MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); + + +#ifdef PRISM2_IO_DEBUG + +static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); + outb(v, dev->base_addr + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u8 v; + + spin_lock_irqsave(&local->lock, flags); + v = inb(dev->base_addr + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); + outw(v, dev->base_addr + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u16 v; + + spin_lock_irqsave(&local->lock, flags); + v = inw(dev->base_addr + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +static inline void hfa384x_outsw_debug(struct net_device *dev, int a, + u8 *buf, int wc) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); + outsw(dev->base_addr + a, buf, wc); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline void hfa384x_insw_debug(struct net_device *dev, int a, + u8 *buf, int wc) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); + insw(dev->base_addr + a, buf, wc); + spin_unlock_irqrestore(&local->lock, flags); +} + +#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) +#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) +#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) +#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) +#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) +#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) + +#else /* PRISM2_IO_DEBUG */ + +#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) +#define HFA384X_INB(a) inb(dev->base_addr + (a)) +#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) +#define HFA384X_INW(a) inw(dev->base_addr + (a)) +#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) +#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) + +#endif /* PRISM2_IO_DEBUG */ + + +static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, + int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + if (len / 2) + HFA384X_INSW(d_off, buf, len / 2); + pos += len / 2; + + if (len & 1) + *((char *) pos) = HFA384X_INB(d_off); + + return 0; +} + + +static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + if (len / 2) + HFA384X_OUTSW(d_off, buf, len / 2); + pos += len / 2; + + if (len & 1) + HFA384X_OUTB(*((char *) pos), d_off); + + return 0; +} + + +/* FIX: This might change at some point.. */ +#include "hostap_hw.c" + + + +static void prism2_detach(dev_link_t *link); +static void prism2_release(u_long arg); +static int prism2_event(event_t event, int priority, + event_callback_args_t *args); + + +static int prism2_pccard_card_present(local_info_t *local) +{ + if (local->link != NULL && + ((local->link->state & (DEV_PRESENT | DEV_CONFIG)) == + (DEV_PRESENT | DEV_CONFIG))) + return 1; + return 0; +} + +static void prism2_pccard_cor_sreset(local_info_t *local) +{ + int res; + conf_reg_t reg; + + if (!prism2_pccard_card_present(local)) + return; + + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", + res); + return; + } + printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", + reg.Value); + + reg.Action = CS_WRITE; + reg.Value |= COR_SOFT_RESET; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", + res); + return; + } + + mdelay(1); + + reg.Value &= ~COR_SOFT_RESET; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", + res); + return; + } + + mdelay(1); +} + + +static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) +{ + int res; + conf_reg_t reg; + int old_cor; + + if (!prism2_pccard_card_present(local)) + return; + + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " + "(%d)\n", res); + return; + } + printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n", + reg.Value); + old_cor = reg.Value; + + reg.Action = CS_WRITE; + reg.Value |= COR_SOFT_RESET; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " + "(%d)\n", res); + return; + } + + mdelay(10); + + /* Setup Genesis mode */ + reg.Action = CS_WRITE; + reg.Value = hcr; + reg.Offset = CISREG_CCSR; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " + "(%d)\n", res); + return; + } + mdelay(10); + + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = old_cor & ~COR_SOFT_RESET; + res = CardServices(AccessConfigurationRegister, local->link->handle, + ®); + if (res != CS_SUCCESS) { + printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " + "(%d)\n", res); + return; + } + + mdelay(10); +} + + +static int prism2_pccard_dev_open(local_info_t *local) +{ + local->link->open++; + return 0; +} + + +static int prism2_pccard_dev_close(local_info_t *local) +{ + if (local == NULL || local->link == NULL) + return 1; + + if (!local->link->open) { + printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " + "link not open?!\n", local->dev->name); + return 1; + } + + local->link->open--; + + if (local->link->state & DEV_STALE_CONFIG) { +#ifdef HOSTAP_USE_RELEASE_TIMER + mod_timer(&local->link->release, jiffies + HZ / 20); +#else /* HOSTAP_USE_RELEASE_TIMER */ + prism2_release((u_long) local->link); +#endif /* HOSTAP_USE_RELEASE_TIMER */ + } + + return 0; +} + + +static struct prism2_helper_functions prism2_pccard_funcs = +{ + .card_present = prism2_pccard_card_present, + .cor_sreset = prism2_pccard_cor_sreset, + .dev_open = prism2_pccard_dev_open, + .dev_close = prism2_pccard_dev_close, + .genesis_reset = prism2_pccard_genesis_reset, +}; + + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,68) +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} +#endif + + +/* allocate local data and register with CardServices + * initialize dev_link structure, but do not configure the card yet */ +static dev_link_t *prism2_attach(void) +{ + dev_link_t *link; + local_info_t *local; + client_reg_t client_reg; + int ret; + struct net_device *dev; + struct hostap_interface *iface; + + for (link = dev_list; link; link = link->next) { + if (link->state & DEV_STALE_LINK) { + printk("%s: flushing stale link\n", dev_info); + prism2_detach(link); + } + } + + link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); + if (link == NULL) + return NULL; + + memset(link, 0, sizeof(dev_link_t)); + + dev = prism2_init_local_data(&prism2_pccard_funcs, 0); + if (dev == NULL) { + kfree(link); + return NULL; + } + iface = dev->priv; + local = iface->local; + + link->priv = dev; + local->link = link; + +#ifdef HOSTAP_USE_RELEASE_TIMER + init_timer(&link->release); + link->release.function = &prism2_release; + link->release.data = (u_long)link; +#endif /* HOSTAP_USE_RELEASE_TIMER */ + + PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); + link->conf.Vcc = 33; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* register with CardServices */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT; + client_reg.EventMask = CS_EVENT_CARD_INSERTION | + CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &prism2_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + prism2_detach(link); + return NULL; + } + return link; +} + + +static void prism2_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + PDEBUG(DEBUG_FLOW, "prism2_detach\n"); + + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) { + printk(KERN_WARNING "%s: Attempt to detach non-existing " + "PCMCIA client\n", dev_info); + return; + } + +#ifdef HOSTAP_USE_RELEASE_TIMER + del_timer(&link->release); +#endif /* HOSTAP_USE_RELEASE_TIMER */ + if (link->state & DEV_CONFIG) { + printk("%s: detach postponed, '%s' still locked\n", + dev_info, link->dev->dev_name); + prism2_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) { + int res = CardServices(DeregisterClient, link->handle); + if (res) { + printk("CardService(DeregisterClient) => %d\n", res); + cs_error(link->handle, DeregisterClient, res); + } + } + + *linkp = link->next; + /* release net devices */ + if (link->priv) { + prism2_free_local_data((struct net_device *) link->priv); + + } + kfree(link); +} + + +#define CS_CHECK(fn, args...) \ +while ((last_ret = CardServices(last_fn = (fn), args)) != 0) goto cs_failed + +#define CFG_CHECK2(fn, args...) \ +do { int ret = CardServices(fn, args); \ +if (ret != 0) { \ + PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ + cs_error(link->handle, fn, ret); \ + goto next_entry; \ +} \ +} while (0) + + +/* run after a CARD_INSERTATION event is received to configure the PCMCIA + * socket and make the device available to the system */ +static int prism2_config(dev_link_t *link) +{ + struct net_device *dev = (struct net_device *) link->priv; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cistpl_cftable_entry_t dflt = { 0 }; + + PDEBUG(DEBUG_FLOW, "prism2_config()\n"); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, link->handle, &tuple); + CS_CHECK(GetTupleData, link->handle, &tuple); + CS_CHECK(ParseTuple, link->handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + CS_CHECK(GetConfigurationInfo, link->handle, &conf); + PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info, + ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc); + link->conf.Vcc = conf.Vcc; + + /* Look for an appropriate configuration table entry in the CIS */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, link->handle, &tuple); + for (;;) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK2(GetTupleData, link->handle, &tuple); + CFG_CHECK2(ParseTuple, link->handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " + "(default 0x%02X)\n", cfg->index, dflt.index); + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" + " this entry\n"); + goto next_entry; + } + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " + "- skipping this entry\n"); + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { + /* At least Compaq WL200 does not have IRQInfo1 set, + * but it does not work without interrupts.. */ + printk("Config has no IRQ info, but trying to enable " + "IRQ anyway..\n"); + link->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " + "dflt.io.nwin=%d\n", + cfg->io.nwin, dflt.io.nwin); + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " + "io.base=0x%04x, len=%d\n", io->flags, + io->win[0].base, io->win[0].len); + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = io->flags & + CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK2(RequestIO, link->handle, &link->io); + + /* This configuration table entry is OK */ + break; + + next_entry: + CS_CHECK(GetNextTuple, link->handle, &tuple); + } + + /* + * Allocate an interrupt line. Note that this does not assign a + * handler to the interrupt, unless the 'Handler' member of the + * irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + int i; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = (void *) prism2_interrupt; + link->irq.Instance = dev; + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping, and putting the + * card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev_info, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state |= DEV_CONFIG; + link->state &= ~DEV_CONFIG_PENDING; + + if (prism2_init_dev(local)) { + prism2_release((u_long) link); + return 1; + } + + strcpy(local->node.dev_name, dev->name); + link->dev = &local->node; + + local->shutdown = 0; + + ret = prism2_hw_config(dev, 1); + return ret; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + prism2_release((u_long)link); + return 1; +} + + +static void prism2_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = (struct net_device *) link->priv; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + PDEBUG(DEBUG_FLOW, "prism2_release\n"); + + if (link->open) { + printk("%s: release postponed, '%s' still open\n", + dev_info, link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + if (dev != NULL) + prism2_hw_shutdown(dev, 0); + + local->shutdown = 1; + + if (link->win) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + + PDEBUG(DEBUG_FLOW, "release - done\n"); +} + + +static int prism2_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = (struct net_device *) link->priv; + + switch (event) { + case CS_EVENT_CARD_INSERTION: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if (prism2_config(link)) + dev->irq = 0; + break; + + case CS_EVENT_CARD_REMOVAL: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + hostap_netif_stop_queues(dev); + netif_device_detach(dev); +#ifdef HOSTAP_USE_RELEASE_TIMER + mod_timer(&link->release, jiffies + HZ / 20); +#else /* HOSTAP_USE_RELEASE_TIMER */ + prism2_release((u_long) link); +#endif /* HOSTAP_USE_RELEASE_TIMER */ + } + break; + + case CS_EVENT_PM_SUSPEND: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); + link->state |= DEV_SUSPEND; + /* fall through */ + + case CS_EVENT_RESET_PHYSICAL: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); + if (link->state & DEV_CONFIG) { + if (link->open) { + hostap_netif_stop_queues(dev); + netif_device_detach(dev); + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); + link->state &= ~DEV_SUSPEND; + /* fall through */ + + case CS_EVENT_CARD_RESET: + PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info); + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, + &link->conf); + if (link->open) { + prism2_hw_shutdown(dev, 1); + prism2_hw_config(dev, 0); + netif_device_attach(dev); + netif_start_queue(dev); + } + } + break; + + default: + PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n", + dev_info, event); + break; + } + return 0; +} + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) +static struct pcmcia_driver hostap_driver = { + .drv = { + .name = "hostap_cs", + }, + .attach = prism2_attach, + .detach = prism2_detach, + .owner = THIS_MODULE, +}; + +static int __init init_prism2_pccard(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + return pcmcia_register_driver(&hostap_driver); +} + +static void __exit exit_prism2_pccard(void) +{ + pcmcia_unregister_driver(&hostap_driver); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} + +#else + +static int __init init_prism2_pccard(void) +{ + servinfo_t serv; + + printk(KERN_INFO "%s: %s\n", dev_info, version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE + "%s: CardServices release does not match!\n", dev_info); + return -1; + } + register_pccard_driver(&dev_info, &prism2_attach, &prism2_detach); + + return 0; +} + + +static void __exit exit_prism2_pccard(void) +{ + unregister_pccard_driver(&dev_info); + while (dev_list) { + PDEBUG(DEBUG_FLOW, "exit_prism2 - detaching device\n"); +#ifdef HOSTAP_USE_RELEASE_TIMER + del_timer(&dev_list->release); +#endif /* HOSTAP_USE_RELEASE_TIMER */ + if (dev_list->state & DEV_CONFIG) + prism2_release((u_long)dev_list); + prism2_detach(dev_list); + } + + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) */ + + +module_init(init_prism2_pccard); +module_exit(exit_prism2_pccard); diff -Nru a/drivers/net/wireless/hostap_download.c b/drivers/net/wireless/hostap_download.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_download.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,692 @@ +static int prism2_enable_aux_port(struct net_device *dev, int enable) +{ + u16 val, reg; + int i, tries; + unsigned long flags; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + spin_lock_irqsave(&local->cmdlock, flags); + + /* wait until busy bit is clear */ + tries = HFA384X_CMD_BUSY_TIMEOUT; + while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { + tries--; + udelay(1); + } + if (tries == 0) { + reg = HFA384X_INW(HFA384X_CMD_OFF); + spin_unlock_irqrestore(&local->cmdlock, flags); + printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", + dev->name, reg); + return -ETIMEDOUT; + } + + val = HFA384X_INW(HFA384X_CONTROL_OFF); + + if (enable) { + HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); + HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); + HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); + + if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) + printk("prism2_enable_aux_port: was not disabled!?\n"); + val &= ~HFA384X_AUX_PORT_MASK; + val |= HFA384X_AUX_PORT_ENABLE; + } else { + HFA384X_OUTW(0, HFA384X_PARAM0_OFF); + HFA384X_OUTW(0, HFA384X_PARAM1_OFF); + HFA384X_OUTW(0, HFA384X_PARAM2_OFF); + + if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) + printk("prism2_enable_aux_port: was not enabled!?\n"); + val &= ~HFA384X_AUX_PORT_MASK; + val |= HFA384X_AUX_PORT_DISABLE; + } + HFA384X_OUTW(val, HFA384X_CONTROL_OFF); + + udelay(5); + + i = 10000; + while (i > 0) { + val = HFA384X_INW(HFA384X_CONTROL_OFF); + val &= HFA384X_AUX_PORT_MASK; + + if ((enable && val == HFA384X_AUX_PORT_ENABLED) || + (!enable && val == HFA384X_AUX_PORT_DISABLED)) + break; + + udelay(10); + i--; + } + + spin_unlock_irqrestore(&local->cmdlock, flags); + + if (i == 0) { + printk("prism2_enable_aux_port(%d) timed out\n", + enable); + return -ETIMEDOUT; + } + + return 0; +} + + +static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, + void *buf) +{ + u16 page, offset; + if (addr & 1 || len & 1) + return -1; + + page = addr >> 7; + offset = addr & 0x7f; + + HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); + HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); + + udelay(5); + +#ifdef PRISM2_PCI + { + u16 *pos = (u16 *) buf; + while (len > 0) { + *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); + len -= 2; + } + } +#else /* PRISM2_PCI */ + HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); +#endif /* PRISM2_PCI */ + + return 0; +} + + +static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, + void *buf) +{ + u16 page, offset; + if (addr & 1 || len & 1) + return -1; + + page = addr >> 7; + offset = addr & 0x7f; + + HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); + HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); + + udelay(5); + +#ifdef PRISM2_PCI + { + u16 *pos = (u16 *) buf; + while (len > 0) { + HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); + len -= 2; + } + } +#else /* PRISM2_PCI */ + HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); +#endif /* PRISM2_PCI */ + + return 0; +} + + +static int prism2_pda_ok(u8 *buf) +{ + u16 *pda = (u16 *) buf; + int pos; + u16 len, pdr; + + if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && + buf[3] == 0x00) + return 0; + + pos = 0; + while (pos + 1 < PRISM2_PDA_SIZE / 2) { + len = le16_to_cpu(pda[pos]); + pdr = le16_to_cpu(pda[pos + 1]); + if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) + return 0; + + if (pdr == 0x0000 && len == 2) { + /* PDA end found */ + return 1; + } + + pos += len + 1; + } + + return 0; +} + + +static u8 * prism2_read_pda(struct net_device *dev) +{ + u8 *buf; + int res, i, found = 0; +#define NUM_PDA_ADDRS 3 + unsigned int pda_addr[NUM_PDA_ADDRS] = { + 0x7f0000 /* others than HFA3841 */, + 0x3f0000 /* HFA3841 */, + 0x390000 /* apparently used in older cards */ + }; + + buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); + if (buf == NULL) + return NULL; + + /* Note: wlan card should be in initial state (just after init cmd) + * and no other operations should be performed concurrently. */ + + prism2_enable_aux_port(dev, 1); + + for (i = 0; i < NUM_PDA_ADDRS; i++) { + printk(KERN_DEBUG "%s: trying to read PDA from 0x%08x", + dev->name, pda_addr[i]); + res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); + if (res) + continue; + if (res == 0 && prism2_pda_ok(buf)) { + printk(": OK\n"); + found = 1; + break; + } else { + printk(": failed\n"); + } + } + + prism2_enable_aux_port(dev, 0); + + if (!found) { + kfree(buf); + buf = NULL; + } + + return buf; +} + + +static int prism2_download_volatile(local_info_t *local, + struct prism2_download_data *param) +{ + struct net_device *dev = local->dev; + int ret = 0, i; + u16 param0, param1; + + if (local->hw_downloading) { + printk(KERN_WARNING "%s: Already downloading - aborting new " + "request\n", dev->name); + return -1; + } + + local->hw_downloading = 1; + if (local->pri_only) { + hfa384x_disable_interrupts(dev); + } else { + prism2_hw_shutdown(dev, 0); + + if (prism2_hw_init(dev, 0)) { + printk(KERN_WARNING "%s: Could not initialize card for" + " download\n", dev->name); + ret = -1; + goto out; + } + } + + if (prism2_enable_aux_port(dev, 1)) { + printk(KERN_WARNING "%s: Could not enable AUX port\n", + dev->name); + ret = -1; + goto out; + } + + param0 = param->start_addr & 0xffff; + param1 = param->start_addr >> 16; + + HFA384X_OUTW(0, HFA384X_PARAM2_OFF); + HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); + if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | + (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), + param0)) { + printk(KERN_WARNING "%s: Download command execution failed\n", + dev->name); + ret = -1; + goto out; + } + + for (i = 0; i < param->num_areas; i++) { + printk(KERN_DEBUG "%s: Writing %d bytes at 0x%08x\n", + dev->name, param->data[i].len, param->data[i].addr); + if (hfa384x_to_aux(dev, param->data[i].addr, + param->data[i].len, param->data[i].data)) { + printk(KERN_WARNING "%s: RAM download at 0x%08x " + "(len=%d) failed\n", dev->name, + param->data[i].addr, param->data[i].len); + ret = -1; + goto out; + } + } + + HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); + HFA384X_OUTW(0, HFA384X_PARAM2_OFF); + if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | + (HFA384X_PROGMODE_DISABLE << 8), param0)) { + printk(KERN_WARNING "%s: Download command execution failed\n", + dev->name); + ret = -1; + goto out; + } + /* ProgMode disable causes the hardware to restart itself from the + * given starting address. Give hw some time and ACK command just in + * case restart did not happen. */ + mdelay(5); + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + + if (prism2_enable_aux_port(dev, 0)) { + printk(KERN_DEBUG "%s: Disabling AUX port failed\n", + dev->name); + /* continue anyway.. restart should have taken care of this */ + } + + mdelay(5); + local->hw_downloading = 0; + if (prism2_hw_config(dev, 2)) { + printk(KERN_WARNING "%s: Card configuration after RAM " + "download failed\n", dev->name); + ret = -1; + goto out2; + } + + goto out2; + out: + local->hw_downloading = 0; + out2: + return ret; +} + + +static int prism2_enable_genesis(local_info_t *local, int hcr) +{ + struct net_device *dev = local->dev; + u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; + u8 readbuf[4]; + + printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", + dev->name, hcr); + local->func->cor_sreset(local); + hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); + local->func->genesis_reset(local, hcr); + + /* Readback test */ + hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); + hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); + hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); + + if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { + printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", + hcr); + return 0; + } else { + printk(KERN_DEBUG "Readback test failed, HCR 0x%02x " + "write %02x %02x %02x %02x read %02x %02x %02x %02x\n", + hcr, initseq[0], initseq[1], initseq[2], initseq[3], + readbuf[0], readbuf[1], readbuf[2], readbuf[3]); + return 1; + } +} + + +static int prism2_download_genesis(local_info_t *local, + struct prism2_download_data *param) +{ + struct net_device *dev = local->dev; + int ram16 = 0, i; + + if (local->hw_downloading) { + printk(KERN_WARNING "%s: Already downloading - aborting new " + "request\n", dev->name); + return -1; + } + + if (!local->func->genesis_reset || !local->func->cor_sreset) { + printk(KERN_INFO "%s: Genesis mode downloading not supported " + "with this hwmodel\n", dev->name); + return -EOPNOTSUPP; + } + + local->hw_downloading = 1; + + if (prism2_enable_aux_port(dev, 1)) { + printk(KERN_DEBUG "%s: failed to enable AUX port\n", + dev->name); + return 1; + } + + /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ + if (prism2_enable_genesis(local, 0x1f) == 0) { + ram16 = 0; + printk(KERN_DEBUG "%s: Genesis mode OK using x8 SRAM\n", + dev->name); + } else if (prism2_enable_genesis(local, 0x0f) == 0) { + ram16 = 1; + printk(KERN_DEBUG "%s: Genesis mode OK using x16 SRAM\n", + dev->name); + } else { + printk(KERN_DEBUG "%s: Could not initiate genesis mode\n", + dev->name); + return 1; + } + + for (i = 0; i < param->num_areas; i++) { + printk(KERN_DEBUG "%s: Writing %d bytes at 0x%08x\n", + dev->name, param->data[i].len, param->data[i].addr); + if (hfa384x_to_aux(dev, param->data[i].addr, + param->data[i].len, param->data[i].data)) { + printk(KERN_WARNING "%s: RAM download at 0x%08x " + "(len=%d) failed\n", dev->name, + param->data[i].addr, param->data[i].len); + return 1; + } + } + + printk(KERN_DEBUG "Disable genesis mode\n"); + local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); + if (prism2_enable_aux_port(dev, 0)) { + printk(KERN_DEBUG "Failed to disable AUX port\n"); + } + + mdelay(5); + local->hw_downloading = 0; + + printk(KERN_DEBUG "Trying to initialize card\n"); + if (prism2_hw_init(dev, 1)) { + printk(KERN_DEBUG "Initialization failed\n"); + return 1; + } + + printk(KERN_DEBUG "Card initialized - running PRI only\n"); + if (prism2_hw_init(dev, 1) || prism2_hw_init2(dev, 1)) { + printk(KERN_DEBUG "Initialization failed\n"); + return 1; + } + + return 0; +} + + +#ifdef PRISM2_NON_VOLATILE_DOWNLOAD +/* Note! Non-volatile downloading functionality has not yet been tested + * thoroughly and it may corrupt flash image and effectively kill the card that + * is being updated. You have been warned. */ + +static inline int prism2_download_block(struct net_device *dev, + u32 addr, u8 *data, + u32 bufaddr, int rest_len) +{ + u16 param0, param1; + int block_len; + + block_len = rest_len < 4096 ? rest_len : 4096; + + param0 = addr & 0xffff; + param1 = addr >> 16; + + HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); + HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); + + if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | + (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), + param0)) { + printk(KERN_WARNING "%s: Flash download command execution " + "failed\n", dev->name); + return -1; + } + + if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { + printk(KERN_WARNING "%s: flash download at 0x%08x " + "(len=%d) failed\n", dev->name, addr, block_len); + return -1; + } + + HFA384X_OUTW(0, HFA384X_PARAM2_OFF); + HFA384X_OUTW(0, HFA384X_PARAM1_OFF); + if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | + (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), + 0)) { + printk(KERN_WARNING "%s: Flash write command execution " + "failed\n", dev->name); + return -1; + } + + return block_len; +} + + +static int prism2_download_nonvolatile(local_info_t *local, + struct prism2_download_data *dl) +{ + struct net_device *dev = local->dev; + int ret = 0, i; + struct { + u16 page; + u16 offset; + u16 len; + } dlbuffer; + u32 bufaddr; + + if (local->hw_downloading) { + printk(KERN_WARNING "%s: Already downloading - aborting new " + "request\n", dev->name); + return -1; + } + + local->hw_downloading = 1; + + ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, + &dlbuffer, 6, 0); + + if (ret < 0) { + printk(KERN_WARNING "%s: Could not read download buffer " + "parameters\n", dev->name); + goto out; + } + + dlbuffer.page = le16_to_cpu(dlbuffer.page); + dlbuffer.offset = le16_to_cpu(dlbuffer.offset); + dlbuffer.len = le16_to_cpu(dlbuffer.len); + + printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", + dlbuffer.len, dlbuffer.page, dlbuffer.offset); + + bufaddr = (dlbuffer.page << 7) + dlbuffer.offset; + + if (!local->pri_only) { + prism2_hw_shutdown(dev, 0); + + if (prism2_hw_init(dev, 0)) { + printk(KERN_WARNING "%s: Could not initialize card for" + " download\n", dev->name); + ret = -1; + goto out; + } + } + + hfa384x_disable_interrupts(dev); + + if (prism2_enable_aux_port(dev, 1)) { + printk(KERN_WARNING "%s: Could not enable AUX port\n", + dev->name); + ret = -1; + goto out; + } + + printk(KERN_DEBUG "%s: starting flash download\n", dev->name); + for (i = 0; i < dl->num_areas; i++) { + int rest_len = dl->data[i].len; + int data_off = 0; + + while (rest_len > 0) { + int block_len; + + block_len = prism2_download_block( + dev, dl->data[i].addr + data_off, + dl->data[i].data + data_off, bufaddr, + rest_len); + + if (block_len < 0) { + ret = -1; + goto out; + } + + rest_len -= block_len; + data_off += block_len; + } + } + + HFA384X_OUTW(0, HFA384X_PARAM1_OFF); + HFA384X_OUTW(0, HFA384X_PARAM2_OFF); + if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | + (HFA384X_PROGMODE_DISABLE << 8), 0)) { + printk(KERN_WARNING "%s: Download command execution failed\n", + dev->name); + ret = -1; + goto out; + } + + if (prism2_enable_aux_port(dev, 0)) { + printk(KERN_DEBUG "%s: Disabling AUX port failed\n", + dev->name); + /* continue anyway.. restart should have taken care of this */ + } + + mdelay(5); + + local->func->hw_reset(dev); + local->hw_downloading = 0; + if (prism2_hw_config(dev, 2)) { + printk(KERN_WARNING "%s: Card configuration after flash " + "download failed\n", dev->name); + ret = -1; + } else { + printk(KERN_INFO "%s: Card initialized successfully after " + "flash download\n", dev->name); + } + + out: + local->hw_downloading = 0; + return ret; +} +#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ + + +static void prism2_download_free_data(struct prism2_download_data *dl) +{ + int i; + + if (dl == NULL) + return; + + for (i = 0; i < dl->num_areas; i++) + kfree(dl->data[i].data); + kfree(dl); +} + + +static int prism2_download(local_info_t *local, + struct prism2_download_param *param) +{ + int ret = 0; + int i; + u32 total_len = 0; + struct prism2_download_data *dl = NULL; + + printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " + "num_areas=%d\n", + param->dl_cmd, param->start_addr, param->num_areas); + + if (param->num_areas > 100) { + ret = -EINVAL; + goto out; + } + + dl = kmalloc(sizeof(*dl) + param->num_areas * + sizeof(struct prism2_download_data_area), GFP_KERNEL); + if (dl == NULL) { + ret = -ENOMEM; + goto out; + } + memset(dl, 0, sizeof(*dl) + param->num_areas * + sizeof(struct prism2_download_data_area)); + dl->dl_cmd = param->dl_cmd; + dl->start_addr = param->start_addr; + dl->num_areas = param->num_areas; + for (i = 0; i < param->num_areas; i++) { + printk(KERN_DEBUG " area %d: addr=0x%08x len=%d ptr=0x%p\n", + i, param->data[i].addr, param->data[i].len, + param->data[i].ptr); + + dl->data[i].addr = param->data[i].addr; + dl->data[i].len = param->data[i].len; + + total_len += param->data[i].len; + if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || + total_len > PRISM2_MAX_DOWNLOAD_LEN) { + ret = -E2BIG; + goto out; + } + + dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); + if (dl->data[i].data == NULL) { + ret = -ENOMEM; + goto out; + } + + if (copy_from_user(dl->data[i].data, param->data[i].ptr, + param->data[i].len)) { + ret = -EFAULT; + goto out; + } + } + + switch (param->dl_cmd) { + case PRISM2_DOWNLOAD_VOLATILE: + case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: + ret = prism2_download_volatile(local, dl); + break; + case PRISM2_DOWNLOAD_VOLATILE_GENESIS: + case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: + ret = prism2_download_genesis(local, dl); + break; + case PRISM2_DOWNLOAD_NON_VOLATILE: +#ifdef PRISM2_NON_VOLATILE_DOWNLOAD + ret = prism2_download_nonvolatile(local, dl); +#else /* PRISM2_NON_VOLATILE_DOWNLOAD */ + printk(KERN_INFO "%s: non-volatile downloading not enabled\n", + local->dev->name); + ret = -EOPNOTSUPP; +#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ + break; + default: + printk(KERN_DEBUG "%s: unsupported download command %d\n", + local->dev->name, param->dl_cmd); + ret = -EINVAL; + break; + }; + + out: + if (ret == 0 && dl && + param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { + prism2_download_free_data(local->dl_pri); + local->dl_pri = dl; + } else if (ret == 0 && dl && + param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { + prism2_download_free_data(local->dl_sec); + local->dl_sec = dl; + } else + prism2_download_free_data(dl); + + return ret; +} diff -Nru a/drivers/net/wireless/hostap_hw.c b/drivers/net/wireless/hostap_hw.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_hw.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3686 @@ +/* + * Host AP (software wireless LAN access point) driver for + * Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + * + * FIX: + * - there is currently no way of associating TX packets to correct wds device + * when TX Exc/OK event occurs, so all tx_packets and some + * tx_errors/tx_dropped are added to the main netdevice; using sw_support + * field in txdesc might be used to fix this (using Alloc event to increment + * tx_packets would need some further info in txfid table) + * + * Buffer Access Path (BAP) usage: + * Prism2 cards have two separate BAPs for accessing the card memory. These + * should allow concurrent access to two different frames and the driver + * previously used BAP0 for sending data and BAP1 for receiving data. + * However, there seems to be number of issues with concurrent access and at + * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI + * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between + * host and card memories. BAP0 accesses are protected with local->baplock + * (spin_lock_bh) to prevent concurrent use. + */ + + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hostap_wext.h" +#include + + +#include "hostap_80211.h" +#include "hostap.h" +#include "hostap_ap.h" + + +/* #define final_version */ + +static int mtu = 1500; +MODULE_PARM(mtu, "i"); +MODULE_PARM_DESC(mtu, "Maximum transfer unit"); + +static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; +MODULE_PARM(channel, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(channel, "Initial channel"); + +static char *essid[MAX_PARM_DEVICES] = { "test" }; +MODULE_PARM(essid, PARM_MIN_MAX "s"); +MODULE_PARM_DESC(essid, "Host AP's ESSID"); + +static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; +MODULE_PARM(iw_mode, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(iw_mode, "Initial operation mode"); + +static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; +MODULE_PARM(beacon_int, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); + +static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; +MODULE_PARM(dtim_period, PARM_MIN_MAX "i"); +MODULE_PARM_DESC(dtim_period, "DTIM period"); + +static int delayed_enable /* = 0 */; +MODULE_PARM(delayed_enable, "i"); +MODULE_PARM_DESC(delayed_enable, "Delay MAC port enable until netdevice open"); + +static int disable_on_close /* = 0 */; +MODULE_PARM(disable_on_close, "i"); +MODULE_PARM_DESC(disable_on_close, "Disable MAC port on netdevice close"); + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) +static int bus_master_threshold_rx[MAX_PARM_DEVICES] = { 100, DEF_INTS }; +MODULE_PARM(bus_master_threshold_rx, "i"); +MODULE_PARM_DESC(bus_master_threshold_rx, "Packet length threshold for using " + "PCI bus master on RX"); + +static int bus_master_threshold_tx[MAX_PARM_DEVICES] = { 100, DEF_INTS }; +MODULE_PARM(bus_master_threshold_tx, "i"); +MODULE_PARM_DESC(bus_master_threshold_tx, "Packet length threshold for using " + "PCI bus master on TX"); +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + +static char *dev_template = "wlan%d"; +MODULE_PARM(dev_template, "s"); +MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " + "wlan%d)"); + + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + + +#ifdef final_version +#define EXTRA_EVENTS_WTERR 0 +#else +/* check WTERR events (Wait Time-out) in development versions */ +#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR +#endif + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) +#define EXTRA_EVENTS_BUS_MASTER (HFA384X_EV_PCI_M0 | HFA384X_EV_PCI_M1) +#else +#define EXTRA_EVENTS_BUS_MASTER 0 +#endif + +/* Events that will be using BAP0 */ +#define HFA384X_BAP0_EVENTS \ + (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) + +/* event mask, i.e., events that will result in an interrupt */ +#define HFA384X_EVENT_MASK \ + (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ + HFA384X_EV_CMD | HFA384X_EV_TICK | \ + EXTRA_EVENTS_WTERR | EXTRA_EVENTS_BUS_MASTER) + +/* Default TX control flags: use 802.11 headers and request interrupt for + * failed transmits. Frames that request ACK callback, will add + * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. + */ +#define HFA384X_TX_CTRL_FLAGS \ + (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) + + +/* ca. 1 usec */ +#define HFA384X_CMD_BUSY_TIMEOUT 5000 +#define HFA384X_BAP_BUSY_TIMEOUT 50000 + +/* ca. 10 usec */ +#define HFA384X_CMD_COMPL_TIMEOUT 20000 +#define HFA384X_DL_COMPL_TIMEOUT 1000000 + +/* Wait times for initialization; yield to other processes to avoid busy + * waiting for long time. */ +#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ +#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ + + +static void prism2_hw_reset(struct net_device *dev); +static void prism2_check_sta_fw_version(local_info_t *local); + +#ifdef PRISM2_DOWNLOAD_SUPPORT +/* hostap_download.c */ +static u8 * prism2_read_pda(struct net_device *dev); +static int prism2_download(local_info_t *local, + struct prism2_download_param *param); +static void prism2_download_free_data(struct prism2_download_data *dl); +static int prism2_download_volatile(local_info_t *local, + struct prism2_download_data *param); +static int prism2_download_genesis(local_info_t *local, + struct prism2_download_data *param); +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + + + + +#ifndef final_version +/* magic value written to SWSUPPORT0 reg. for detecting whether card is still + * present */ +#define HFA384X_MAGIC 0x8A32 +#endif + + +static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) +{ + return HFA384X_INW(reg); +} + + +static void hfa384x_read_regs(struct net_device *dev, + struct hfa384x_regs *regs) +{ + regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); + regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); + regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); + regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); + regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); +} + + +/* local->cmdlock must be locked when calling this helper function */ +static inline void __hostap_cmd_queue_free(local_info_t *local, + struct hostap_cmd_queue *entry, + int del_req) +{ + if (del_req) { + entry->del_req = 1; + if (!list_empty(&entry->list)) { + list_del_init(&entry->list); + local->cmd_queue_len--; + } + } + + if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) + kfree(entry); +} + +static inline void hostap_cmd_queue_free(local_info_t *local, + struct hostap_cmd_queue *entry, + int del_req) +{ + unsigned long flags; + + spin_lock_irqsave(&local->cmdlock, flags); + __hostap_cmd_queue_free(local, entry, del_req); + spin_unlock_irqrestore(&local->cmdlock, flags); +} + + +static inline int hfa384x_cmd_issue(struct net_device *dev, + struct hostap_cmd_queue *entry) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int tries; + u16 reg; + unsigned long flags; + + if (entry->issued) { + printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", + dev->name, entry); + } + + /* wait until busy bit is clear; this should always be clear since the + * commands are serialized */ + tries = HFA384X_CMD_BUSY_TIMEOUT; + while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { + tries--; + udelay(1); + } +#ifndef final_version + if (tries != HFA384X_CMD_BUSY_TIMEOUT) { + prism2_io_debug_error(dev, 1); + printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " + "for %d usec\n", dev->name, + HFA384X_CMD_BUSY_TIMEOUT - tries); + } +#endif + if (tries == 0) { + reg = HFA384X_INW(HFA384X_CMD_OFF); + prism2_io_debug_error(dev, 2); + printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " + "reg=0x%04x\n", dev->name, reg); + return -ETIMEDOUT; + } + + /* write command */ + spin_lock_irqsave(&local->cmdlock, flags); + HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); + HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); + HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); + entry->issued = 1; + spin_unlock_irqrestore(&local->cmdlock, flags); + + return 0; +} + + +/* Issue given command (possibly after waiting in command queue) and sleep + * until the command is completed (or timed out). This can be called only + * from user context. */ +static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, + u16 *param1, u16 *resp0) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int err, res, issue, issued = 0; + unsigned long flags; + struct hostap_cmd_queue *entry; + DECLARE_WAITQUEUE(wait, current); + + if (in_interrupt()) { + printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt " + "context\n", dev->name); + return -1; + } + + if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { + printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", + dev->name); + return -1; + } + + if (signal_pending(current)) + return -EINTR; + + entry = (struct hostap_cmd_queue *) + kmalloc(sizeof(*entry), GFP_ATOMIC); + if (entry == NULL) { + printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n", + dev->name); + return -ENOMEM; + } + memset(entry, 0, sizeof(*entry)); + atomic_set(&entry->usecnt, 1); + entry->type = CMD_SLEEP; + entry->cmd = cmd; + entry->param0 = param0; + if (param1) + entry->param1 = *param1; + init_waitqueue_head(&entry->compl); + + /* prepare to wait for command completion event, but do not sleep yet + */ + add_wait_queue(&entry->compl, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&local->cmdlock, flags); + issue = list_empty(&local->cmd_queue); + if (issue) + entry->issuing = 1; + list_add_tail(&entry->list, &local->cmd_queue); + local->cmd_queue_len++; + spin_unlock_irqrestore(&local->cmdlock, flags); + + err = 0; + if (!issue) + goto wait_completion; + + if (signal_pending(current)) + err = -EINTR; + + if (!err) { + if (hfa384x_cmd_issue(dev, entry)) + err = -ETIMEDOUT; + else + issued = 1; + } + + wait_completion: + if (!err && entry->type != CMD_COMPLETED) { + /* sleep until command is completed or timed out */ + res = schedule_timeout(2 * HZ); + } else + res = -1; + + if (!err && signal_pending(current)) + err = -EINTR; + + if (err && issued) { + /* the command was issued, so a CmdCompl event should occur + * soon; however, there's a pending signal and + * schedule_timeout() would be interrupted; wait a short period + * of time to avoid removing entry from the list before + * CmdCompl event */ + udelay(300); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&entry->compl, &wait); + + /* If entry->list is still in the list, it must be removed + * first and in this case prism2_cmd_ev() does not yet have + * local reference to it, and the data can be kfree()'d + * here. If the command completion event is still generated, + * it will be assigned to next (possibly) pending command, but + * the driver will reset the card anyway due to timeout + * + * If the entry is not in the list prism2_cmd_ev() has a local + * reference to it, but keeps cmdlock as long as the data is + * needed, so the data can be kfree()'d here. */ + + /* FIX: if the entry->list is in the list, it has not been completed + * yet, so removing it here is somewhat wrong.. this could cause + * references to freed memory and next list_del() causing NULL pointer + * dereference.. it would probably be better to leave the entry in the + * list and the list should be emptied during hw reset */ + + spin_lock_irqsave(&local->cmdlock, flags); + if (!list_empty(&entry->list)) { + printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " + "(entry=%p, type=%d, res=%d)\n", dev->name, entry, + entry->type, res); + list_del_init(&entry->list); + local->cmd_queue_len--; + } + spin_unlock_irqrestore(&local->cmdlock, flags); + + if (err) { + printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", + dev->name, err); + res = err; + goto done; + } + + if (entry->type != CMD_COMPLETED) { + u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); + printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " + "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " + "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, + res, entry, entry->type, entry->cmd, entry->param0, reg, + HFA384X_INW(HFA384X_INTEN_OFF)); + if (reg & HFA384X_EV_CMD) { + /* Command completion event is pending, but the + * interrupt was not delivered - probably an issue + * with pcmcia-cs configuration. */ + printk(KERN_WARNING "%s: interrupt delivery does not " + "seem to work\n", dev->name); + } + prism2_io_debug_error(dev, 3); + res = -ETIMEDOUT; + goto done; + } + + if (resp0 != NULL) + *resp0 = entry->resp0; +#ifndef final_version + if (entry->res) { + printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " + "resp0=0x%04x\n", + dev->name, cmd, entry->res, entry->resp0); + } +#endif /* final_version */ + + res = entry->res; + done: + hostap_cmd_queue_free(local, entry, 1); + return res; +} + + +/* Issue given command (possibly after waiting in command queue) and use + * callback function to indicate command completion. This can be called both + * from user and interrupt context. */ +static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, + void (*callback)(struct net_device *dev, + void *context, u16 resp0, + u16 status), + void *context) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int issue, ret; + unsigned long flags; + struct hostap_cmd_queue *entry; + + if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { + printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", + dev->name); + return -1; + } + + entry = (struct hostap_cmd_queue *) + kmalloc(sizeof(*entry), GFP_ATOMIC); + if (entry == NULL) { + printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc " + "failed\n", dev->name); + return -ENOMEM; + } + memset(entry, 0, sizeof(*entry)); + atomic_set(&entry->usecnt, 1); + entry->type = CMD_CALLBACK; + entry->cmd = cmd; + entry->param0 = param0; + entry->callback = callback; + entry->context = context; + + spin_lock_irqsave(&local->cmdlock, flags); + issue = list_empty(&local->cmd_queue); + if (issue) + entry->issuing = 1; + list_add_tail(&entry->list, &local->cmd_queue); + local->cmd_queue_len++; + spin_unlock_irqrestore(&local->cmdlock, flags); + + if (issue && hfa384x_cmd_issue(dev, entry)) + ret = -ETIMEDOUT; + else + ret = 0; + + hostap_cmd_queue_free(local, entry, ret); + + return ret; +} + + +static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) +{ + int res, tries; + u16 reg; + + /* wait until busy bit is clear; this should always be clear since the + * commands are serialized */ + tries = HFA384X_CMD_BUSY_TIMEOUT; + while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { + tries--; + udelay(1); + } + if (tries == 0) { + prism2_io_debug_error(dev, 4); + printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout - " + "reg=0x%04x\n", dev->name, + HFA384X_INW(HFA384X_CMD_OFF)); + return -ETIMEDOUT; + } + + /* write command */ + HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); + HFA384X_OUTW(cmd, HFA384X_CMD_OFF); + + /* wait for command completion */ + if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) + tries = HFA384X_DL_COMPL_TIMEOUT; + else + tries = HFA384X_CMD_COMPL_TIMEOUT; + + while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && + tries > 0) { + tries--; + udelay(10); + } + if (tries == 0) { + reg = HFA384X_INW(HFA384X_EVSTAT_OFF); + prism2_io_debug_error(dev, 5); + printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " + "reg=0x%04x\n", dev->name, reg); + return -ETIMEDOUT; + } + + res = (HFA384X_INW(HFA384X_STATUS_OFF) & + (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | + BIT(8))) >> 8; +#ifndef final_version + if (res) { + printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", + dev->name, cmd, res); + } +#endif + + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + + return res; +} + + +static int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0) +{ + int tries; + u16 reg; + + /* wait until busy bit is clear */ + tries = HFA384X_CMD_BUSY_TIMEOUT; + while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { + tries--; + udelay(1); + } + if (tries == 0) { + reg = HFA384X_INW(HFA384X_CMD_OFF); + prism2_io_debug_error(dev, 6); + printk("%s: hfa384x_cmd - timeout - reg=0x%04x\n", dev->name, + reg); + return -ETIMEDOUT; + } + + /* write command */ + HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); + HFA384X_OUTW(cmd, HFA384X_CMD_OFF); + + return 0; +} + + +static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off) +{ + int tries = HFA384X_BAP_BUSY_TIMEOUT; + int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; + + while (res && tries > 0) { + tries--; + udelay(1); + res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; + } + return res; +} + + +/* Offset must be even */ +static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, + int offset) +{ + u16 o_off, s_off; + int ret = 0; + + if (offset % 2 || bap > 1) + return -EINVAL; + + if (bap == BAP1) { + o_off = HFA384X_OFFSET1_OFF; + s_off = HFA384X_SELECT1_OFF; + } else { + o_off = HFA384X_OFFSET0_OFF; + s_off = HFA384X_SELECT0_OFF; + } + + if (hfa384x_wait_offset(dev, o_off)) { + prism2_io_debug_error(dev, 7); + printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", + dev->name); + ret = -ETIMEDOUT; + goto out; + } + + HFA384X_OUTW(id, s_off); + HFA384X_OUTW(offset, o_off); + + if (hfa384x_wait_offset(dev, o_off)) { + prism2_io_debug_error(dev, 8); + printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", + dev->name); + ret = -ETIMEDOUT; + goto out; + } +#ifndef final_version + if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { + prism2_io_debug_error(dev, 9); + printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " + "(%d,0x04%x,%d); reg=0x%04x\n", + dev->name, bap, id, offset, HFA384X_INW(o_off)); + ret = -EINVAL; + } +#endif + + out: + return ret; +} + + +static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, + int exact_len) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res, rlen = 0; + struct hfa384x_rid_hdr rec; + + res = down_interruptible(&local->rid_bap_sem); + if (res) + return res; + + res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); + if (res) { + printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " + "(res=%d, rid=%04x, len=%d)\n", + dev->name, res, rid, len); + up(&local->rid_bap_sem); + return res; + } + + spin_lock_bh(&local->baplock); + + res = hfa384x_setup_bap(dev, BAP0, rid, 0); + if (!res) + res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); + + if (le16_to_cpu(rec.len) == 0) { + /* RID not available */ + res = -ENODATA; + } + + rlen = (le16_to_cpu(rec.len) - 1) * 2; + if (!res && exact_len && rlen != len) { + printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " + "rid=0x%04x, len=%d (expected %d)\n", + dev->name, rid, rlen, len); + res = -ENODATA; + } + + if (!res) + res = hfa384x_from_bap(dev, BAP0, buf, len); + + spin_unlock_bh(&local->baplock); + up(&local->rid_bap_sem); + + if (res) { + if (res != -ENODATA) + printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " + "len=%d) - failed - res=%d\n", dev->name, rid, + len, res); + if (res == -ETIMEDOUT) + prism2_hw_reset(dev); + return res; + } + + return rlen; +} + + +static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_rid_hdr rec; + int res; + + rec.rid = cpu_to_le16(rid); + /* RID len in words and +1 for rec.rid */ + rec.len = cpu_to_le16(len / 2 + len % 2 + 1); + + res = down_interruptible(&local->rid_bap_sem); + if (res) + return res; + + spin_lock_bh(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, rid, 0); + if (!res) + res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); + if (!res) + res = hfa384x_to_bap(dev, BAP0, buf, len); + spin_unlock_bh(&local->baplock); + + if (res) { + printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " + "failed - res=%d\n", dev->name, rid, len, res); + up(&local->rid_bap_sem); + return res; + } + + res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); + up(&local->rid_bap_sem); + if (res) { + printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " + "failed (res=%d, rid=%04x, len=%d)\n", + dev->name, res, rid, len); + return res; + } + + if (res == -ETIMEDOUT) + prism2_hw_reset(dev); + + return res; +} + + +static void hfa384x_disable_interrupts(struct net_device *dev) +{ + /* disable interrupts and clear event status */ + HFA384X_OUTW(0, HFA384X_INTEN_OFF); + HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); +} + + +static void hfa384x_enable_interrupts(struct net_device *dev) +{ + /* ack pending events and enable interrupts from selected events */ + HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); + HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); +} + + +static void hfa384x_events_no_bap0(struct net_device *dev) +{ + HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, + HFA384X_INTEN_OFF); +} + + +static void hfa384x_events_all(struct net_device *dev) +{ + HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); +} + + +static void hfa384x_events_only_cmd(struct net_device *dev) +{ + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); +} + + +static u16 hfa384x_allocate_fid(struct net_device *dev, int len) +{ + u16 fid; + unsigned long delay; + + /* FIX: this could be replace with hfa384x_cmd() if the Alloc event + * below would be handled like CmdCompl event (sleep here, wake up from + * interrupt handler */ + if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { + printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", + dev->name, len); + return 0xffff; + } + + delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; + while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && + time_before(jiffies, delay)) + yield(); + if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { + printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); + return 0xffff; + } + + fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); + HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); + + return fid; +} + + +static int prism2_reset_port(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res; + + if (!local->dev_enabled) + return 0; + + res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, + NULL, NULL); + if (res) + printk(KERN_DEBUG "%s: reset port failed to disable port\n", + dev->name); + else { + res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, + NULL, NULL); + if (res) + printk(KERN_DEBUG "%s: reset port failed to enable " + "port\n", dev->name); + } + + return res; +} + + +static int prism2_get_version_info(struct net_device *dev, u16 rid, + const char *txt) +{ + struct hfa384x_comp_ident comp; + + if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { + printk(KERN_DEBUG "Could not get RID for component %s\n", txt); + return -1; + } + + printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, + __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), + __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); + return 0; +} + + +static int prism2_setup_rids(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 tmp; + int ret = 0; + + hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); + + if (!local->fw_ap) { + tmp = hostap_get_porttype(local); + ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); + if (ret) { + printk("%s: Port type setting to %d failed\n", + dev->name, tmp); + goto fail; + } + } + + /* Setting SSID to empty string seems to kill the card in Host AP mode + */ + if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { + ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, + local->essid); + if (ret) { + printk("%s: AP own SSID setting failed\n", dev->name); + goto fail; + } + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, + PRISM2_DATA_MAXLEN); + if (ret) { + printk("%s: MAC data length setting to %d failed\n", + dev->name, PRISM2_DATA_MAXLEN); + goto fail; + } + + if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { + printk("%s: Channel list read failed\n", dev->name); + ret = -EINVAL; + goto fail; + } + local->channel_mask = __le16_to_cpu(tmp); + + if (local->channel < 1 || local->channel > 14 || + !(local->channel_mask & (1 << (local->channel - 1)))) { + printk(KERN_WARNING "%s: Channel setting out of range " + "(%d)!\n", dev->name, local->channel); + ret = -EBUSY; + goto fail; + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); + if (ret) { + printk("%s: Channel setting to %d failed\n", + dev->name, local->channel); + goto fail; + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, + local->beacon_int); + if (ret) { + printk("%s: Beacon interval setting to %d failed\n", + dev->name, local->beacon_int); + /* this may fail with Symbol/Lucent firmware */ + if (ret == -ETIMEDOUT) + goto fail; + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, + local->dtim_period); + if (ret) { + printk("%s: DTIM period setting to %d failed\n", + dev->name, local->dtim_period); + /* this may fail with Symbol/Lucent firmware */ + if (ret == -ETIMEDOUT) + goto fail; + } + + ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, + local->is_promisc); + if (ret) + printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", + dev->name, local->is_promisc); + + if (!local->fw_ap) { + ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, + local->essid); + if (ret) { + printk("%s: Desired SSID setting failed\n", dev->name); + goto fail; + } + } + + /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and + * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic + * rates */ + if (local->tx_rate_control == 0) { + local->tx_rate_control = + HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS | + HFA384X_RATES_5MBPS | + HFA384X_RATES_11MBPS; + } + if (local->basic_rates == 0) + local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; + + if (!local->fw_ap) { + ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, + local->tx_rate_control); + if (ret) { + printk("%s: TXRateControl setting to %d failed\n", + dev->name, local->tx_rate_control); + goto fail; + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, + local->tx_rate_control); + if (ret) { + printk("%s: cnfSupportedRates setting to %d failed\n", + dev->name, local->tx_rate_control); + } + + ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, + local->basic_rates); + if (ret) { + printk("%s: cnfBasicRates setting to %d failed\n", + dev->name, local->basic_rates); + } + + ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); + if (ret) { + printk("%s: Create IBSS setting to 1 failed\n", + dev->name); + } + } + + if (local->name_set) + (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, + local->name); + + if (hostap_set_encryption(local)) { + printk(KERN_INFO "%s: could not configure encryption\n", + dev->name); + } + + (void) hostap_set_antsel(local); + + if (hostap_set_roaming(local)) { + printk(KERN_INFO "%s: could not set host roaming\n", + dev->name); + } + + if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && + hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) + printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", + dev->name, local->enh_sec); + + /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently + * not working correctly (last seven counters report bogus values). + * This has been fixed in 0.8.2, so enable 32-bit tallies only + * beginning with that firmware version. Another bug fix for 32-bit + * tallies in 1.4.0; should 16-bit tallies be used for some other + * versions, too? */ + if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { + if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { + printk(KERN_INFO "%s: cnfThirty2Tally setting " + "failed\n", dev->name); + local->tallies32 = 0; + } else + local->tallies32 = 1; + } else + local->tallies32 = 0; + + hostap_set_auth_algs(local); + + if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, + local->fragm_threshold)) { + printk(KERN_INFO "%s: setting FragmentationThreshold to %d " + "failed\n", dev->name, local->fragm_threshold); + } + + if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, + local->rts_threshold)) { + printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", + dev->name, local->rts_threshold); + } + + fail: + return ret; +} + + +static void prism2_clear_cmd_queue(local_info_t *local) +{ + struct list_head *ptr, *n; + unsigned long flags; + struct hostap_cmd_queue *entry; + + spin_lock_irqsave(&local->cmdlock, flags); + for (ptr = local->cmd_queue.next, n = ptr->next; + ptr != &local->cmd_queue; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct hostap_cmd_queue, list); + atomic_inc(&entry->usecnt); + printk(KERN_DEBUG "%s: removed pending cmd_queue entry " + "(type=%d, cmd=0x%04x, param0=0x%04x)\n", + local->dev->name, entry->type, entry->cmd, + entry->param0); + __hostap_cmd_queue_free(local, entry, 1); + } + if (local->cmd_queue_len) { + printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " + "flush\n", local->dev->name, local->cmd_queue_len); + local->cmd_queue_len = 0; + } + spin_unlock_irqrestore(&local->cmdlock, flags); +} + + +static int prism2_hw_init(struct net_device *dev, int initial) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret, first = 1; + unsigned long start, delay; + + PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); + + clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); + + init: + /* initialize HFA 384x */ + ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); + if (ret) { + printk("%s: first command failed - is the card compatible?\n", + dev_info); + return 1; + } + + if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { + /* EvStat has Cmd bit set in some cases, so retry once if no + * wait was needed */ + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + printk(KERN_DEBUG "%s: init command completed too quickly - " + "retrying\n", dev->name); + first = 0; + goto init; + } + + start = jiffies; + delay = jiffies + HFA384X_INIT_TIMEOUT; + while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && + time_before(jiffies, delay)) + yield(); + if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { + printk("%s: card initialization timed out\n", dev_info); + return 1; + } + printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", + (jiffies - start) * 1000 / HZ); + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + return 0; +} + + +static int prism2_hw_init2(struct net_device *dev, int initial) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int i; + +#ifdef PRISM2_DOWNLOAD_SUPPORT + local->pda = prism2_read_pda(dev); +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + + hfa384x_disable_interrupts(dev); + +#ifndef final_version + HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); + if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { + printk("SWSUPPORT0 write/read failed: %04X != %04X\n", + HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); + goto failed; + } +#endif + + if (initial || local->pri_only) { + hfa384x_events_only_cmd(dev); + /* get card version information */ + if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || + prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { + hfa384x_disable_interrupts(dev); + goto failed; + } + + if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { + printk(KERN_DEBUG "%s: Failed to read STA f/w version " + "- only Primary f/w present\n", dev->name); + local->pri_only = 1; + return 0; + } + local->pri_only = 0; + hfa384x_disable_interrupts(dev); + } + + /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and + * enable interrupts before this. This would also require some sort of + * sleeping AllocEv waiting */ + + /* allocate TX FIDs */ + local->txfid_len = PRISM2_TXFID_LEN; + for (i = 0; i < PRISM2_TXFID_COUNT; i++) { + local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); + if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { + local->txfid[i] = hfa384x_allocate_fid(dev, 1600); + if (local->txfid[i] != 0xffff) { + printk(KERN_DEBUG "%s: Using shorter TX FID " + "(1600 bytes)\n", dev->name); + local->txfid_len = 1600; + } + } + if (local->txfid[i] == 0xffff) + goto failed; + local->intransmitfid[i] = PRISM2_TXFID_EMPTY; + } + + hfa384x_events_only_cmd(dev); + + if (initial) { + prism2_check_sta_fw_version(local); + + if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, + &dev->dev_addr, 6, 1) < 0) { + printk("%s: could not get own MAC address\n", + dev->name); + } + if (local->apdev) + memcpy(local->apdev->dev_addr, dev->dev_addr, + ETH_ALEN); + if (local->stadev) + memcpy(local->stadev->dev_addr, dev->dev_addr, + ETH_ALEN); + } else if (local->fw_ap) + prism2_check_sta_fw_version(local); + + prism2_setup_rids(dev); + + /* MAC is now configured, but port 0 is not yet enabled */ + return 0; + + failed: + printk(KERN_WARNING "%s: Initialization failed\n", dev_info); + return 1; +} + + +static int prism2_hw_enable(struct net_device *dev, int initial) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int was_resetting = local->hw_resetting; + + if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { + printk("%s: MAC port 0 enabling failed\n", dev->name); + return 1; + } + + local->hw_ready = 1; + local->hw_reset_tries = 0; + local->hw_resetting = 0; + hfa384x_enable_interrupts(dev); + + /* at least D-Link DWL-650 seems to require additional port reset + * before it starts acting as an AP, so reset port automatically + * here just in case */ + if (initial && prism2_reset_port(dev)) { + printk("%s: MAC port 0 reseting failed\n", dev->name); + return 1; + } + + if (was_resetting && netif_queue_stopped(dev)) { + /* If hw_reset() was called during pending transmit, netif + * queue was stopped. Wake it up now since the wlan card has + * been resetted. */ + hostap_netif_wake_queues(dev); + } + + return 0; +} + + +static int prism2_hw_config(struct net_device *dev, int initial) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + if (local->hw_downloading) + return 1; + + if (prism2_hw_init(dev, initial) || prism2_hw_init2(dev, initial)) + return 1; + + if (!local->pri_only && (!initial || !delayed_enable)) { + if (!local->dev_enabled) + prism2_callback(local, PRISM2_CALLBACK_ENABLE); + local->dev_enabled = 1; + return prism2_hw_enable(dev, initial); + } + + return 0; +} + + +static void prism2_hw_shutdown(struct net_device *dev, int no_disable) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + /* Allow only command completion events during disable */ + hfa384x_events_only_cmd(dev); + + local->hw_ready = 0; + if (local->dev_enabled) + prism2_callback(local, PRISM2_CALLBACK_DISABLE); + local->dev_enabled = 0; + + if (local->func->card_present && !local->func->card_present(local)) { + printk(KERN_DEBUG "%s: card already removed or not configured " + "during shutdown\n", dev->name); + return; + } + + if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && + hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) + printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); + + hfa384x_disable_interrupts(dev); + + if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) + hfa384x_events_only_cmd(dev); + else + prism2_clear_cmd_queue(local); +} + + +static void prism2_hw_reset(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + +#if 0 + static long last_reset = 0; + + /* do not reset card more than once per second to avoid ending up in a + * busy loop reseting the card */ + if (time_before_eq(jiffies, last_reset + HZ)) + return; + last_reset = jiffies; +#endif + + if (in_interrupt()) { + printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called " + "in interrupt context\n", dev->name); + return; + } + + if (local->hw_downloading) + return; + + if (local->hw_resetting) { + printk(KERN_WARNING "%s: %s: already resetting card - " + "ignoring reset request\n", dev_info, dev->name); + return; + } + + local->hw_reset_tries++; + if (local->hw_reset_tries > 10) { + printk(KERN_WARNING "%s: too many reset tries, skipping\n", + dev->name); + return; + } + + printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); + hfa384x_disable_interrupts(dev); + local->hw_resetting = 1; + if (local->func->cor_sreset) { + /* Host system seems to hang in some cases with high traffic + * load or shared interrupts during COR sreset. Disable shared + * interrupts during reset to avoid these crashes. COS sreset + * takes quite a long time, so it is unfortunate that this + * seems to be needed. Anyway, I do not know of any better way + * of avoiding the crash. */ + disable_irq(dev->irq); + local->func->cor_sreset(local); + enable_irq(dev->irq); + } + prism2_hw_shutdown(dev, 1); + prism2_hw_config(dev, 0); + local->hw_resetting = 0; + +#ifdef PRISM2_DOWNLOAD_SUPPORT + if (local->dl_pri) { + printk(KERN_DEBUG "%s: persistent download of primary " + "firmware\n", dev->name); + if (prism2_download_genesis(local, local->dl_pri) < 0) + printk(KERN_WARNING "%s: download (PRI) failed\n", + dev->name); + } + + if (local->dl_sec) { + printk(KERN_DEBUG "%s: persistent download of secondary " + "firmware\n", dev->name); + if (prism2_download_volatile(local, local->dl_sec) < 0) + printk(KERN_WARNING "%s: download (SEC) failed\n", + dev->name); + } +#endif /* PRISM2_DOWNLOAD_SUPPORT */ +} + + +static void prism2_schedule_reset(local_info_t *local) +{ + PRISM2_SCHEDULE_TASK(&local->reset_queue); +} + + +/* Called only as scheduled task after noticing card timeout in interrupt + * context */ +static void handle_reset_queue(void *data) +{ + local_info_t *local = (local_info_t *) data; + + printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); + prism2_hw_reset(local->dev); + + if (netif_queue_stopped(local->dev)) { + int i; + + for (i = 0; i < PRISM2_TXFID_COUNT; i++) + if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { + PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " + "wake up queue\n"); + hostap_netif_wake_queues(local->dev); + break; + } + } + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} + + +/* TODO: share one netif queue for all interfaces and get rid of this + * function.. */ +/* update trans_start for all used devices */ +static void prism2_netif_update_trans_start(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct list_head *ptr; + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + iface->dev->trans_start = jiffies; + } + read_unlock_bh(&local->iface_lock); +} + + +static int prism2_get_txfid_idx(local_info_t *local) +{ + int idx, end; + unsigned long flags; + + spin_lock_irqsave(&local->txfidlock, flags); + end = idx = local->next_txfid; + do { + if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { + local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; + spin_unlock_irqrestore(&local->txfidlock, flags); + return idx; + } + idx++; + if (idx >= PRISM2_TXFID_COUNT) + idx = 0; + } while (idx != end); + spin_unlock_irqrestore(&local->txfidlock, flags); + + PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " + "packet dropped\n"); + local->stats.tx_dropped++; + + return -1; +} + + +/* Called only from hardware IRQ */ +static void prism2_transmit_cb(struct net_device *dev, void *context, + u16 resp0, u16 res) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int idx = (int) context; + + if (res) { + printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", + dev->name, res); + return; + } + + if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { + printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " + "idx=%d\n", dev->name, idx); + return; + } + + if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { + printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " + "with no pending transmit\n", dev->name); + } + + if (netif_queue_stopped(dev)) { + /* ready for next TX, so wake up queue that was stopped in + * prism2_transmit() */ + hostap_netif_wake_queues(dev); + } + + spin_lock(&local->txfidlock); + + /* With reclaim, Resp0 contains new txfid for transmit; the old txfid + * will be automatically allocated for the next TX frame */ + local->intransmitfid[idx] = resp0; + + PDEBUG(DEBUG_FID, "%s: prism2_cmd_ev: txfid[%d]=0x%04x, resp0=0x%04x, " + "transmit_txfid=0x%04x\n", dev->name, idx, local->txfid[idx], + resp0, local->intransmitfid[local->next_txfid]); + + idx++; + if (idx >= PRISM2_TXFID_COUNT) + idx = 0; + local->next_txfid = idx; + + /* check if all TX buffers are occupied */ + do { + if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { + spin_unlock(&local->txfidlock); + return; + } + idx++; + if (idx >= PRISM2_TXFID_COUNT) + idx = 0; + } while (idx != local->next_txfid); + spin_unlock(&local->txfidlock); + + /* no empty TX buffers, stop queue */ + hostap_netif_stop_queues(dev); +} + + +/* Called only from software IRQ if PCI bus master is not used (with bus master + * this can be called both from software and hardware IRQ) */ +static int prism2_transmit(struct net_device *dev, int idx) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res; + + /* The driver tries to stop netif queue so that there would not be + * more than one attempt to transmit frames going on; check that this + * is really the case */ + + if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { + printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " + "when previous TX was pending\n", dev->name); + return -1; + } + + /* stop the queue for the time that transmit is pending */ + hostap_netif_stop_queues(dev); + + /* transmit packet */ + res = hfa384x_cmd_callback( + dev, + HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, + local->txfid[idx], + prism2_transmit_cb, (void *) idx); + + if (res) { + struct net_device_stats *stats; + printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " + "failed (res=%d)\n", dev->name, res); + stats = hostap_get_stats(dev); + stats->tx_dropped++; + hostap_netif_wake_queues(dev); + return -1; + } + prism2_netif_update_trans_start(dev); + + /* Since we did not wait for command completion, the card continues + * to process on the background and we will finish handling when + * command completion event is handled (prism2_cmd_ev() function) */ + + return 0; +} + + +/* Called only from hardware IRQ */ +static void prism2_cmd_ev(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hostap_cmd_queue *entry = NULL; + + spin_lock(&local->cmdlock); + if (!list_empty(&local->cmd_queue)) { + entry = list_entry(local->cmd_queue.next, + struct hostap_cmd_queue, list); + atomic_inc(&entry->usecnt); + list_del_init(&entry->list); + local->cmd_queue_len--; + + if (!entry->issued) { + printk(KERN_DEBUG "%s: Command completion event, but " + "cmd not issued\n", dev->name); + __hostap_cmd_queue_free(local, entry, 1); + entry = NULL; + } + } + spin_unlock(&local->cmdlock); + + if (!entry) { + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + printk(KERN_DEBUG "%s: Command completion event, but no " + "pending commands\n", dev->name); + return; + } + + entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); + entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & + (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | + BIT(9) | BIT(8))) >> 8; + HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); + + /* TODO: rest of the CmdEv handling could be moved to tasklet */ + if (entry->type == CMD_SLEEP) { + entry->type = CMD_COMPLETED; + wake_up_interruptible(&entry->compl); + } else if (entry->type == CMD_CALLBACK) { + if (entry->callback) + entry->callback(dev, entry->context, entry->resp0, + entry->res); + } else { + printk(KERN_DEBUG "%s: Invalid command completion type %d\n", + dev->name, entry->type); + } + hostap_cmd_queue_free(local, entry, 1); + + /* issue next command, if pending */ + entry = NULL; + spin_lock(&local->cmdlock); + if (!list_empty(&local->cmd_queue)) { + entry = list_entry(local->cmd_queue.next, + struct hostap_cmd_queue, list); + if (entry->issuing) { + /* hfa384x_cmd() has already started issuing this + * command, so do not start here */ + entry = NULL; + } + if (entry) + atomic_inc(&entry->usecnt); + } + spin_unlock(&local->cmdlock); + + if (entry) { + /* issue next command; if command issuing fails, remove the + * entry from cmd_queue */ + int res = hfa384x_cmd_issue(dev, entry); + spin_lock(&local->cmdlock); + __hostap_cmd_queue_free(local, entry, res); + spin_unlock(&local->cmdlock); + } +} + + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) +static void prism2_tx_cb(struct net_device *dev, void *context, + u16 resp0, u16 res) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long addr; + int buf_len = (int) context; + + if (res) { + printk(KERN_DEBUG "%s: prism2_tx_cb - res=0x%02x\n", + dev->name, res); + return; + } + + addr = virt_to_phys(local->bus_m0_buf); + HFA384X_OUTW((addr & 0xffff0000) >> 16, HFA384X_PCI_M0_ADDRH_OFF); + HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF); + HFA384X_OUTW(buf_len / 2, HFA384X_PCI_M0_LEN_OFF); + HFA384X_OUTW(HFA384X_PCI_CTL_TO_BAP, HFA384X_PCI_M0_CTL_OFF); +} +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + +/* Called only from software IRQ */ +static int prism2_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res, idx = -1, ret = 1, data_len; + struct hfa384x_tx_frame txdesc; + u16 fc, ethertype = 0; + enum { WDS_NO, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME } use_wds = WDS_NO; + struct net_device_stats *stats; + u8 *wepbuf = NULL; + int wepbuf_len = 0, host_encrypt = 0; + struct prism2_crypt_data *crypt = NULL; + void *sta = NULL; + u8 *encaps_data; + int encaps_len, skip_header_bytes; + int no_encrypt = 0; + int to_assoc_ap = 0; + + prism2_callback(local, PRISM2_CALLBACK_TX_START); + stats = hostap_get_stats(dev); + + if ((local->func->card_present && !local->func->card_present(local)) || + !local->hw_ready || local->hw_downloading || local->pri_only) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: prism2_tx: hw not ready - " + "skipping\n", dev->name); + ret = 0; + goto fail; + } + + if (skb->len < ETH_HLEN) { + printk(KERN_DEBUG "%s: prism2_tx: short skb (len=%d)\n", + dev->name, skb->len); + ret = 0; + goto fail; + } + + if (local->dev != dev) { + use_wds = (local->iw_mode == IW_MODE_MASTER && + !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? + WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; + if (dev == local->stadev) { + to_assoc_ap = 1; + use_wds = WDS_NO; + } else if (dev == local->apdev) { + printk(KERN_DEBUG "%s: prism2_tx: trying to use " + "AP device with Ethernet net dev\n", dev->name); + ret = 0; + goto fail; + } + } else { + if (local->iw_mode == IW_MODE_REPEAT) { + printk(KERN_DEBUG "%s: prism2_tx: trying to use " + "non-WDS link in Repeater mode\n", dev->name); + ret = 0; + goto fail; + } else if (local->iw_mode == IW_MODE_INFRA && + (local->wds_type & HOSTAP_WDS_AP_CLIENT) && + memcmp(skb->data + ETH_ALEN, dev->dev_addr, + ETH_ALEN) != 0) { + /* AP client mode: send frames with foreign src addr + * using 4-addr WDS frames */ + use_wds = WDS_COMPLIANT_FRAME; + } + } + + if (local->host_encrypt) { + /* Set crypt to default algorithm and key; will be replaced in + * AP code if STA has own alg/key */ + crypt = local->crypt; + host_encrypt = 1; + } + + if (skb->protocol == __constant_htons(ETH_P_HOSTAP)) { + /* frame from prism2_send_mgmt() */ + if (skb->len < sizeof(txdesc)) { + printk(KERN_DEBUG "%s: prism2_tx: short ETH_P_HOSTAP " + "skb\n", dev->name); + ret = 0; + goto fail; + } + memcpy(&txdesc, skb->data, sizeof(txdesc)); + skb_pull(skb, sizeof(txdesc)); + encaps_data = NULL; + encaps_len = 0; + skip_header_bytes = 0; + data_len = skb->len; + + fc = le16_to_cpu(txdesc.frame_control); + + /* data frames use normal host encryption, if needed */ + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) + goto data_txdesc_set; + + /* mgmt/ctrl frames do not need further processing, so skip to + * frame transmit */ + goto frame_processing_done; + } + + /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload + * ==> + * Prism2 TX frame with 802.11 header: + * txdesc (address order depending on used mode; includes dst_addr and + * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; + * proto[2], payload {, possible addr4[6]} */ + + ethertype = (skb->data[12] << 8) | skb->data[13]; + + memset(&txdesc, 0, sizeof(txdesc)); + + txdesc.tx_control = __cpu_to_le16(local->tx_control); + + /* Length of data after txdesc */ + data_len = skb->len - ETH_HLEN; + encaps_data = NULL; + encaps_len = 0; + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + data_len += encaps_len + 2; + skip_header_bytes -= 2; + } else if (ethertype >= 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + data_len += encaps_len + 2; + skip_header_bytes -= 2; + } + + fc = (WLAN_FC_TYPE_DATA << 2) | (WLAN_FC_STYPE_DATA << 4); + memcpy(&txdesc.dst_addr, skb->data, 2 * ETH_ALEN); + + if (use_wds != WDS_NO) { + /* Note! Prism2 station firmware has problems with sending real + * 802.11 frames with four addresses; until these problems can + * be fixed or worked around, 4-addr frames needed for WDS are + * using incompatible format: FromDS flag is not set and the + * fourth address is added after the frame payload; it is + * assumed, that the receiving station knows how to handle this + * frame format */ + + if (use_wds == WDS_COMPLIANT_FRAME) { + fc |= WLAN_FC_FROMDS | WLAN_FC_TODS; + /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, + * Addr4 = SA */ + memcpy(&txdesc.addr4, skb->data + ETH_ALEN, ETH_ALEN); + } else { + /* bogus 4-addr format to workaround Prism2 station + * f/w bug */ + fc |= WLAN_FC_TODS; + /* From DS: Addr1 = DA (used as RA), + * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), + */ + + /* SA from skb->data + ETH_ALEN will be added after + * frame payload */ + data_len += ETH_ALEN; + + memcpy(&txdesc.src_addr, dev->dev_addr, ETH_ALEN); + } + + /* send broadcast and multicast frames to broadcast RA, if + * configured; otherwise, use unicast RA of the WDS link */ + if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && + skb->data[0] & 0x01) + memset(&txdesc.addr1, 0xff, ETH_ALEN); + else if (iface->type == HOSTAP_INTERFACE_WDS) + memcpy(&txdesc.addr1, iface->u.wds.remote_addr, + ETH_ALEN); + else + memcpy(&txdesc.addr1, local->bssid, ETH_ALEN); + memcpy(&txdesc.addr2, dev->dev_addr, ETH_ALEN); + memcpy(&txdesc.addr3, skb->data, ETH_ALEN); + } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { + fc |= WLAN_FC_FROMDS; + /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ + memcpy(&txdesc.addr1, skb->data, ETH_ALEN); + /* FIX - addr2 replaced by f/w, so no need to fill it now(?) */ + memcpy(&txdesc.addr2, dev->dev_addr, ETH_ALEN); + memcpy(&txdesc.addr3, skb->data + ETH_ALEN, ETH_ALEN); + } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { + fc |= WLAN_FC_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ + memcpy(&txdesc.addr1, to_assoc_ap ? + local->assoc_ap_addr : local->bssid, ETH_ALEN); + memcpy(&txdesc.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(&txdesc.addr3, skb->data, ETH_ALEN); + } else if (local->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ + memcpy(&txdesc.addr1, skb->data, ETH_ALEN); + memcpy(&txdesc.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(&txdesc.addr3, local->bssid, ETH_ALEN); + } + + txdesc.frame_control = __cpu_to_le16(fc); + txdesc.data_len = __cpu_to_le16(data_len); + txdesc.len = __cpu_to_be16(data_len); + + skb->dev = dev; + + data_txdesc_set: + if (to_assoc_ap) + goto skip_ap_processing; + + switch (hostap_handle_sta_tx(local, skb, &txdesc, use_wds != WDS_NO, + host_encrypt, &crypt, &sta)) { + case AP_TX_CONTINUE: + break; + case AP_TX_CONTINUE_NOT_AUTHORIZED: + if (local->ieee_802_1x && ethertype != ETH_P_PAE && + use_wds == WDS_NO) { + printk(KERN_DEBUG "%s: dropped frame to unauthorized " + "port (IEEE 802.1X): ethertype=0x%04x\n", + dev->name, ethertype); + hostap_dump_tx_header(dev->name, &txdesc); + + ret = 0; /* drop packet */ + stats->tx_dropped++; + goto fail; + } + break; + case AP_TX_DROP: + ret = 0; /* drop packet */ + stats->tx_dropped++; + goto fail; + case AP_TX_RETRY: + goto fail; + case AP_TX_BUFFERED: + /* do not free skb here, it will be freed when the + * buffered frame is sent/timed out */ + ret = 0; + goto tx_exit; + } + + skip_ap_processing: + + if (local->ieee_802_1x && ethertype == ETH_P_PAE) { + if (crypt) { + no_encrypt = 1; + printk(KERN_DEBUG "%s: TX: IEEE 802.1X - passing " + "unencrypted EAPOL frame\n", dev->name); + } + crypt = NULL; /* no encryption for IEEE 802.1X frames */ + } + + if (crypt && (!crypt->ops || !crypt->ops->encrypt)) + crypt = NULL; + else if ((crypt || local->crypt) && !no_encrypt) { + /* Add ISWEP flag both for firmware and host based encryption + */ + fc |= WLAN_FC_ISWEP; + txdesc.frame_control = cpu_to_le16(fc); + } + + if (crypt) { + /* Perform host driver -based encryption */ + u8 *pos; + int olen; + + olen = data_len; + data_len += crypt->ops->extra_prefix_len + + crypt->ops->extra_postfix_len; + txdesc.data_len = cpu_to_le16(data_len); + txdesc.len = cpu_to_be16(data_len); + + wepbuf_len = data_len; + wepbuf = (u8 *) kmalloc(wepbuf_len, GFP_ATOMIC); + if (wepbuf == NULL) { + printk(KERN_DEBUG "%s: could not allocate TX wepbuf\n", + dev->name); + goto fail; + } + + pos = wepbuf + crypt->ops->extra_prefix_len; + if (encaps_len > 0) { + memcpy(pos, encaps_data, encaps_len); + pos += encaps_len; + } + memcpy(pos, skb->data + skip_header_bytes, + skb->len - skip_header_bytes); + if (use_wds == WDS_OWN_FRAME) { + memcpy(pos + skb->len - skip_header_bytes, + skb->data + ETH_ALEN, ETH_ALEN); + } + + atomic_inc(&crypt->refcnt); + olen = crypt->ops->encrypt(wepbuf, olen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (olen > wepbuf_len) { + printk(KERN_WARNING "%s: encrypt overwrote wepbuf " + "(%d > %d)\n", dev->name, olen, wepbuf_len); + } + if (olen < 0) + goto fail; + + data_len = wepbuf_len = olen; + txdesc.data_len = cpu_to_le16(data_len); + txdesc.len = cpu_to_be16(data_len); + } + + frame_processing_done: + idx = prism2_get_txfid_idx(local); + if (idx < 0) + goto fail; + + if (local->frame_dump & PRISM2_DUMP_TX_HDR) + hostap_dump_tx_header(dev->name, &txdesc); + + spin_lock(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + if (!res && skb->len >= local->bus_master_threshold_tx) { + u8 *pos; + int buf_len; + + local->bus_m0_tx_idx = idx; + + /* FIX: BAP0 should be locked during bus master transfer, but + * baplock with BH's disabled is not OK for this; netif queue + * stopping is not enough since BAP0 is used also for RID + * read/write */ + + /* stop the queue for the time that bus mastering on BAP0 is + * in use */ + hostap_netif_stop_queues(dev); + + spin_unlock(&local->baplock); + + /* Copy frame data to bus_m0_buf */ + pos = local->bus_m0_buf; + memcpy(pos, &txdesc, sizeof(txdesc)); + pos += sizeof(txdesc); + + if (!wepbuf) { + if (encaps_len > 0) { + memcpy(pos, encaps_data, encaps_len); + pos += encaps_len; + } + memcpy(pos, skb->data + skip_header_bytes, + skb->len - skip_header_bytes); + pos += skb->len - skip_header_bytes; + } + if (!wepbuf && use_wds == WDS_OWN_FRAME) { + /* add addr4 (SA) to bogus frame format if WDS is used + */ + memcpy(pos, skb->data + ETH_ALEN, ETH_ALEN); + pos += ETH_ALEN; + } + + if (wepbuf) { + memcpy(pos, wepbuf, wepbuf_len); + pos += wepbuf_len; + } + + buf_len = pos - local->bus_m0_buf; + if (buf_len & 1) + buf_len++; + +#ifdef PRISM2_ENABLE_BEFORE_TX_BUS_MASTER + /* Any RX packet seems to break something with TX bus + * mastering; enable command is enough to fix this.. */ + if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_ENABLE, 0, + prism2_tx_cb, (void *) buf_len)) { + printk(KERN_DEBUG "%s: TX: enable port0 failed\n", + dev->name); + } +#else /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */ + prism2_tx_cb(dev, (void *) buf_len, 0, 0); +#endif /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */ + + /* Bus master transfer will be started from command completion + * event handler and TX handling will be finished by calling + * prism2_transmit() from bus master event handler */ + goto tx_stats; + } +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + if (!res) + res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); + if (!res && !wepbuf && encaps_len > 0) + res = hfa384x_to_bap(dev, BAP0, encaps_data, encaps_len); + if (!res && !wepbuf && use_wds != WDS_OWN_FRAME) + res = hfa384x_to_bap(dev, BAP0, skb->data + skip_header_bytes, + skb->len - skip_header_bytes); + else if (!res && !wepbuf && use_wds == WDS_OWN_FRAME) { + int wlen, is_odd; + + wlen = skb->len - skip_header_bytes; + is_odd = wlen & 1; + + if (is_odd) + wlen--; /* need to avoid using odd offset */ + + res = hfa384x_to_bap(dev, BAP0, skb->data + skip_header_bytes, + wlen); + + /* add addr4 (SA) to bogus frame format if WDS is used */ + if (!res && is_odd) { + char tmpbuf[ETH_ALEN + 1]; + tmpbuf[0] = *(skb->data + skb->len - 1); + memcpy(tmpbuf + 1, skb->data + ETH_ALEN, ETH_ALEN); + res = hfa384x_to_bap(dev, BAP0, tmpbuf, ETH_ALEN + 1); + } else if (!res) { + res = hfa384x_to_bap(dev, BAP0, skb->data + ETH_ALEN, + ETH_ALEN); + } + } + + if (!res && wepbuf) + res = hfa384x_to_bap(dev, BAP0, wepbuf, wepbuf_len); + spin_unlock(&local->baplock); + + if (!res) + res = prism2_transmit(dev, idx); + if (res) { + printk(KERN_DEBUG "%s: prism2_tx - to BAP0 failed\n", + dev->name); + local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; + PRISM2_SCHEDULE_TASK(&local->reset_queue); + ret = 0; /* do not retry failed frames to avoid problems */ + goto fail; + } + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + tx_stats: +#endif + stats->tx_packets++; + stats->tx_bytes += data_len + 36; + + ret = 0; + + fail: + if (wepbuf) + kfree(wepbuf); + + if (!ret) + dev_kfree_skb(skb); + + tx_exit: + if (sta) + hostap_handle_sta_release(sta); + + prism2_callback(local, PRISM2_CALLBACK_TX_END); + return ret; +} + + +/* Called only from software IRQ */ +static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_tx_frame txdesc; + int hdr_len, data_len, ret = 1, idx, res; + u16 fc, tx_control; + + if ((local->func->card_present && !local->func->card_present(local)) || + !local->hw_ready || local->hw_downloading || local->pri_only) { + printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready - " + "skipping\n", dev->name); + ret = 0; + local->apdevstats.tx_dropped++; + goto fail; + } + + if (skb->len < 24) { + printk(KERN_DEBUG "%s: prism2_tx_80211: short skb (len=%d)\n", + dev->name, skb->len); + ret = 0; + local->apdevstats.tx_dropped++; + goto fail; + } + + memset(&txdesc, 0, sizeof(txdesc)); + /* txdesc.tx_rate might need to be set if f/w does not select suitable + * TX rate */ + + /* skb->data starts with txdesc->frame_control */ + hdr_len = 24; + memcpy(&txdesc.frame_control, skb->data, hdr_len); + fc = le16_to_cpu(txdesc.frame_control); + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && + (fc & WLAN_FC_FROMDS) && (fc & WLAN_FC_TODS) && skb->len >= 30) { + /* Addr4 */ + memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); + hdr_len += ETH_ALEN; + } + + tx_control = local->tx_control; + /* Request TX callback if protocol version is 2 in 802.11 header; + * this version 2 is a special case used between hostapd and kernel + * driver */ + if (((fc & WLAN_FC_PVER) == BIT(1)) && + local->ap && local->ap->tx_callback_idx) { + tx_control |= HFA384X_TX_CTRL_TX_OK; + txdesc.sw_support = cpu_to_le16(local->ap->tx_callback_idx); + + /* remove special version from the frame header */ + fc &= ~WLAN_FC_PVER; + txdesc.frame_control = cpu_to_le16(fc); + } + txdesc.tx_control = cpu_to_le16(tx_control); + + data_len = skb->len - hdr_len; + txdesc.data_len = __cpu_to_le16(data_len); + txdesc.len = __cpu_to_be16(data_len); + + /* We do not need to care about frame authorization etc. here since + * hostapd has full knowledge of auth/assoc status. However, we need to + * buffer the frame is the destination STA is in power saving mode. + * + * Wi-Fi 802.11b test plan suggests that AP should ignore power save + * bit in authentication and (re)association frames and assume tha + * STA remains awake for the response. */ + if (hostap_handle_sta_tx(local, skb, &txdesc, 0, 0, NULL, NULL) == + AP_TX_BUFFERED && + (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_AUTH && + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ASSOC_RESP && + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_REASSOC_RESP))) { + /* do not free skb here, it will be freed when the + * buffered frame is sent/timed out */ + ret = 0; + goto tx_exit; + } + + idx = prism2_get_txfid_idx(local); + if (idx < 0) { + local->apdevstats.tx_dropped++; + goto fail; + } + + spin_lock(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); + if (!res) + res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); + if (!res) + res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, + skb->len - hdr_len); + spin_unlock(&local->baplock); + + if (!res) + res = prism2_transmit(dev, idx); + if (res) { + printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", + dev->name); + local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; + PRISM2_SCHEDULE_TASK(&local->reset_queue); + local->apdevstats.tx_dropped++; + ret = 0; + goto fail; + } + + ret = 0; + + local->apdevstats.tx_packets++; + local->apdevstats.tx_bytes += skb->len; + + fail: + if (!ret) + dev_kfree_skb(skb); + tx_exit: + return ret; +} + + +/* Some SMP systems have reported number of odd errors with hostap_pci. fid + * register has changed values between consecutive reads for an unknown reason. + * This should really not happen, so more debugging is needed. This test + * version is a big slower, but it will detect most of such register changes + * and will try to get the correct fid eventually. */ +#define EXTRA_FID_READ_TESTS + +static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) +{ +#ifdef EXTRA_FID_READ_TESTS + u16 val, val2, val3; + int i; + + for (i = 0; i < 10; i++) { + val = HFA384X_INW(reg); + val2 = HFA384X_INW(reg); + val3 = HFA384X_INW(reg); + + if (val == val2 && val == val3) + return val; + + printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" + " %04x %04x %04x\n", + dev->name, i, reg, val, val2, val3); + if ((val == val2 || val == val3) && val != 0) + return val; + if (val2 == val3 && val2 != 0) + return val2; + } + printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " + "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); + return val; +#else /* EXTRA_FID_READ_TESTS */ + return HFA384X_INW(reg); +#endif /* EXTRA_FID_READ_TESTS */ +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_rx(local_info_t *local) +{ + struct net_device *dev = local->dev; + int res, rx_pending = 0; + u16 len, hdr_len, rxfid, status, macport; + struct net_device_stats *stats; + struct hfa384x_rx_frame rxdesc; + struct sk_buff *skb = NULL; + + prism2_callback(local, PRISM2_CALLBACK_RX_START); + stats = hostap_get_stats(dev); + + rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); +#ifndef final_version + if (rxfid == 0) { + rxfid = HFA384X_INW(HFA384X_RXFID_OFF); + printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", + rxfid); + if (rxfid == 0) { + PRISM2_SCHEDULE_TASK(&local->reset_queue); + goto rx_dropped; + } + /* try to continue with the new rxfid value */ + } +#endif + + spin_lock(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); + if (!res) + res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); + + if (res) { + spin_unlock(&local->baplock); + printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, + res); + if (res == -ETIMEDOUT) { + PRISM2_SCHEDULE_TASK(&local->reset_queue); + } + goto rx_dropped; + } + + len = le16_to_cpu(rxdesc.data_len); + hdr_len = sizeof(rxdesc); + status = le16_to_cpu(rxdesc.status); + macport = (status >> 8) & 0x07; + + /* Drop frames with too large reported payload length. Monitor mode + * seems to sometimes pass frames (e.g., ctrl::ack) with signed and + * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for + * macport 7 */ + if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { + if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { + if (len >= (u16) -14) { + hdr_len -= 65535 - len; + hdr_len--; + } + len = 0; + } else { + spin_unlock(&local->baplock); + printk(KERN_DEBUG "%s: Received frame with invalid " + "length 0x%04x\n", dev->name, len); + hostap_dump_rx_header(dev->name, &rxdesc); + goto rx_dropped; + } + } + + skb = dev_alloc_skb(len + hdr_len); + if (!skb) { + spin_unlock(&local->baplock); + printk(KERN_DEBUG "%s: RX failed to allocate skb\n", + dev->name); + goto rx_dropped; + } + skb->dev = dev; + memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + if (len >= local->bus_master_threshold_rx) { + unsigned long addr; + + hfa384x_events_no_bap1(dev); + + local->rx_skb = skb; + /* Internal BAP0 offset points to the byte following rxdesc; + * copy rest of the data using bus master */ + addr = virt_to_phys(skb_put(skb, len)); + HFA384X_OUTW((addr & 0xffff0000) >> 16, + HFA384X_PCI_M0_ADDRH_OFF); + HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF); + if (len & 1) + len++; + HFA384X_OUTW(len / 2, HFA384X_PCI_M0_LEN_OFF); + HFA384X_OUTW(HFA384X_PCI_CTL_FROM_BAP, HFA384X_PCI_M0_CTL_OFF); + + /* pci_bus_m1 event will be generated when data transfer is + * complete and the frame will then be added to rx_list and + * rx_tasklet is scheduled */ + rx_pending = 1; + + /* Have to release baplock before returning, although BAP0 + * should really not be used before DMA transfer has been + * completed. */ + spin_unlock(&local->baplock); + } else +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + { + if (len > 0) + res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), + len); + spin_unlock(&local->baplock); + if (res) { + printk(KERN_DEBUG "%s: RX failed to read " + "frame data\n", dev->name); + goto rx_dropped; + } + + skb_queue_tail(&local->rx_list, skb); + tasklet_schedule(&local->rx_tasklet); + } + + rx_exit: + prism2_callback(local, PRISM2_CALLBACK_RX_END); + if (!rx_pending) { + HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); + } + + return; + + rx_dropped: + stats->rx_dropped++; + if (skb) + dev_kfree_skb(skb); + goto rx_exit; +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) +{ + struct hfa384x_rx_frame *rxdesc; + struct net_device *dev = skb->dev; + struct hostap_80211_rx_status stats; + int hdrlen, rx_hdrlen; + + rx_hdrlen = sizeof(*rxdesc); + if (skb->len < sizeof(*rxdesc)) { + /* Allow monitor mode to receive shorter frames */ + if (local->iw_mode == IW_MODE_MONITOR && + skb->len >= sizeof(*rxdesc) - 30) { + rx_hdrlen = skb->len; + } else { + dev_kfree_skb(skb); + return; + } + } + + rxdesc = (struct hfa384x_rx_frame *) skb->data; + + if (local->frame_dump & PRISM2_DUMP_RX_HDR && + skb->len >= sizeof(*rxdesc)) + hostap_dump_rx_header(dev->name, rxdesc); + + if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && + (!local->monitor_allow_fcserr || + local->iw_mode != IW_MODE_MONITOR)) + goto drop; + + if (skb->len > PRISM2_DATA_MAXLEN) { + printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", + dev->name, skb->len, PRISM2_DATA_MAXLEN); + goto drop; + } + + stats.mac_time = le32_to_cpu(rxdesc->time); + stats.signal = HFA384X_RSSI_LEVEL_TO_dBm(rxdesc->signal); + stats.noise = HFA384X_RSSI_LEVEL_TO_dBm(rxdesc->silence); + stats.rate = rxdesc->rate; + + /* Convert Prism2 RX structure into IEEE 802.11 header */ + hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control)); + if (hdrlen > rx_hdrlen) + hdrlen = rx_hdrlen; + + memmove(skb_pull(skb, rx_hdrlen - hdrlen), + &rxdesc->frame_control, hdrlen); + + hostap_80211_rx(dev, skb, &stats); + return; + + drop: + dev_kfree_skb(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_rx_tasklet(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&local->rx_list)) != NULL) + hostap_rx_skb(local, skb); +} + + +/* Called only from hardware IRQ */ +static void prism2_alloc_ev(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int idx; + u16 fid; + + fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); + + PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); + + spin_lock(&local->txfidlock); + idx = local->next_alloc; + + do { + if (local->txfid[idx] == fid) { + PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", + idx); + +#ifndef final_version + if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) + printk("Already released txfid found at idx " + "%d\n", idx); + if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) + printk("Already reserved txfid found at idx " + "%d\n", idx); +#endif + local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; + idx++; + local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : + idx; + + if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && + netif_queue_stopped(dev)) + hostap_netif_wake_queues(dev); + + spin_unlock(&local->txfidlock); + return; + } + + idx++; + if (idx >= PRISM2_TXFID_COUNT) + idx = 0; + } while (idx != local->next_alloc); + + printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " + "read 0x%04x) for alloc event\n", dev->name, fid, + HFA384X_INW(HFA384X_ALLOCFID_OFF)); + printk(KERN_DEBUG "TXFIDs:"); + for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) + printk(" %04x[%04x]", local->txfid[idx], + local->intransmitfid[idx]); + printk("\n"); + spin_unlock(&local->txfidlock); + + /* FIX: should probably schedule reset; reference to one txfid was lost + * completely.. Bad things will happen if we run out of txfids + * Actually, this will cause netdev watchdog to notice TX timeout and + * then card reset after all txfids have been leaked. */ +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_tx_callback(local_info_t *local, + struct hfa384x_tx_frame *txdesc, int ok, + char *payload) +{ + u16 sw_support, hdrlen, len; + struct sk_buff *skb; + struct hostap_tx_callback_info *cb; + + /* Make sure that frame was from us. */ + if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) { + printk(KERN_DEBUG "%s: TX callback - foreign frame\n", + local->dev->name); + return; + } + + sw_support = le16_to_cpu(txdesc->sw_support); + + spin_lock(&local->lock); + cb = local->tx_callback; + while (cb != NULL && cb->idx != sw_support) + cb = cb->next; + spin_unlock(&local->lock); + + if (cb == NULL) { + printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", + local->dev->name, sw_support); + return; + } + + hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control)); + len = le16_to_cpu(txdesc->data_len); + skb = dev_alloc_skb(hdrlen + len); + if (skb == NULL) { + printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " + "skb\n", local->dev->name); + return; + } + + memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); + if (payload) + memcpy(skb_put(skb, len), payload, len); + + skb->dev = local->dev; + skb->mac.raw = skb->data; + + cb->func(skb, ok, cb->data); +} + + +/* Called only as a tasklet (software IRQ) */ +static int hostap_tx_compl_read(local_info_t *local, int error, + struct hfa384x_tx_frame *txdesc, + char **payload) +{ + u16 fid, len; + int res, ret = 0; + struct net_device *dev = local->dev; + + fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); + + PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); + + spin_lock(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, fid, 0); + if (!res) + res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); + if (res) { + PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " + "read txdesc\n", dev->name, error, fid); + if (res == -ETIMEDOUT) { + PRISM2_SCHEDULE_TASK(&local->reset_queue); + } + ret = -1; + goto fail; + } + if (txdesc->sw_support) { + len = le16_to_cpu(txdesc->data_len); + if (len < PRISM2_DATA_MAXLEN) { + *payload = (char *) kmalloc(len, GFP_ATOMIC); + if (*payload == NULL || + hfa384x_from_bap(dev, BAP0, *payload, len)) { + PDEBUG(DEBUG_EXTRA, "%s: could not read TX " + "frame payload\n", dev->name); + kfree(*payload); + *payload = NULL; + ret = -1; + goto fail; + } + } + } + + fail: + spin_unlock(&local->baplock); + + return ret; +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_tx_ev(local_info_t *local) +{ + struct net_device *dev = local->dev; + char *payload = NULL; + struct hfa384x_tx_frame txdesc; + + if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) + goto fail; + + if (local->frame_dump & PRISM2_DUMP_TX_HDR) { + PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " + "retry_count=%d tx_rate=%d seq_ctrl=%d " + "duration_id=%d\n", + dev->name, le16_to_cpu(txdesc.status), + txdesc.retry_count, txdesc.tx_rate, + le16_to_cpu(txdesc.seq_ctrl), + le16_to_cpu(txdesc.duration_id)); + } + + if (txdesc.sw_support) + hostap_tx_callback(local, &txdesc, 1, payload); + kfree(payload); + + fail: + HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_sta_tx_exc_tasklet(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { + struct hfa384x_tx_frame *txdesc = + (struct hfa384x_tx_frame *) skb->data; + hostap_handle_sta_tx_exc(local, txdesc); + dev_kfree_skb(skb); + } +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_txexc(local_info_t *local) +{ + struct net_device *dev = local->dev; + u16 status, fc; + int show_dump, res; + char *payload = NULL; + struct hfa384x_tx_frame txdesc; + + show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; + local->stats.tx_errors++; + + res = hostap_tx_compl_read(local, 1, &txdesc, &payload); + HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); + if (res) + return; + + status = le16_to_cpu(txdesc.status); + +#if WIRELESS_EXT > 13 + /* We produce a TXDROP event only for retry or lifetime + * exceeded, because that's the only status that really mean + * that this particular node went away. + * Other errors means that *we* screwed up. - Jean II */ + if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) + { + union iwreq_data wrqu; + + /* Copy 802.11 dest address. */ + memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); + } else + show_dump = 1; +#endif /* WIRELESS_EXT > 13 */ + + if (local->iw_mode == IW_MODE_MASTER || + local->iw_mode == IW_MODE_REPEAT || + local->wds_type & HOSTAP_WDS_AP_CLIENT) { + struct sk_buff *skb; + skb = dev_alloc_skb(sizeof(txdesc)); + if (skb) { + memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, + sizeof(txdesc)); + skb_queue_tail(&local->sta_tx_exc_list, skb); + tasklet_schedule(&local->sta_tx_exc_tasklet); + } + } + + if (txdesc.sw_support) + hostap_tx_callback(local, &txdesc, 0, payload); + kfree(payload); + + if (!show_dump) + return; + + PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" + " tx_control=%04x\n", + dev->name, status, + status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", + status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", + status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", + status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", + le16_to_cpu(txdesc.tx_control)); + + fc = le16_to_cpu(txdesc.frame_control); + PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " + "(%s%s%s::%d%s%s)\n", + txdesc.retry_count, txdesc.tx_rate, fc, + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT ? "Mgmt" : "", + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_CTRL ? "Ctrl" : "", + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ? "Data" : "", + WLAN_FC_GET_STYPE(fc), + fc & WLAN_FC_TODS ? " ToDS" : "", + fc & WLAN_FC_FROMDS ? " FromDS" : ""); + PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" + MACSTR " A4=" MACSTR "\n", + MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), + MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_info_tasklet(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&local->info_list)) != NULL) { + hostap_info_process(local, skb); + dev_kfree_skb(skb); + } +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info(local_info_t *local) +{ + struct net_device *dev = local->dev; + u16 fid; + int res, left; + struct hfa384x_info_frame info; + struct sk_buff *skb; + + fid = HFA384X_INW(HFA384X_INFOFID_OFF); + + spin_lock(&local->baplock); + res = hfa384x_setup_bap(dev, BAP0, fid, 0); + if (!res) + res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); + if (res) { + spin_unlock(&local->baplock); + printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", + fid); + if (res == -ETIMEDOUT) { + PRISM2_SCHEDULE_TASK(&local->reset_queue); + } + goto out; + } + + le16_to_cpus(&info.len); + le16_to_cpus(&info.type); + left = (info.len - 1) * 2; + + if (info.len & 0x8000 || info.len == 0 || left > 2060) { + /* data register seems to give 0x8000 in some error cases even + * though busy bit is not set in offset register; + * in addition, length must be at least 1 due to type field */ + spin_unlock(&local->baplock); + printk(KERN_DEBUG "%s: Received info frame with invalid " + "length 0x%04x (type 0x%04x)\n", dev->name, info.len, + info.type); + goto out; + } + + skb = dev_alloc_skb(sizeof(info) + left); + if (skb == NULL) { + spin_unlock(&local->baplock); + printk(KERN_DEBUG "%s: Could not allocate skb for info " + "frame\n", dev->name); + goto out; + } + + memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); + if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) + { + spin_unlock(&local->baplock); + printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " + "len=0x%04x, type=0x%04x\n", + dev->name, fid, info.len, info.type); + dev_kfree_skb(skb); + goto out; + } + spin_unlock(&local->baplock); + + skb_queue_tail(&local->info_list, skb); + tasklet_schedule(&local->info_tasklet); + + out: + HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); +} + + +/* Called only as a tasklet (software IRQ) */ +static void hostap_bap_tasklet(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + struct net_device *dev = local->dev; + u16 ev; + int frames = 30; + + if (local->func->card_present && !local->func->card_present(local)) + return; + + set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); + + /* Process all pending BAP events without generating new interrupts + * for them */ + while (frames-- > 0) { + ev = HFA384X_INW(HFA384X_EVSTAT_OFF); + if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) + break; + if (ev & HFA384X_EV_RX) + prism2_rx(local); + if (ev & HFA384X_EV_INFO) + prism2_info(local); + if (ev & HFA384X_EV_TX) + prism2_tx_ev(local); + if (ev & HFA384X_EV_TXEXC) + prism2_txexc(local); + } + + set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); + clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); + + /* Enable interrupts for new BAP events */ + hfa384x_events_all(dev); + clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); +} + + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) +/* Called only from hardware IRQ */ +static void prism2_bus_master_ev(struct net_device *dev, int bap) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + if (bap == BAP1) { + /* FIX: frame payload was DMA'd to skb->data; might need to + * invalidate data cache for that memory area */ + skb_queue_tail(&local->rx_list, local->rx_skb); + tasklet_schedule(&local->rx_tasklet); + HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); + } else { + if (prism2_transmit(dev, local->bus_m0_tx_idx)) { + printk(KERN_DEBUG "%s: prism2_transmit() failed " + "when called from bus master event\n", + dev->name); + local->intransmitfid[local->bus_m0_tx_idx] = + PRISM2_TXFID_EMPTY; + PRISM2_SCHEDULE_TASK(&local->reset_queue); + } + } +} +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + +/* Called only from hardware IRQ */ +static void prism2_infdrop(struct net_device *dev) +{ + static unsigned long last_inquire = 0; + + PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); + + /* some firmware versions seem to get stuck with + * full CommTallies in high traffic load cases; every + * packet will then cause INFDROP event and CommTallies + * info frame will not be sent automatically. Try to + * get out of this state by inquiring CommTallies. */ + if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { + hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, + HFA384X_INFO_COMMTALLIES, NULL, NULL); + last_inquire = jiffies; + } +} + + +/* Called only from hardware IRQ */ +static void prism2_ev_tick(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 evstat, inten; + static int prev_stuck = 0; + + if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && + local->last_tick_timer) { + evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); + inten = HFA384X_INW(HFA384X_INTEN_OFF); + if (!prev_stuck) { + printk(KERN_INFO "%s: SW TICK stuck? " + "bits=0x%lx EvStat=%04x IntEn=%04x\n", + dev->name, local->bits, evstat, inten); + } + local->sw_tick_stuck++; + if ((evstat & HFA384X_BAP0_EVENTS) && + (inten & HFA384X_BAP0_EVENTS)) { + printk(KERN_INFO "%s: trying to recover from IRQ " + "hang\n", dev->name); + hfa384x_events_no_bap0(dev); + } + prev_stuck = 1; + } else + prev_stuck = 0; +} + + +/* Called only from hardware IRQ */ +static inline void prism2_check_magic(local_info_t *local) +{ + /* at least PCI Prism2.5 with bus mastering seems to sometimes + * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the + * register once or twice seems to get the correct value.. PCI cards + * cannot anyway be removed during normal operation, so there is not + * really any need for this verification with them. */ + +#ifndef PRISM2_PCI +#ifndef final_version + static unsigned long last_magic_err = 0; + struct net_device *dev = local->dev; + + if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { + if (!local->hw_ready) + return; + HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); + if (time_after(jiffies, last_magic_err + 10 * HZ)) { + printk("%s: Interrupt, but SWSUPPORT0 does not match: " + "%04X != %04X - card removed?\n", dev->name, + HFA384X_INW(HFA384X_SWSUPPORT0_OFF), + HFA384X_MAGIC); + last_magic_err = jiffies; + } else if (net_ratelimit()) { + printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " + "MAGIC=%04x\n", dev->name, + HFA384X_INW(HFA384X_SWSUPPORT0_OFF), + HFA384X_MAGIC); + } + if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) + PRISM2_SCHEDULE_TASK(&local->reset_queue); + return; + } +#endif /* final_version */ +#endif /* !PRISM2_PCI */ +} + + +/* Called only from hardware IRQ */ +static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int events = 0; + u16 ev; + + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); + + if (local->func->card_present && !local->func->card_present(local)) { + printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", + dev->name); + return IRQ_HANDLED; + } + + prism2_check_magic(local); + + for (;;) { + ev = HFA384X_INW(HFA384X_EVSTAT_OFF); + if (ev == 0xffff) { + if (local->shutdown) + return IRQ_HANDLED; + HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); + printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", + dev->name); + return IRQ_HANDLED; + } + + ev &= HFA384X_INW(HFA384X_INTEN_OFF); + if (ev == 0) + break; + + if (ev & HFA384X_EV_CMD) { + prism2_cmd_ev(dev); + } + + /* Above events are needed even before hw is ready, but other + * events should be skipped during initialization. This may + * change for AllocEv if allocate_fid is implemented without + * busy waiting. */ + if (!local->hw_ready || local->hw_resetting || + !local->dev_enabled) { + ev = HFA384X_INW(HFA384X_EVSTAT_OFF); + if (ev & HFA384X_EV_CMD) + goto next_event; + if ((ev & HFA384X_EVENT_MASK) == 0) + return IRQ_HANDLED; + if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && + net_ratelimit()) { + printk(KERN_DEBUG "%s: prism2_interrupt: hw " + "not ready; skipping events 0x%04x " + "(IntEn=0x%04x)%s%s%s\n", + dev->name, ev, + HFA384X_INW(HFA384X_INTEN_OFF), + !local->hw_ready ? " (!hw_ready)" : "", + local->hw_resetting ? + " (hw_resetting)" : "", + !local->dev_enabled ? + " (!dev_enabled)" : ""); + } + HFA384X_OUTW(ev, HFA384X_EVACK_OFF); + return IRQ_HANDLED; + } + + if (ev & HFA384X_EV_TICK) { + prism2_ev_tick(dev); + HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); + } + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + if (ev & HFA384X_EV_PCI_M0) { + prism2_bus_master_ev(dev, BAP0); + HFA384X_OUTW(HFA384X_EV_PCI_M0, HFA384X_EVACK_OFF); + } + + if (ev & HFA384X_EV_PCI_M1) { + /* previous RX has been copied can be ACKed now */ + HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); + + prism2_bus_master_ev(dev, BAP1); + HFA384X_OUTW(HFA384X_EV_PCI_M1, HFA384X_EVACK_OFF); + } +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + if (ev & HFA384X_EV_ALLOC) { + prism2_alloc_ev(dev); + HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); + } + + /* Reading data from the card is quite time consuming, so do it + * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed + * and unmasked after needed data has been read completely. */ + if (ev & HFA384X_BAP0_EVENTS) { + hfa384x_events_no_bap0(dev); + tasklet_schedule(&local->bap_tasklet); + } + +#ifndef final_version + if (ev & HFA384X_EV_WTERR) { + PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); + HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); + } +#endif /* final_version */ + + if (ev & HFA384X_EV_INFDROP) { + prism2_infdrop(dev); + HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); + } + + next_event: + events++; + if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { + PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " + "(EvStat=0x%04x)\n", + PRISM2_MAX_INTERRUPT_EVENTS, + HFA384X_INW(HFA384X_EVSTAT_OFF)); + break; + } + } + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); + return IRQ_RETVAL(events); +} + + +static void prism2_check_sta_fw_version(local_info_t *local) +{ + struct hfa384x_comp_ident comp; + int id, variant, major, minor; + + if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, + &comp, sizeof(comp), 1) < 0) + return; + + local->fw_ap = 0; + id = le16_to_cpu(comp.id); + if (id != HFA384X_COMP_ID_STA) { + if (id == HFA384X_COMP_ID_FW_AP) + local->fw_ap = 1; + return; + } + + major = __le16_to_cpu(comp.major); + minor = __le16_to_cpu(comp.minor); + variant = __le16_to_cpu(comp.variant); + local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); + + /* Station firmware versions before 1.4.x seem to have a bug in + * firmware-based WEP encryption when using Host AP mode, so use + * host_encrypt as a default for them. Firmware version 1.4.9 is the + * first one that has been seen to produce correct encryption, but the + * bug might be fixed before that (although, at least 1.4.2 is broken). + */ + local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); + + if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && + !local->fw_encrypt_ok) { + printk(KERN_DEBUG "%s: defaulting to host-based encryption as " + "a workaround for firmware bug in Host AP mode WEP\n", + local->dev->name); + local->host_encrypt = 1; + } + + /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken + * in station firmware versions before 1.5.x. With these versions, the + * driver uses a workaround with bogus frame format (4th address after + * the payload). This is not compatible with other AP devices. Since + * the firmware bug is fixed in the latest station firmware versions, + * automatically enable standard compliant mode for cards using station + * firmware version 1.5.0 or newer. */ + if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) + local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; + else { + printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " + "workaround for firmware bug in Host AP mode WDS\n", + local->dev->name); + } + + hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); +} + + +static void prism2_crypt_deinit_entries(local_info_t *local, int force) +{ + struct list_head *ptr, *n; + struct prism2_crypt_data *entry; + + for (ptr = local->crypt_deinit_list.next, n = ptr->next; + ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct prism2_crypt_data, list); + + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(ptr); + + if (entry->ops) + entry->ops->deinit(entry->priv); + kfree(entry); + } +} + + +static void prism2_crypt_deinit_handler(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_crypt_deinit_entries(local, 0); + if (!list_empty(&local->crypt_deinit_list)) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", local->dev->name); + local->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&local->crypt_deinit_timer); + } + spin_unlock_irqrestore(&local->lock, flags); + +} + + +static void hostap_passive_scan(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + struct net_device *dev = local->dev; + u16 channel; + + if (local->passive_scan_interval <= 0) + return; + + if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { + int max_tries = 16; + + /* Even though host system does not really know when the WLAN + * MAC is sending frames, try to avoid changing channels for + * passive scanning when a host-generated frame is being + * transmitted */ + if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { + printk(KERN_DEBUG "%s: passive scan detected pending " + "TX - delaying\n", dev->name); + local->passive_scan_timer.expires = jiffies + HZ / 10; + add_timer(&local->passive_scan_timer); + return; + } + + do { + local->passive_scan_channel++; + if (local->passive_scan_channel > 14) + local->passive_scan_channel = 1; + max_tries--; + } while (!(local->channel_mask & + (1 << (local->passive_scan_channel - 1))) && + max_tries > 0); + + if (max_tries == 0) { + printk(KERN_INFO "%s: no allowed passive scan channels" + " found\n", dev->name); + return; + } + + printk(KERN_DEBUG "%s: passive scan channel %d\n", + dev->name, local->passive_scan_channel); + channel = local->passive_scan_channel; + local->passive_scan_state = PASSIVE_SCAN_WAIT; + local->passive_scan_timer.expires = jiffies + HZ / 10; + } else { + channel = local->channel; + local->passive_scan_state = PASSIVE_SCAN_LISTEN; + local->passive_scan_timer.expires = jiffies + + local->passive_scan_interval * HZ; + } + + if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CHANGE_CHANNEL << 8), + channel, NULL, NULL)) + printk(KERN_ERR "%s: passive scan channel set %d " + "failed\n", dev->name, channel); + + add_timer(&local->passive_scan_timer); +} + + +/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is + * used to monitor that local->last_tick_timer is being updated. If not, + * interrupt busy-loop is assumed and driver tries to recover by masking out + * some events. */ +static void hostap_tick_timer(unsigned long data) +{ + static unsigned long last_inquire = 0; + local_info_t *local = (local_info_t *) data; + local->last_tick_timer = jiffies; + + /* Inquire CommTallies every 10 seconds to keep the statistics updated + * more often during low load and when using 32-bit tallies. */ + if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && + !local->hw_downloading && local->hw_ready && + !local->hw_resetting && local->dev_enabled) { + hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, + HFA384X_INFO_COMMTALLIES, NULL, NULL); + last_inquire = jiffies; + } + + local->tick_timer.expires = jiffies + 2 * HZ; + add_timer(&local->tick_timer); +} + + +#ifndef PRISM2_NO_PROCFS_DEBUG +static int prism2_registers_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + local_info_t *local = (local_info_t *) data; + + if (off != 0) { + *eof = 1; + return 0; + } + +#define SHOW_REG(n) \ +p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) + + SHOW_REG(CMD); + SHOW_REG(PARAM0); + SHOW_REG(PARAM1); + SHOW_REG(PARAM2); + SHOW_REG(STATUS); + SHOW_REG(RESP0); + SHOW_REG(RESP1); + SHOW_REG(RESP2); + SHOW_REG(INFOFID); + SHOW_REG(CONTROL); + SHOW_REG(SELECT0); + SHOW_REG(SELECT1); + SHOW_REG(OFFSET0); + SHOW_REG(OFFSET1); + SHOW_REG(RXFID); + SHOW_REG(ALLOCFID); + SHOW_REG(TXCOMPLFID); + SHOW_REG(SWSUPPORT0); + SHOW_REG(SWSUPPORT1); + SHOW_REG(SWSUPPORT2); + SHOW_REG(EVSTAT); + SHOW_REG(INTEN); + SHOW_REG(EVACK); + /* Do not read data registers, because they change the state of the + * MAC (offset += 2) */ + /* SHOW_REG(DATA0); */ + /* SHOW_REG(DATA1); */ + SHOW_REG(AUXPAGE); + SHOW_REG(AUXOFFSET); + /* SHOW_REG(AUXDATA); */ +#ifdef PRISM2_PCI + SHOW_REG(PCICOR); + SHOW_REG(PCIHCR); + SHOW_REG(PCI_M0_ADDRH); + SHOW_REG(PCI_M0_ADDRL); + SHOW_REG(PCI_M0_LEN); + SHOW_REG(PCI_M0_CTL); + SHOW_REG(PCI_STATUS); + SHOW_REG(PCI_M1_ADDRH); + SHOW_REG(PCI_M1_ADDRL); + SHOW_REG(PCI_M1_LEN); + SHOW_REG(PCI_M1_CTL); +#endif /* PRISM2_PCI */ + + return (p - page); +} +#endif /* PRISM2_NO_PROCFS_DEBUG */ + + +static struct net_device * +prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx) +{ + struct net_device *dev; + struct hostap_interface *iface; + struct local_info *local; + int len, i; + + if (funcs == NULL) + return NULL; + + len = sizeof(struct hostap_interface) + + 3 + sizeof(struct local_info) + + 3 + sizeof(struct ap_data); + + dev = alloc_etherdev(len); + if (dev == NULL) + return NULL; + + iface = dev->priv; + local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); + local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); + local->dev = iface->dev = dev; + iface->local = local; + iface->type = HOSTAP_INTERFACE_MAIN; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + dev->name = iface->name; +#endif + INIT_LIST_HEAD(&local->hostap_interfaces); + list_add(&iface->list, &local->hostap_interfaces); + + local->hw_module = THIS_MODULE; + +#ifdef PRISM2_IO_DEBUG + local->io_debug_enabled = 1; +#endif /* PRISM2_IO_DEBUG */ + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + local->bus_m0_buf = (u8 *) kmalloc(sizeof(struct hfa384x_tx_frame) + + PRISM2_DATA_MAXLEN, GFP_DMA); + if (local->bus_m0_buf == NULL) + goto fail; +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + local->func = funcs; + local->func->cmd = hfa384x_cmd; + local->func->read_regs = hfa384x_read_regs; + local->func->get_rid = hfa384x_get_rid; + local->func->set_rid = hfa384x_set_rid; + local->func->hw_enable = prism2_hw_enable; + local->func->hw_config = prism2_hw_config; + local->func->hw_reset = prism2_hw_reset; + local->func->hw_shutdown = prism2_hw_shutdown; + local->func->reset_port = prism2_reset_port; + local->func->tx = prism2_tx; + local->func->schedule_reset = prism2_schedule_reset; +#ifdef PRISM2_DOWNLOAD_SUPPORT + local->func->download = prism2_download; +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + local->func->tx_80211 = prism2_tx_80211; + + local->disable_on_close = disable_on_close; + local->mtu = mtu; + + rwlock_init(&local->iface_lock); + spin_lock_init(&local->txfidlock); + spin_lock_init(&local->cmdlock); + spin_lock_init(&local->baplock); + spin_lock_init(&local->lock); + init_MUTEX(&local->rid_bap_sem); + + if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) + card_idx = 0; + local->card_idx = card_idx; + + i = essid[card_idx] == NULL ? 0 : card_idx; + len = strlen(essid[i]); + memcpy(local->essid, essid[i], + len > MAX_SSID_LEN ? MAX_SSID_LEN : len); + local->essid[MAX_SSID_LEN] = '\0'; + i = GET_INT_PARM(iw_mode, card_idx); + if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || + i == IW_MODE_MONITOR) { + local->iw_mode = i; + } else { + printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " + "IW_MODE_MASTER\n", i); + local->iw_mode = IW_MODE_MASTER; + } + local->channel = GET_INT_PARM(channel, card_idx); + local->beacon_int = GET_INT_PARM(beacon_int, card_idx); + local->dtim_period = GET_INT_PARM(dtim_period, card_idx); + local->wds_max_connections = 16; + local->tx_control = HFA384X_TX_CTRL_FLAGS; + local->manual_retry_count = -1; + local->rts_threshold = 2347; + local->fragm_threshold = 2346; + local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + local->bus_master_threshold_rx = GET_INT_PARM(bus_master_threshold_rx, + card_idx); + local->bus_master_threshold_tx = GET_INT_PARM(bus_master_threshold_tx, + card_idx); +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + + /* Initialize task queue structures */ + INIT_WORK(&local->reset_queue, handle_reset_queue, local); + INIT_WORK(&local->set_multicast_list_queue, + hostap_set_multicast_list_queue, local->dev); + + /* Initialize tasklets for handling hardware IRQ related operations + * outside hw IRQ handler */ + HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet, + (unsigned long) local); + + HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet, + (unsigned long) local); + hostap_info_init(local); + + HOSTAP_TASKLET_INIT(&local->rx_tasklet, + hostap_rx_tasklet, (unsigned long) local); + skb_queue_head_init(&local->rx_list); + + HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet, + hostap_sta_tx_exc_tasklet, (unsigned long) local); + skb_queue_head_init(&local->sta_tx_exc_list); + + INIT_LIST_HEAD(&local->cmd_queue); + init_waitqueue_head(&local->hostscan_wq); + INIT_LIST_HEAD(&local->crypt_deinit_list); + init_timer(&local->crypt_deinit_timer); + local->crypt_deinit_timer.data = (unsigned long) local; + local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; + + init_timer(&local->passive_scan_timer); + local->passive_scan_timer.data = (unsigned long) local; + local->passive_scan_timer.function = hostap_passive_scan; + + init_timer(&local->tick_timer); + local->tick_timer.data = (unsigned long) local; + local->tick_timer.function = hostap_tick_timer; + local->tick_timer.expires = jiffies + 2 * HZ; + add_timer(&local->tick_timer); + + hostap_setup_dev(dev, local, 1); + + local->saved_eth_header_parse = dev->hard_header_parse; + + return dev; + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + fail: + kfree(local->bus_m0_buf); + free_netdev(dev); + return NULL; +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ +} + + +static int prism2_init_dev(local_info_t *local) +{ + struct net_device *dev = local->dev; + int len, ret; + + len = strlen(dev_template); + if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { + printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", + dev_template); + return 1; + } + + rtnl_lock(); + ret = dev_alloc_name(dev, dev_template); + if (ret >= 0) + ret = register_netdevice(dev); + rtnl_unlock(); + if (ret < 0) { + printk(KERN_WARNING "%s: register netdevice failed!\n", + dev_info); + return 1; + } + printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); + + hostap_init_proc(local); +#ifndef PRISM2_NO_PROCFS_DEBUG + create_proc_read_entry("registers", 0, local->proc, + prism2_registers_proc_read, local); +#endif /* PRISM2_NO_PROCFS_DEBUG */ + hostap_init_data(local); + + return 0; +} + + +static void prism2_free_local_data(struct net_device *dev) +{ + struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; + int i; + struct sk_buff *skb; + struct hostap_interface *iface; + struct local_info *local; + struct list_head *ptr, *n; + + if (dev == NULL) + return; + + iface = dev->priv; + local = iface->local; + + flush_scheduled_work(); + + if (timer_pending(&local->crypt_deinit_timer)) + del_timer(&local->crypt_deinit_timer); + prism2_crypt_deinit_entries(local, 1); + + if (timer_pending(&local->passive_scan_timer)) + del_timer(&local->passive_scan_timer); + + if (timer_pending(&local->tick_timer)) + del_timer(&local->tick_timer); + + prism2_clear_cmd_queue(local); + + while ((skb = skb_dequeue(&local->info_list)) != NULL) + dev_kfree_skb(skb); + + while ((skb = skb_dequeue(&local->rx_list)) != NULL) + dev_kfree_skb(skb); + + while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) + dev_kfree_skb(skb); + + if (local->dev_enabled) + prism2_callback(local, PRISM2_CALLBACK_DISABLE); + + if (local->crypt) { + if (local->crypt->ops) + local->crypt->ops->deinit(local->crypt->priv); + kfree(local->crypt); + local->crypt = NULL; + } + + if (local->ap != NULL) + hostap_free_data(local->ap); + +#ifndef PRISM2_NO_PROCFS_DEBUG + if (local->proc != NULL) + remove_proc_entry("registers", local->proc); +#endif /* PRISM2_NO_PROCFS_DEBUG */ + hostap_remove_proc(local); + + tx_cb = local->tx_callback; + while (tx_cb != NULL) { + tx_cb_prev = tx_cb; + tx_cb = tx_cb->next; + kfree(tx_cb_prev); + } + + hostap_set_hostapd(local, 0, 0); + + for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { + if (local->frag_cache[i].skb != NULL) + dev_kfree_skb(local->frag_cache[i].skb); + } + +#ifdef PRISM2_DOWNLOAD_SUPPORT + prism2_download_free_data(local->dl_pri); + prism2_download_free_data(local->dl_sec); +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + + list_for_each_safe(ptr, n, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type == HOSTAP_INTERFACE_MAIN) { + /* special handling for this interface below */ + continue; + } + hostap_remove_interface(iface->dev, 0, 1); + } + +#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) + kfree(local->bus_m0_buf); +#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ + kfree(local->pda); + kfree(local->last_scan_results); + + unregister_netdev(local->dev); + free_netdev(local->dev); +} + + +/* These might at some point be compiled separately and used as separate + * kernel modules or linked into one */ +#ifdef PRISM2_DOWNLOAD_SUPPORT +#include "hostap_download.c" +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + +#ifdef PRISM2_CALLBACK +/* External hostap_callback.c file can be used to, e.g., blink activity led. + * This can use platform specific code and must define prism2_callback() + * function (if PRISM2_CALLBACK is not defined, these function calls are not + * used. */ +#include "hostap_callback.c" +#endif /* PRISM2_CALLBACK */ diff -Nru a/drivers/net/wireless/hostap_info.c b/drivers/net/wireless/hostap_info.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_info.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,476 @@ +/* Host AP driver Info Frame processing (part of hostap.o module) */ + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, + int left) +{ + struct hfa384x_comm_tallies *tallies; + + if (left < sizeof(struct hfa384x_comm_tallies)) { + printk(KERN_DEBUG "%s: too short (len=%d) commtallies " + "info frame\n", local->dev->name, left); + return; + } + + tallies = (struct hfa384x_comm_tallies *) buf; +#define ADD_COMM_TALLIES(name) \ +local->comm_tallies.name += le16_to_cpu(tallies->name) + ADD_COMM_TALLIES(tx_unicast_frames); + ADD_COMM_TALLIES(tx_multicast_frames); + ADD_COMM_TALLIES(tx_fragments); + ADD_COMM_TALLIES(tx_unicast_octets); + ADD_COMM_TALLIES(tx_multicast_octets); + ADD_COMM_TALLIES(tx_deferred_transmissions); + ADD_COMM_TALLIES(tx_single_retry_frames); + ADD_COMM_TALLIES(tx_multiple_retry_frames); + ADD_COMM_TALLIES(tx_retry_limit_exceeded); + ADD_COMM_TALLIES(tx_discards); + ADD_COMM_TALLIES(rx_unicast_frames); + ADD_COMM_TALLIES(rx_multicast_frames); + ADD_COMM_TALLIES(rx_fragments); + ADD_COMM_TALLIES(rx_unicast_octets); + ADD_COMM_TALLIES(rx_multicast_octets); + ADD_COMM_TALLIES(rx_fcs_errors); + ADD_COMM_TALLIES(rx_discards_no_buffer); + ADD_COMM_TALLIES(tx_discards_wrong_sa); + ADD_COMM_TALLIES(rx_discards_wep_undecryptable); + ADD_COMM_TALLIES(rx_message_in_msg_fragments); + ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); +#undef ADD_COMM_TALLIES +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, + int left) +{ + struct hfa384x_comm_tallies32 *tallies; + + if (left < sizeof(struct hfa384x_comm_tallies32)) { + printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " + "info frame\n", local->dev->name, left); + return; + } + + tallies = (struct hfa384x_comm_tallies32 *) buf; +#define ADD_COMM_TALLIES(name) \ +local->comm_tallies.name += le32_to_cpu(tallies->name) + ADD_COMM_TALLIES(tx_unicast_frames); + ADD_COMM_TALLIES(tx_multicast_frames); + ADD_COMM_TALLIES(tx_fragments); + ADD_COMM_TALLIES(tx_unicast_octets); + ADD_COMM_TALLIES(tx_multicast_octets); + ADD_COMM_TALLIES(tx_deferred_transmissions); + ADD_COMM_TALLIES(tx_single_retry_frames); + ADD_COMM_TALLIES(tx_multiple_retry_frames); + ADD_COMM_TALLIES(tx_retry_limit_exceeded); + ADD_COMM_TALLIES(tx_discards); + ADD_COMM_TALLIES(rx_unicast_frames); + ADD_COMM_TALLIES(rx_multicast_frames); + ADD_COMM_TALLIES(rx_fragments); + ADD_COMM_TALLIES(rx_unicast_octets); + ADD_COMM_TALLIES(rx_multicast_octets); + ADD_COMM_TALLIES(rx_fcs_errors); + ADD_COMM_TALLIES(rx_discards_no_buffer); + ADD_COMM_TALLIES(tx_discards_wrong_sa); + ADD_COMM_TALLIES(rx_discards_wep_undecryptable); + ADD_COMM_TALLIES(rx_message_in_msg_fragments); + ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); +#undef ADD_COMM_TALLIES +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, + int left) +{ + if (local->tallies32) + prism2_info_commtallies32(local, buf, left); + else + prism2_info_commtallies16(local, buf, left); +} + + +#ifndef PRISM2_NO_STATION_MODES +#ifndef PRISM2_NO_DEBUG +static const char* hfa384x_linkstatus_str(u16 linkstatus) +{ + switch (linkstatus) { + case HFA384X_LINKSTATUS_CONNECTED: + return "Connected"; + case HFA384X_LINKSTATUS_DISCONNECTED: + return "Disconnected"; + case HFA384X_LINKSTATUS_AP_CHANGE: + return "Access point change"; + case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: + return "Access point out of range"; + case HFA384X_LINKSTATUS_AP_IN_RANGE: + return "Access point in range"; + case HFA384X_LINKSTATUS_ASSOC_FAILED: + return "Association failed"; + default: + return "Unknown"; + } +} +#endif /* PRISM2_NO_DEBUG */ + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, + int left) +{ + u16 val; + int non_sta_mode; + + /* Alloc new JoinRequests to occur since LinkStatus for the previous + * has been received */ + local->last_join_time = 0; + + if (left != 2) { + printk(KERN_DEBUG "%s: invalid linkstatus info frame " + "length %d\n", local->dev->name, left); + return; + } + + non_sta_mode = local->iw_mode == IW_MODE_MASTER || + local->iw_mode == IW_MODE_REPEAT || + local->iw_mode == IW_MODE_MONITOR; + + val = buf[0] | (buf[1] << 8); + if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", + local->dev->name, val, hfa384x_linkstatus_str(val)); + } + + if (non_sta_mode) + return; + + /* Get current BSSID later in scheduled task */ + set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); + local->prev_link_status = val; + PRISM2_SCHEDULE_TASK(&local->info_queue); +} + + +static void prism2_host_roaming(local_info_t *local) +{ + struct hfa384x_join_request req; + struct net_device *dev = local->dev; + struct hfa384x_scan_result *selected, *entry; + int i; + unsigned long flags; + + if (local->last_join_time && + time_before(jiffies, local->last_join_time + 10 * HZ)) { + PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " + "completed - waiting for it before issuing new one\n", + dev->name); + return; + } + + /* ScanResults are sorted: first ESS results in decreasing signal + * quality then IBSS results in similar order. + * Trivial roaming policy: just select the first entry. + * This could probably be improved by adding hysteresis to limit + * number of handoffs, etc. + * + * Could do periodic RID_SCANREQUEST or Inquire F101 to get new + * ScanResults */ + spin_lock_irqsave(&local->lock, flags); + if (local->last_scan_results == NULL || + local->last_scan_results_count == 0) { + spin_unlock_irqrestore(&local->lock, flags); + PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", + dev->name); + return; + } + + selected = &local->last_scan_results[0]; + + if (local->preferred_ap[0] || local->preferred_ap[1] || + local->preferred_ap[2] || local->preferred_ap[3] || + local->preferred_ap[4] || local->preferred_ap[5]) { + /* Try to find preferred AP */ + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", + dev->name, MAC2STR(local->preferred_ap)); + for (i = 0; i < local->last_scan_results_count; i++) { + entry = &local->last_scan_results[i]; + if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) + { + PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " + "selection\n", dev->name); + selected = entry; + break; + } + } + } + + memcpy(req.bssid, selected->bssid, 6); + req.channel = selected->chid; + spin_unlock_irqrestore(&local->lock, flags); + + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", + dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); + if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, + sizeof(req))) { + printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); + } + local->last_join_time = jiffies; +} + + +#if WIRELESS_EXT > 13 +static void hostap_report_scan_complete(local_info_t *local) +{ + union iwreq_data wrqu; + + /* Inform user space about new scan results (just empty event, + * SIOCGIWSCAN can be used to fetch data */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); + + /* Allow SIOCGIWSCAN handling to occur since we have received + * scanning result */ + local->scan_timestamp = 0; +} +#else /* WIRELESS_EXT > 13 */ +static inline void hostap_report_scan_complete(local_info_t *local) +{ +} +#endif /* WIRELESS_EXT > 13 */ + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, + int left) +{ + u16 *pos; + int new_count; + unsigned long flags; + struct hfa384x_scan_result *results, *prev; + + if (left < 4) { + printk(KERN_DEBUG "%s: invalid scanresult info frame " + "length %d\n", local->dev->name, left); + return; + } + + pos = (u16 *) buf; + pos++; + pos++; + left -= 4; + + new_count = left / sizeof(struct hfa384x_scan_result); + results = kmalloc(new_count * sizeof(struct hfa384x_scan_result), + GFP_ATOMIC); + if (results == NULL) + return; + memcpy(results, pos, new_count * sizeof(struct hfa384x_scan_result)); + + spin_lock_irqsave(&local->lock, flags); + local->last_scan_type = PRISM2_SCAN; + prev = local->last_scan_results; + local->last_scan_results = results; + local->last_scan_results_count = new_count; + spin_unlock_irqrestore(&local->lock, flags); + kfree(prev); + + hostap_report_scan_complete(local); + + /* Perform rest of ScanResults handling later in scheduled task */ + set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); + PRISM2_SCHEDULE_TASK(&local->info_queue); +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_hostscanresults(local_info_t *local, + unsigned char *buf, int left) +{ + int i, result_size, copy_len, new_count; + struct hfa384x_hostscan_result *results, *prev; + unsigned long flags; + u16 *pos; + u8 *ptr; + + wake_up_interruptible(&local->hostscan_wq); + + if (left < 4) { + printk(KERN_DEBUG "%s: invalid hostscanresult info frame " + "length %d\n", local->dev->name, left); + return; + } + + pos = (u16 *) buf; + copy_len = result_size = le16_to_cpu(*pos); + if (result_size == 0) { + printk(KERN_DEBUG "%s: invalid result_size (0) in " + "hostscanresults\n", local->dev->name); + return; + } + if (copy_len > sizeof(struct hfa384x_hostscan_result)) + copy_len = sizeof(struct hfa384x_hostscan_result); + + pos++; + pos++; + left -= 4; + ptr = (u8 *) pos; + + new_count = left / result_size; + results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), + GFP_ATOMIC); + if (results == NULL) + return; + memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result)); + + for (i = 0; i < new_count; i++) { + memcpy(&results[i], ptr, copy_len); + ptr += result_size; + left -= result_size; + } + + if (left) { + printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", + local->dev->name, left, result_size); + } + + spin_lock_irqsave(&local->lock, flags); + local->last_scan_type = PRISM2_HOSTSCAN; + prev = local->last_hostscan_results; + local->last_hostscan_results = results; + local->last_hostscan_results_count = new_count; + spin_unlock_irqrestore(&local->lock, flags); + kfree(prev); + + hostap_report_scan_complete(local); +} +#endif /* PRISM2_NO_STATION_MODES */ + + +/* Called only as a tasklet (software IRQ) */ +void hostap_info_process(local_info_t *local, struct sk_buff *skb) +{ + struct hfa384x_info_frame *info; + unsigned char *buf; + int left; +#ifndef PRISM2_NO_DEBUG + int i; +#endif /* PRISM2_NO_DEBUG */ + + info = (struct hfa384x_info_frame *) skb->data; + buf = skb->data + sizeof(*info); + left = skb->len - sizeof(*info); + + switch (info->type) { + case HFA384X_INFO_COMMTALLIES: + prism2_info_commtallies(local, buf, left); + break; + +#ifndef PRISM2_NO_STATION_MODES + case HFA384X_INFO_LINKSTATUS: + prism2_info_linkstatus(local, buf, left); + break; + + case HFA384X_INFO_SCANRESULTS: + prism2_info_scanresults(local, buf, left); + break; + + case HFA384X_INFO_HOSTSCANRESULTS: + prism2_info_hostscanresults(local, buf, left); + break; +#endif /* PRISM2_NO_STATION_MODES */ + +#ifndef PRISM2_NO_DEBUG + default: + PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", + local->dev->name, info->len, info->type); + PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); + for (i = 0; i < (left < 100 ? left : 100); i++) + PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); + PDEBUG2(DEBUG_EXTRA, "\n"); + break; +#endif /* PRISM2_NO_DEBUG */ + } +} + + +#ifndef PRISM2_NO_STATION_MODES +static void handle_info_queue_linkstatus(local_info_t *local) +{ + int val = local->prev_link_status; + int connected; + + connected = + val == HFA384X_LINKSTATUS_CONNECTED || + val == HFA384X_LINKSTATUS_AP_CHANGE || + val == HFA384X_LINKSTATUS_AP_IN_RANGE; + + if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, + local->bssid, ETH_ALEN, 1) < 0) { + printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " + "LinkStatus event\n", local->dev->name); + } else { + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", + local->dev->name, + MAC2STR((unsigned char *) local->bssid)); + if (local->wds_type & HOSTAP_WDS_AP_CLIENT) + hostap_add_sta(local->ap, local->bssid); + } + +#if WIRELESS_EXT > 13 + { + union iwreq_data wrqu; + + /* Get BSSID if we have a valid AP address */ + if (connected) + memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); + else + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); + } +#endif /* WIRELESS_EXT > 13 */ +} + + +static void handle_info_queue_scanresults(local_info_t *local) +{ + if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) + prism2_host_roaming(local); +} + + +/* Called only as scheduled task after receiving info frames (used to avoid + * pending too much time in HW IRQ handler). */ +static void handle_info_queue(void *data) +{ + local_info_t *local = (local_info_t *) data; + + if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, + &local->pending_info)) + handle_info_queue_linkstatus(local); + + if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, + &local->pending_info)) + handle_info_queue_scanresults(local); + +#ifndef NEW_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif +} +#endif /* PRISM2_NO_STATION_MODES */ + + +void hostap_info_init(local_info_t *local) +{ + skb_queue_head_init(&local->info_list); +#ifndef PRISM2_NO_STATION_MODES + INIT_WORK(&local->info_queue, handle_info_queue, local); +#endif /* PRISM2_NO_STATION_MODES */ +} + + +EXPORT_SYMBOL(hostap_info_init); +EXPORT_SYMBOL(hostap_info_process); diff -Nru a/drivers/net/wireless/hostap_ioctl.c b/drivers/net/wireless/hostap_ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_ioctl.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3688 @@ +/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ + +#ifdef WIRELESS_EXT + +#ifdef in_atomic +/* Get kernel_locked() for in_atomic() */ +#include +#endif + + +static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + local->wstats.status = 0; + local->wstats.discard.code = + local->comm_tallies.rx_discards_wep_undecryptable; + local->wstats.discard.misc = + local->comm_tallies.rx_fcs_errors + + local->comm_tallies.rx_discards_no_buffer + + local->comm_tallies.tx_discards_wrong_sa; + +#if WIRELESS_EXT > 11 + local->wstats.discard.retries = + local->comm_tallies.tx_retry_limit_exceeded; + local->wstats.discard.fragment = + local->comm_tallies.rx_message_in_bad_msg_fragments; +#endif /* WIRELESS_EXT > 11 */ + + if (local->iw_mode != IW_MODE_MASTER && + local->iw_mode != IW_MODE_REPEAT) { + struct hfa384x_comms_quality sq; +#ifdef in_atomic + /* FIX: get_rid() will sleep and it must not be called + * in interrupt context or while atomic. However, this + * function seems to be called while atomic (at least in Linux + * 2.5.59). Now, we just avoid illegal call, but in this case + * the signal quality values are not shown. Statistics could be + * collected before, if this really needs to be called while + * atomic. */ + if (in_atomic()) { + printk(KERN_DEBUG "%s: hostap_get_wireless_stats() " + "called while atomic - skipping signal " + "quality query\n", dev->name); + } else +#endif /* in_atomic */ + if (local->func->get_rid(local->dev, + HFA384X_RID_COMMSQUALITY, + &sq, sizeof(sq), 1) >= 0) { + local->wstats.qual.qual = le16_to_cpu(sq.comm_qual); + local->wstats.qual.level = HFA384X_LEVEL_TO_dBm( + le16_to_cpu(sq.signal_level)); + local->wstats.qual.noise = HFA384X_LEVEL_TO_dBm( + le16_to_cpu(sq.noise_level)); + local->wstats.qual.updated = 7; + } + } + + return &local->wstats; +} + + +static int prism2_get_datarates(struct net_device *dev, u8 *rates) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u8 buf[12]; + int len; + u16 val; + + len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, + sizeof(buf), 0); + if (len < 2) + return 0; + + val = le16_to_cpu(*(u16 *) buf); /* string length */ + + if (len - 2 < val || val > 10) + return 0; + + memcpy(rates, buf + 2, val); + return val; +} + + +static int prism2_get_name(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + u8 rates[10]; + int len, i, over2 = 0; + + len = prism2_get_datarates(dev, rates); + + for (i = 0; i < len; i++) { + if (rates[i] == 0x0b || rates[i] == 0x16) { + over2 = 1; + break; + } + } + + strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); + + return 0; +} + + +static void prism2_crypt_delayed_deinit(local_info_t *local, + struct prism2_crypt_data **crypt) +{ + struct prism2_crypt_data *tmp; + unsigned long flags; + + tmp = *crypt; + *crypt = NULL; + + if (tmp == NULL) + return; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(&local->lock, flags); + list_add(&tmp->list, &local->crypt_deinit_list); + if (!timer_pending(&local->crypt_deinit_timer)) { + local->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&local->crypt_deinit_timer); + } + spin_unlock_irqrestore(&local->lock, flags); +} + + +static int prism2_ioctl_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int i; + int first = 0; + + if (erq->flags & IW_ENCODE_DISABLED) { + prism2_crypt_delayed_deinit(local, &local->crypt); + goto done; + } + + if (local->crypt != NULL && local->crypt->ops != NULL && + strcmp(local->crypt->ops->name, "WEP") != 0) { + /* changing to use WEP; deinit previously used algorithm */ + prism2_crypt_delayed_deinit(local, &local->crypt); + } + + if (local->crypt == NULL) { + struct prism2_crypt_data *new_crypt; + + /* take WEP into use */ + new_crypt = (struct prism2_crypt_data *) + kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); + if (new_crypt == NULL) + return -ENOMEM; + memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); + new_crypt->ops = hostap_get_crypto_ops("WEP"); + if (!new_crypt->ops) { + request_module("hostap_crypt_wep"); + new_crypt->ops = hostap_get_crypto_ops("WEP"); + } + if (new_crypt->ops) + new_crypt->priv = new_crypt->ops->init(); + if (!new_crypt->ops || !new_crypt->priv) { + kfree(new_crypt); + new_crypt = NULL; + + printk(KERN_WARNING "%s: could not initialize WEP: " + "load module hostap_crypt_wep.o\n", + dev->name); + return -EOPNOTSUPP; + } + first = 1; + local->crypt = new_crypt; + } + + i = erq->flags & IW_ENCODE_INDEX; + if (i < 1 || i > 4) + i = local->crypt->ops->get_key_idx(local->crypt->priv); + else + i--; + if (i < 0 || i >= WEP_KEYS) + return -EINVAL; + + if (erq->length > 0) { + int len = erq->length <= 5 ? 5 : 13; + if (len > erq->length) + memset(keybuf + erq->length, 0, len - erq->length); + local->crypt->ops->set_key(i, keybuf, len, local->crypt->priv); + if (first) + local->crypt->ops->set_key_idx(i, local->crypt->priv); + } else { + if (local->crypt->ops->set_key_idx(i, local->crypt->priv) < 0) + return -EINVAL; /* keyidx not valid */ + } + + done: + local->open_wep = erq->flags & IW_ENCODE_OPEN; + + if (hostap_set_encryption(local)) { + printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); + return -EINVAL; + } + + /* Do not reset port0 if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. Prism2 documentation seem to require port reset + * after WEP configuration. However, keys are apparently changed at + * least in Managed mode. */ + if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { + printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); + return -EINVAL; + } + + return 0; +} + + +static int prism2_ioctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int i, len; + u16 val; + + if (local->crypt == NULL || local->crypt->ops == NULL) { + erq->length = 0; + erq->flags = IW_ENCODE_DISABLED; + return 0; + } + + if (strcmp(local->crypt->ops->name, "WEP") != 0) { + /* only WEP is supported with wireless extensions, so just + * report that encryption is used */ + erq->length = 0; + erq->flags = IW_ENCODE_ENABLED; + return 0; + } + + i = erq->flags & IW_ENCODE_INDEX; + if (i < 1 || i > 4) + i = local->crypt->ops->get_key_idx(local->crypt->priv); + else + i--; + if (i < 0 || i >= WEP_KEYS) + return -EINVAL; + + erq->flags = i + 1; + + /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show + * the keys from driver buffer */ + len = local->crypt->ops->get_key(i, key, WEP_KEY_LEN, + local->crypt->priv); + erq->length = (len >= 0 ? len : 0); + + if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) + { + printk("CNFWEPFLAGS reading failed\n"); + return -EOPNOTSUPP; + } + le16_to_cpus(&val); + if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) + erq->flags |= IW_ENCODE_ENABLED; + else + erq->flags |= IW_ENCODE_DISABLED; + if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + + return 0; +} + + +#if WIRELESS_EXT <= 15 +static int prism2_ioctl_giwspy(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *srq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct sockaddr addr[IW_MAX_SPY]; + struct iw_quality qual[IW_MAX_SPY]; + + if (local->iw_mode != IW_MODE_MASTER) { + printk("SIOCGIWSPY is currently only supported in Host AP " + "mode\n"); + srq->length = 0; + return -EOPNOTSUPP; + } + + srq->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_SPY, 0); + + memcpy(extra, &addr, sizeof(addr[0]) * srq->length); + memcpy(extra + sizeof(addr[0]) * srq->length, &qual, + sizeof(qual[0]) * srq->length); + + return 0; +} +#endif /* WIRELESS_EXT <= 15 */ + + +static int hostap_set_rate(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret, basic_rates; + + basic_rates = local->basic_rates & local->tx_rate_control; + if (!basic_rates || basic_rates != local->basic_rates) { + printk(KERN_INFO "%s: updating basic rate set automatically " + "to match with the new supported rate set\n", + dev->name); + if (!basic_rates) + basic_rates = local->tx_rate_control; + + local->basic_rates = basic_rates; + if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, + basic_rates)) + printk(KERN_WARNING "%s: failed to set " + "cnfBasicRates\n", dev->name); + } + + ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, + local->tx_rate_control) || + hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, + local->tx_rate_control) || + local->func->reset_port(dev)); + + if (ret) { + printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " + "setting to 0x%x failed\n", + dev->name, local->tx_rate_control); + } + + /* Update TX rate configuration for all STAs based on new operational + * rate set. */ + hostap_update_rates(local); + + return ret; +} + + +static int prism2_ioctl_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (rrq->fixed) { + switch (rrq->value) { + case 11000000: + local->tx_rate_control = HFA384X_RATES_11MBPS; + break; + case 5500000: + local->tx_rate_control = HFA384X_RATES_5MBPS; + break; + case 2000000: + local->tx_rate_control = HFA384X_RATES_2MBPS; + break; + case 1000000: + local->tx_rate_control = HFA384X_RATES_1MBPS; + break; + default: + local->tx_rate_control = HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | + HFA384X_RATES_11MBPS; + break; + } + } else { + switch (rrq->value) { + case 11000000: + local->tx_rate_control = HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | + HFA384X_RATES_11MBPS; + break; + case 5500000: + local->tx_rate_control = HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; + break; + case 2000000: + local->tx_rate_control = HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS; + break; + case 1000000: + local->tx_rate_control = HFA384X_RATES_1MBPS; + break; + default: + local->tx_rate_control = HFA384X_RATES_1MBPS | + HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | + HFA384X_RATES_11MBPS; + break; + } + } + + return hostap_set_rate(dev); +} + + +static int prism2_ioctl_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + u16 val; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret = 0; + + if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < + 0) + return -EINVAL; + + if ((val & 0x1) && (val > 1)) + rrq->fixed = 0; + else + rrq->fixed = 1; + + if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && + !local->fw_tx_rate_control) { + /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in + * Host AP mode, so use the recorded TX rate of the last sent + * frame */ + rrq->value = local->ap->last_tx_rate > 0 ? + local->ap->last_tx_rate * 100000 : 11000000; + return 0; + } + + if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < + 0) + return -EINVAL; + + switch (val) { + case HFA384X_RATES_1MBPS: + rrq->value = 1000000; + break; + case HFA384X_RATES_2MBPS: + rrq->value = 2000000; + break; + case HFA384X_RATES_5MBPS: + rrq->value = 5500000; + break; + case HFA384X_RATES_11MBPS: + rrq->value = 11000000; + break; + default: + /* should not happen */ + rrq->value = 11000000; + ret = -EINVAL; + break; + } + + return ret; +} + + +static int prism2_ioctl_siwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *sens, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + /* Set the desired AP density */ + if (sens->value < 1 || sens->value > 3) + return -EINVAL; + + if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || + local->func->reset_port(dev)) + return -EINVAL; + + return 0; +} + +static int prism2_ioctl_giwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *sens, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + /* Get the current AP density */ + if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < + 0) + return -EINVAL; + + sens->value = __le16_to_cpu(val); + sens->fixed = 1; + + return 0; +} + + +/* Deprecated in new wireless extension API */ +static int prism2_ioctl_giwaplist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct sockaddr addr[IW_MAX_AP]; + struct iw_quality qual[IW_MAX_AP]; + + if (local->iw_mode != IW_MODE_MASTER) { + printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " + "in Host AP mode\n"); + data->length = 0; + return -EOPNOTSUPP; + } + + data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); + + memcpy(extra, &addr, sizeof(addr[0]) * data->length); + data->flags = 1; /* has quality information */ + memcpy(extra + sizeof(addr[0]) * data->length, &qual, + sizeof(qual[0]) * data->length); + + return 0; +} + + +static int prism2_ioctl_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + if (rts->disabled) + val = __constant_cpu_to_le16(2347); + else if (rts->value < 0 || rts->value > 2347) + return -EINVAL; + else + val = __cpu_to_le16(rts->value); + + if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || + local->func->reset_port(dev)) + return -EINVAL; + + local->rts_threshold = rts->value; + + return 0; +} + +static int prism2_ioctl_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < + 0) + return -EINVAL; + + rts->value = __le16_to_cpu(val); + rts->disabled = (rts->value == 2347); + rts->fixed = 1; + + return 0; +} + + +static int prism2_ioctl_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + if (rts->disabled) + val = __constant_cpu_to_le16(2346); + else if (rts->value < 256 || rts->value > 2346) + return -EINVAL; + else + val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ + + if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, + 2) + || local->func->reset_port(dev)) + return -EINVAL; + + local->fragm_threshold = rts->value & ~0x1; + + return 0; +} + +static int prism2_ioctl_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, + &val, 2, 1) < 0) + return -EINVAL; + + rts->value = __le16_to_cpu(val); + rts->disabled = (rts->value == 2346); + rts->fixed = 1; + + return 0; +} + + +static int hostap_join_ap(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_join_request req; + unsigned long flags; + int i; + struct hfa384x_scan_result *entry; + + memcpy(req.bssid, local->preferred_ap, ETH_ALEN); + req.channel = 0; + + spin_lock_irqsave(&local->lock, flags); + for (i = 0; i < local->last_scan_results_count; i++) { + if (!local->last_scan_results) + break; + entry = &local->last_scan_results[i]; + if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) { + req.channel = entry->chid; + break; + } + } + spin_unlock_irqrestore(&local->lock, flags); + + if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, + sizeof(req))) { + printk(KERN_DEBUG "%s: JoinRequest " MACSTR + " failed\n", + dev->name, MAC2STR(local->preferred_ap)); + return -1; + } + + printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", + dev->name, MAC2STR(local->preferred_ap)); + + return 0; +} + + +static int prism2_ioctl_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ +#ifdef PRISM2_NO_STATION_MODES + return -EOPNOTSUPP; +#else /* PRISM2_NO_STATION_MODES */ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); + + if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { + struct hfa384x_scan_request scan_req; + memset(&scan_req, 0, sizeof(scan_req)); + scan_req.channel_list = __constant_cpu_to_le16(0x3fff); + scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); + if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, + &scan_req, sizeof(scan_req))) { + printk(KERN_DEBUG "%s: ScanResults request failed - " + "preferred AP delayed to next unsolicited " + "scan\n", dev->name); + } + } else if (local->host_roaming == 2 && + local->iw_mode == IW_MODE_INFRA) { + if (hostap_join_ap(dev)) + return -EINVAL; + } else { + printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " + "in Managed mode when host_roaming is enabled\n", + dev->name); + } + + return 0; +#endif /* PRISM2_NO_STATION_MODES */ +} + +static int prism2_ioctl_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (dev == local->stadev) { + memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); + ap_addr->sa_family = ARPHRD_ETHER; + return 0; + } + + if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, + &ap_addr->sa_data, ETH_ALEN, 1) < 0) + return -EOPNOTSUPP; + + /* local->bssid is also updated in LinkStatus handler when in station + * mode */ + memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); + ap_addr->sa_family = ARPHRD_ETHER; + + return 0; +} + + +static int prism2_ioctl_siwnickn(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *nickname) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + memset(local->name, 0, sizeof(local->name)); + memcpy(local->name, nickname, data->length); + local->name_set = 1; + + if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || + local->func->reset_port(dev)) + return -EINVAL; + + return 0; +} + +static int prism2_ioctl_giwnickn(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *nickname) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int len; + char name[MAX_NAME_LEN + 3]; + u16 val; + + len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, + &name, MAX_NAME_LEN + 2, 0); + val = __le16_to_cpu(*(u16 *) name); + if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) + return -EOPNOTSUPP; + + name[val + 2] = '\0'; + data->length = val + 1; + memcpy(nickname, name + 2, val + 1); + + return 0; +} + + +static int prism2_ioctl_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + /* freq => chan. */ + if (freq->e == 1 && + freq->m / 100000 >= freq_list[0] && + freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { + int ch; + int fr = freq->m / 100000; + for (ch = 0; ch < FREQ_COUNT; ch++) { + if (fr == freq_list[ch]) { + freq->e = 0; + freq->m = ch + 1; + break; + } + } + } + + if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || + !(local->channel_mask & (1 << (freq->m - 1)))) + return -EINVAL; + + local->channel = freq->m; /* channel is used in prism2_setup_rids() */ + if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || + local->func->reset_port(dev)) + return -EINVAL; + + return 0; +} + +static int prism2_ioctl_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < + 0) + return -EINVAL; + + le16_to_cpus(&val); + if (val < 1 || val > FREQ_COUNT) + return -EINVAL; + + freq->m = freq_list[val - 1] * 100000; + freq->e = 1; + + return 0; +} + + +static void hostap_monitor_set_type(local_info_t *local) +{ + struct net_device *dev = local->dev; + + if (local->monitor_type == PRISM2_MONITOR_PRISM || + local->monitor_type == PRISM2_MONITOR_CAPHDR) { + dev->type = ARPHRD_IEEE80211_PRISM; + dev->hard_header_parse = + hostap_80211_prism_header_parse; + } else { + dev->type = ARPHRD_IEEE80211; + dev->hard_header_parse = hostap_80211_header_parse; + } +} + + +static int prism2_ioctl_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (data->flags == 0) + ssid[0] = '\0'; /* ANY */ + + if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { + /* Setting SSID to empty string seems to kill the card in + * Host AP mode */ + printk(KERN_DEBUG "%s: Host AP mode does not support " + "'Any' essid\n", dev->name); + return -EINVAL; + } + + memcpy(local->essid, ssid, data->length); + local->essid[data->length] = '\0'; + + if ((!local->fw_ap && + hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) + || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || + local->func->reset_port(dev)) + return -EINVAL; + + return 0; +} + +static int prism2_ioctl_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 val; + + data->flags = 1; /* active */ + if (local->iw_mode == IW_MODE_MASTER) { + data->length = strlen(local->essid); + memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); + } else { + int len; + char ssid[MAX_SSID_LEN + 2]; + memset(ssid, 0, sizeof(ssid)); + len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, + &ssid, MAX_SSID_LEN + 2, 0); + val = __le16_to_cpu(*(u16 *) ssid); + if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { + return -EOPNOTSUPP; + } + data->length = val; + memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); + } + + return 0; +} + + +static int prism2_ioctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct iw_range *range = (struct iw_range *) extra; + u8 rates[10]; + u16 val; + int i, len, over2; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + +#if WIRELESS_EXT > 9 + /* TODO: could fill num_txpower and txpower array with + * something; however, there are 128 different values.. */ + + range->txpower_capa = IW_TXPOW_DBM; + + if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) + { + range->min_pmp = 1 * 1024; + range->max_pmp = 65535 * 1024; + range->min_pmt = 1 * 1024; + range->max_pmt = 1000 * 1024; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | + IW_POWER_UNICAST_R | IW_POWER_ALL_R; + } +#endif /* WIRELESS_EXT > 9 */ + +#if WIRELESS_EXT > 10 + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 13; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; +#endif /* WIRELESS_EXT > 10 */ + + range->num_channels = FREQ_COUNT; + + val = 0; + for (i = 0; i < FREQ_COUNT; i++) { + if (local->channel_mask & (1 << i)) { + range->freq[val].i = i + 1; + range->freq[val].m = freq_list[i] * 100000; + range->freq[val].e = 1; + val++; + } + if (val == IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = val; + + range->max_qual.qual = 92; /* 0 .. 92 */ + range->max_qual.level = 154; /* 27 .. 154 */ + range->max_qual.noise = 154; /* 27 .. 154 */ + range->sensitivity = 3; + + range->max_encoding_tokens = WEP_KEYS; + range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + + over2 = 0; + len = prism2_get_datarates(dev, rates); + range->num_bitrates = 0; + for (i = 0; i < len; i++) { + if (range->num_bitrates < IW_MAX_BITRATES) { + range->bitrate[range->num_bitrates] = + rates[i] * 500000; + range->num_bitrates++; + } + if (rates[i] == 0x0b || rates[i] == 0x16) + over2 = 1; + } + /* estimated maximum TCP throughput values (bps) */ + range->throughput = over2 ? 5500000 : 1500000; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + return 0; +} + + +static int hostap_monitor_mode_enable(local_info_t *local) +{ + struct net_device *dev = local->dev; + + printk(KERN_DEBUG "Enabling monitor mode\n"); + hostap_monitor_set_type(local); + + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, + HFA384X_PORTTYPE_PSEUDO_IBSS)) { + printk(KERN_DEBUG "Port type setting for monitor mode " + "failed\n"); + return -EOPNOTSUPP; + } + + /* Host decrypt is needed to get the IV and ICV fields; + * however, monitor mode seems to remove WEP flag from frame + * control field */ + if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, + HFA384X_WEPFLAGS_HOSTENCRYPT | + HFA384X_WEPFLAGS_HOSTDECRYPT)) { + printk(KERN_DEBUG "WEP flags setting failed\n"); + return -EOPNOTSUPP; + } + + if (local->func->reset_port(dev) || + local->func->cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_MONITOR << 8), + 0, NULL, NULL)) { + printk(KERN_DEBUG "Setting monitor mode failed\n"); + return -EOPNOTSUPP; + } + + return 0; +} + + +static int hostap_monitor_mode_disable(local_info_t *local) +{ + struct net_device *dev = local->dev; + + printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); + dev->type = ARPHRD_ETHER; + dev->hard_header_parse = local->saved_eth_header_parse; + if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_STOP << 8), + 0, NULL, NULL)) + return -1; + return hostap_set_encryption(local); +} + + +static int prism2_ioctl_siwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int double_reset = 0; + + if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && + *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && + *mode != IW_MODE_MONITOR) + return -EOPNOTSUPP; + +#ifdef PRISM2_NO_STATION_MODES + if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) + return -EOPNOTSUPP; +#endif /* PRISM2_NO_STATION_MODES */ + + if (*mode == local->iw_mode) + return 0; + + if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { + printk(KERN_WARNING "%s: empty SSID not allowed in Master " + "mode\n", dev->name); + return -EINVAL; + } + + if (local->iw_mode == IW_MODE_MONITOR) + hostap_monitor_mode_disable(local); + + if (local->iw_mode == IW_MODE_ADHOC && *mode == IW_MODE_MASTER) { + /* There seems to be a firmware bug in at least STA f/w v1.5.6 + * that leaves beacon frames to use IBSS type when moving from + * IBSS to Host AP mode. Doing double Port0 reset seems to be + * enough to workaround this. */ + double_reset = 1; + } + + printk(KERN_DEBUG "prism2: %s: operating mode changed " + "%d -> %d\n", dev->name, local->iw_mode, *mode); + local->iw_mode = *mode; + + if (local->iw_mode == IW_MODE_MONITOR) + hostap_monitor_mode_enable(local); + else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && + !local->fw_encrypt_ok) { + printk(KERN_DEBUG "%s: defaulting to host-based encryption as " + "a workaround for firmware bug in Host AP mode WEP\n", + dev->name); + local->host_encrypt = 1; + } + + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, + hostap_get_porttype(local))) + return -EOPNOTSUPP; + + if (local->func->reset_port(dev)) + return -EINVAL; + if (double_reset && local->func->reset_port(dev)) + return -EINVAL; + + return 0; +} + + +static int prism2_ioctl_giwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (dev == local->stadev) { + *mode = IW_MODE_INFRA; + return 0; + } + + *mode = local->iw_mode; + return 0; +} + + +static int prism2_ioctl_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ +#ifdef PRISM2_NO_STATION_MODES + return -EOPNOTSUPP; +#else /* PRISM2_NO_STATION_MODES */ + int ret = 0; + + if (wrq->disabled) + return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); + + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); + if (ret) + return ret; + ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); + if (ret) + return ret; + break; + case IW_POWER_ALL_R: + ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); + if (ret) + return ret; + ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); + if (ret) + return ret; + break; + case IW_POWER_ON: + break; + default: + return -EINVAL; + } + + if (wrq->flags & IW_POWER_TIMEOUT) { + ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); + if (ret) + return ret; + ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, + wrq->value / 1024); + if (ret) + return ret; + } + if (wrq->flags & IW_POWER_PERIOD) { + ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); + if (ret) + return ret; + ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, + wrq->value / 1024); + if (ret) + return ret; + } + + return ret; +#endif /* PRISM2_NO_STATION_MODES */ +} + + +static int prism2_ioctl_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ +#ifdef PRISM2_NO_STATION_MODES + return -EOPNOTSUPP; +#else /* PRISM2_NO_STATION_MODES */ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 enable, mcast; + + if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) + < 0) + return -EINVAL; + + if (!__le16_to_cpu(enable)) { + rrq->disabled = 1; + return 0; + } + + rrq->disabled = 0; + + if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + u16 timeout; + if (local->func->get_rid(dev, + HFA384X_RID_CNFPMHOLDOVERDURATION, + &timeout, 2, 1) < 0) + return -EINVAL; + + rrq->flags = IW_POWER_TIMEOUT; + rrq->value = __le16_to_cpu(timeout) * 1024; + } else { + u16 period; + if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, + &period, 2, 1) < 0) + return -EINVAL; + + rrq->flags = IW_POWER_PERIOD; + rrq->value = __le16_to_cpu(period) * 1024; + } + + if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, + 2, 1) < 0) + return -EINVAL; + + if (__le16_to_cpu(mcast)) + rrq->flags |= IW_POWER_ALL_R; + else + rrq->flags |= IW_POWER_UNICAST_R; + + return 0; +#endif /* PRISM2_NO_STATION_MODES */ +} + + +#if WIRELESS_EXT > 10 +static int prism2_ioctl_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (rrq->disabled) + return -EINVAL; + + /* setting retry limits is not supported with the current station + * firmware code; simulate this with alternative retry count for now */ + if (rrq->flags == IW_RETRY_LIMIT) { + if (rrq->value < 0) { + /* disable manual retry count setting and use firmware + * defaults */ + local->manual_retry_count = -1; + local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; + } else { + if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, + rrq->value)) { + printk(KERN_DEBUG "%s: Alternate retry count " + "setting to %d failed\n", + dev->name, rrq->value); + return -EOPNOTSUPP; + } + + local->manual_retry_count = rrq->value; + local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; + } + return 0; + } + + return -EOPNOTSUPP; + +#if 0 + /* what could be done, if firmware would support this.. */ + + if (rrq->flags & IW_RETRY_LIMIT) { + if (rrq->flags & IW_RETRY_MAX) + HFA384X_RID_LONGRETRYLIMIT = rrq->value; + else if (rrq->flags & IW_RETRY_MIN) + HFA384X_RID_SHORTRETRYLIMIT = rrq->value; + else { + HFA384X_RID_LONGRETRYLIMIT = rrq->value; + HFA384X_RID_SHORTRETRYLIMIT = rrq->value; + } + + } + + if (rrq->flags & IW_RETRY_LIFETIME) { + HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; + } + + return 0; +#endif /* 0 */ +} + +static int prism2_ioctl_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 shortretry, longretry, lifetime; + + if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, + 2, 1) < 0 || + local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, + 2, 1) < 0 || + local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, + &lifetime, 2, 1) < 0) + return -EINVAL; + + le16_to_cpus(&shortretry); + le16_to_cpus(&longretry); + le16_to_cpus(&lifetime); + + rrq->disabled = 0; + + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1024; + } else { + if (local->manual_retry_count >= 0) { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = local->manual_retry_count; + } else if ((rrq->flags & IW_RETRY_MAX)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + rrq->value = longretry; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = shortretry; + if (shortretry != longretry) + rrq->flags |= IW_RETRY_MIN; + } + } + return 0; +} +#endif /* WIRELESS_EXT > 10 */ + + +#if WIRELESS_EXT > 9 + +/* Note! This TX power controlling is experimental and should not be used in + * production use. It just sets raw power register and does not use any kind of + * feedback information from the measured TX power (CR58). This is now + * commented out to make sure that it is not used by accident. TX power + * configuration will be enabled again after proper algorithm using feedback + * has been implemented. */ + +#ifdef RAW_TXPOWER_SETTING +/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. + * This version assumes following mapping: + * CR31 is 7-bit value with -64 to +63 range. + * -64 is mapped into +20dBm and +63 into -43dBm. + * This is certainly not an exact mapping for every card, but at least + * increasing dBm value should correspond to increasing TX power. + */ + +static int prism2_txpower_hfa386x_to_dBm(u16 val) +{ + signed char tmp; + + if (val > 255) + val = 255; + + tmp = val; + tmp >>= 2; + + return -12 - tmp; +} + +static u16 prism2_txpower_dBm_to_hfa386x(int val) +{ + signed char tmp; + + if (val > 20) + return 128; + else if (val < -43) + return 127; + + tmp = val; + tmp = -12 - tmp; + tmp <<= 2; + + return (unsigned char) tmp; +} +#endif /* RAW_TXPOWER_SETTING */ + + +static int prism2_ioctl_siwtxpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; +#ifdef RAW_TXPOWER_SETTING + char *tmp; +#endif + u16 val; + int ret = 0; + + if (rrq->disabled) { + 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); + printk(KERN_DEBUG "%s: Turning radio off: %s\n", + dev->name, ret ? "failed" : "OK"); + local->txpower_type = PRISM2_TXPOWER_OFF; + } + return (ret ? -EOPNOTSUPP : 0); + } + + if (local->txpower_type == PRISM2_TXPOWER_OFF) { + val = 0; /* disable all standby and sleep modes */ + ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_A_D_TEST_MODES2, &val, NULL); + printk(KERN_DEBUG "%s: Turning radio on: %s\n", + dev->name, ret ? "failed" : "OK"); + local->txpower_type = PRISM2_TXPOWER_UNKNOWN; + } + +#ifdef RAW_TXPOWER_SETTING + if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { + printk(KERN_DEBUG "Setting ALC on\n"); + val = HFA384X_TEST_CFG_BIT_ALC; + local->func->cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); + local->txpower_type = PRISM2_TXPOWER_AUTO; + return 0; + } + + if (local->txpower_type != PRISM2_TXPOWER_FIXED) { + printk(KERN_DEBUG "Setting ALC off\n"); + val = HFA384X_TEST_CFG_BIT_ALC; + local->func->cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); + local->txpower_type = PRISM2_TXPOWER_FIXED; + } + + if (rrq->flags == IW_TXPOW_DBM) + tmp = "dBm"; + else if (rrq->flags == IW_TXPOW_MWATT) + tmp = "mW"; + else + tmp = "UNKNOWN"; + printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); + + if (rrq->flags != IW_TXPOW_DBM) { + printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); + return -EOPNOTSUPP; + } + + local->txpower = rrq->value; + val = prism2_txpower_dBm_to_hfa386x(local->txpower); + if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) + ret = -EOPNOTSUPP; +#else /* RAW_TXPOWER_SETTING */ + if (rrq->fixed) + ret = -EOPNOTSUPP; +#endif /* RAW_TXPOWER_SETTING */ + + return ret; +} + +static int prism2_ioctl_giwtxpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ +#ifdef RAW_TXPOWER_SETTING + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 resp0; + + rrq->flags = IW_TXPOW_DBM; + rrq->disabled = 0; + rrq->fixed = 0; + + if (local->txpower_type == PRISM2_TXPOWER_AUTO) { + if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, + HFA386X_CR_MANUAL_TX_POWER, + NULL, &resp0) == 0) { + rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); + } else { + /* Could not get real txpower; guess 15 dBm */ + rrq->value = 15; + } + } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { + rrq->value = 0; + rrq->disabled = 1; + } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { + rrq->value = local->txpower; + rrq->fixed = 1; + } else { + printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", + local->txpower_type); + } + return 0; +#else /* RAW_TXPOWER_SETTING */ + return -EOPNOTSUPP; +#endif /* RAW_TXPOWER_SETTING */ +} +#endif /* WIRELESS_EXT > 9 */ + + +#if WIRELESS_EXT > 13 + +#ifndef PRISM2_NO_STATION_MODES + +/* HostScan request works with and without host_roaming mode. In addition, it + * does not break current association. However, it requires newer station + * firmware version (>= 1.3.1) than scan request. */ +static int prism2_request_hostscan(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_hostscan_request scan_req; + + memset(&scan_req, 0, sizeof(scan_req)); + scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask); + scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); + /* leave target_ssid empty so that all SSIDs are accepted */ + + if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, + sizeof(scan_req))) { + printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); + return -EINVAL; + } + return 0; +} + + +static int prism2_request_scan(struct net_device *dev) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + struct hfa384x_scan_request scan_req; + int ret = 0; + + memset(&scan_req, 0, sizeof(scan_req)); + scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask); + scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); + + /* FIX: + * It seems to be enough to set roaming mode for a short moment to + * host-based and then setup scanrequest data and return the mode to + * firmware-based. + * + * Master mode would need to drop to Managed mode for a short while + * to make scanning work.. Or sweep through the different channels and + * use passive scan based on beacons. */ + + if (!local->host_roaming) + hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, + HFA384X_ROAMING_HOST); + + if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, + sizeof(scan_req))) { + printk(KERN_DEBUG "SCANREQUEST failed\n"); + ret = -EINVAL; + } + + if (!local->host_roaming) + hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, + HFA384X_ROAMING_FIRMWARE); + + return 0; +} + +#else /* !PRISM2_NO_STATION_MODES */ + +static inline int prism2_request_hostscan(struct net_device *dev) +{ + return -EOPNOTSUPP; +} + + +static inline int prism2_request_scan(struct net_device *dev) +{ + return -EOPNOTSUPP; +} + +#endif /* !PRISM2_NO_STATION_MODES */ + + +static int prism2_ioctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret; + + if (local->iw_mode == IW_MODE_MASTER) { + /* In master mode, we just return the results of our local + * tables, so we don't need to start anything... + * Jean II */ + data->length = 0; + return 0; + } + + if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) + ret = prism2_request_hostscan(dev); + else + ret = prism2_request_scan(dev); + + if (ret == 0) + local->scan_timestamp = jiffies; + + /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ + + return ret; +} + + +#ifndef PRISM2_NO_STATION_MODES +/* Translate scan data returned from the card to a card independant + * format that the Wireless Tools will understand - Jean II */ +static inline int prism2_translate_scan(local_info_t *local, char *buffer) +{ + struct hfa384x_scan_result *scan; + struct hfa384x_hostscan_result *hscan; + int i, entries, entry, hostscan; + struct iw_event iwe; + char *current_ev = buffer; + char *end_buf = buffer + IW_SCAN_MAX_DATA; + char *current_val; + u16 capabilities; + u8 *pos; + + spin_lock_bh(&local->lock); + + hostscan = local->last_scan_type == PRISM2_HOSTSCAN; + entries = hostscan ? local->last_hostscan_results_count : + local->last_scan_results_count; + for (entry = 0; entry < entries; entry++) { + scan = &local->last_scan_results[entry]; + hscan = &local->last_hostscan_results[entry]; + + /* First entry *MUST* be the AP MAC address */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, + hostscan ? hscan->bssid : scan->bssid, ETH_ALEN); + /* FIX: + * I do not know how this is possible, but iwe_stream_add_event + * seems to re-order memcpy execution so that len is set only + * after copying.. Pre-setting len here "fixes" this, but real + * problems should be solved (after which these iwe.len + * settings could be removed from this function). */ + iwe.len = IW_EV_ADDR_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = le16_to_cpu(hostscan ? hscan->ssid_len : + scan->ssid_len); + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.u.data.flags = 1; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + hostscan ? hscan->ssid : + scan->ssid); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + capabilities = le16_to_cpu(hostscan ? hscan->capability : + scan->capability); + if (capabilities & (WLAN_CAPABILITY_ESS | + WLAN_CAPABILITY_IBSS)) { + if (capabilities & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + iwe.len = IW_EV_UINT_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, + &iwe, + IW_EV_UINT_LEN); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = freq_list[le16_to_cpu(hostscan ? hscan->chid : + scan->chid) - 1] * 100000; + iwe.u.freq.e = 1; + iwe.len = IW_EV_FREQ_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + if (hostscan) { + iwe.u.qual.level = le16_to_cpu(hscan->sl); + iwe.u.qual.noise = le16_to_cpu(hscan->anl); + } else { + iwe.u.qual.level = HFA384X_LEVEL_TO_dBm( + le16_to_cpu(scan->sl)); + iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm( + le16_to_cpu(scan->anl)); + } + iwe.len = IW_EV_QUAL_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_QUAL_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (capabilities & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + ""); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + current_val = current_ev + IW_EV_LCP_LEN; + pos = hostscan ? hscan->sup_rates : scan->sup_rates; + for (i = 0; i < sizeof(scan->sup_rates); i++) { + if (pos[i] == 0) + break; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = + ((pos[i] & 0x7f) * 500000); + current_val = iwe_stream_add_value( + current_ev, current_val, end_buf, &iwe, + IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if ((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + +#if WIRELESS_EXT > 14 + { + char buf[20]; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "bcn_int=%d", + le16_to_cpu(hostscan ? hscan->beacon_interval : + scan->beacon_interval)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "resp_rate=%d", + le16_to_cpu(hostscan ? hscan->rate : + scan->rate)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + + if (hostscan && (capabilities & WLAN_CAPABILITY_IBSS)) + { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "atim=%d", + le16_to_cpu(hscan->atim)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point( + current_ev, end_buf, &iwe, buf); + } + } +#endif /* WIRELESS_EXT > 14 */ + + + /* Could add beacon_interval and rate (of the received + * ProbeResp) to scan results. With hostscan, could also add + * ATIM. */ + } + + spin_unlock_bh(&local->lock); + + return current_ev - buffer; +} +#endif /* PRISM2_NO_STATION_MODES */ + + +static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ +#ifdef PRISM2_NO_STATION_MODES + return -EOPNOTSUPP; +#else /* PRISM2_NO_STATION_MODES */ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res; + + /* Wait until the scan is finished. We can probably do better + * than that - Jean II */ + if (local->scan_timestamp && + time_before(jiffies, local->scan_timestamp + 3 * HZ)) { + /* Important note : we don't want to block the caller + * until results are ready for various reasons. + * First, managing wait queues is complex and racy + * (there may be multiple simultaneous callers). + * Second, we grab some rtnetlink lock before comming + * here (in dev_ioctl()). + * Third, the caller can wait on the Wireless Event + * - Jean II */ + return -EAGAIN; + } + local->scan_timestamp = 0; + + res = prism2_translate_scan(local, extra); + + if (res >= 0) { + data->length = res; + return 0; + } else { + data->length = 0; + return res; + } +#endif /* PRISM2_NO_STATION_MODES */ +} + + +static int prism2_ioctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int res; + + if (local->iw_mode == IW_MODE_MASTER) { + /* In MASTER mode, it doesn't make sense to go around + * scanning the frequencies and make the stations we serve + * wait when what the user is really interested about is the + * list of stations and access points we are talking to. + * So, just extract results from our cache... + * Jean II */ + + /* Translate to WE format */ + res = prism2_ap_translate_scan(dev, extra); + if (res >= 0) { + printk(KERN_DEBUG "Scan result translation succeeded " + "(length=%d)\n", res); + data->length = res; + return 0; + } else { + printk(KERN_DEBUG + "Scan result translation failed (res=%d)\n", + res); + data->length = 0; + return res; + } + } else { + /* Station mode */ + return prism2_ioctl_giwscan_sta(dev, info, data, extra); + } +} +#endif /* WIRELESS_EXT > 13 */ + + +static const struct iw_priv_args prism2_priv[] = { + { PRISM2_IOCTL_MONITOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, + { PRISM2_IOCTL_READMIF, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, + { PRISM2_IOCTL_WRITEMIF, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, + { PRISM2_IOCTL_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, + { PRISM2_IOCTL_INQUIRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, + { PRISM2_IOCTL_SET_RID_WORD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, + { PRISM2_IOCTL_MACCMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, +#ifdef PRISM2_USE_WE_TYPE_ADDR + { PRISM2_IOCTL_WDS_ADD, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, + { PRISM2_IOCTL_WDS_DEL, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, + { PRISM2_IOCTL_ADDMAC, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, + { PRISM2_IOCTL_DELMAC, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, + { PRISM2_IOCTL_KICKMAC, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, +#else /* PRISM2_USE_WE_TYPE_ADDR */ + { PRISM2_IOCTL_WDS_ADD, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "wds_add" }, + { PRISM2_IOCTL_WDS_DEL, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "wds_del" }, + { PRISM2_IOCTL_ADDMAC, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "addmac" }, + { PRISM2_IOCTL_DELMAC, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "delmac" }, + { PRISM2_IOCTL_KICKMAC, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 18, 0, "kickmac" }, +#endif /* PRISM2_USE_WE_TYPE_ADDR */ + /* --- raw access to sub-ioctls --- */ + { PRISM2_IOCTL_PRISM2_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, +#if WIRELESS_EXT >= 12 + { PRISM2_IOCTL_GET_PRISM2_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, +#ifdef PRISM2_USE_WE_SUB_IOCTLS + /* --- sub-ioctls handlers --- */ + { PRISM2_IOCTL_PRISM2_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, + { PRISM2_IOCTL_GET_PRISM2_PARAM, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, + /* --- sub-ioctls definitions --- */ + { PRISM2_PARAM_PTYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ptype" }, + { PRISM2_PARAM_PTYPE, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getptype" }, + { PRISM2_PARAM_TXRATECTRL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, + { PRISM2_PARAM_TXRATECTRL, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, + { PRISM2_PARAM_BEACON_INT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, + { PRISM2_PARAM_BEACON_INT, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, +#ifndef PRISM2_NO_STATION_MODES + { PRISM2_PARAM_PSEUDO_IBSS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, + { PRISM2_PARAM_PSEUDO_IBSS, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, +#endif /* PRISM2_NO_STATION_MODES */ + { PRISM2_PARAM_ALC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, + { PRISM2_PARAM_ALC, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, + { PRISM2_PARAM_TXPOWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txpower" }, + { PRISM2_PARAM_TXPOWER, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getxpower" }, + { PRISM2_PARAM_DUMP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, + { PRISM2_PARAM_DUMP, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, + { PRISM2_PARAM_OTHER_AP_POLICY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, + { PRISM2_PARAM_OTHER_AP_POLICY, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, + { PRISM2_PARAM_AP_MAX_INACTIVITY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, + { PRISM2_PARAM_AP_MAX_INACTIVITY, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, + { PRISM2_PARAM_AP_BRIDGE_PACKETS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, + { PRISM2_PARAM_AP_BRIDGE_PACKETS, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, + { PRISM2_PARAM_DTIM_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, + { PRISM2_PARAM_DTIM_PERIOD, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, + { PRISM2_PARAM_AP_NULLFUNC_ACK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, + { PRISM2_PARAM_AP_NULLFUNC_ACK, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, + { PRISM2_PARAM_MAX_WDS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, + { PRISM2_PARAM_MAX_WDS, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, + { PRISM2_PARAM_AP_AUTOM_AP_WDS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, + { PRISM2_PARAM_AP_AUTOM_AP_WDS, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, + { PRISM2_PARAM_AP_AUTH_ALGS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, + { PRISM2_PARAM_AP_AUTH_ALGS, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, + { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, + { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, + { PRISM2_PARAM_HOST_ENCRYPT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, + { PRISM2_PARAM_HOST_ENCRYPT, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, + { PRISM2_PARAM_HOST_DECRYPT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, + { PRISM2_PARAM_HOST_DECRYPT, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, + { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_rx" }, + { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_rx" }, + { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_tx" }, + { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_tx" }, +#ifndef PRISM2_NO_STATION_MODES + { PRISM2_PARAM_HOST_ROAMING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, + { PRISM2_PARAM_HOST_ROAMING, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, +#endif /* PRISM2_NO_STATION_MODES */ + { PRISM2_PARAM_BCRX_STA_KEY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, + { PRISM2_PARAM_BCRX_STA_KEY, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, + { PRISM2_PARAM_IEEE_802_1X, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, + { PRISM2_PARAM_IEEE_802_1X, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, + { PRISM2_PARAM_ANTSEL_TX, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, + { PRISM2_PARAM_ANTSEL_TX, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, + { PRISM2_PARAM_ANTSEL_RX, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, + { PRISM2_PARAM_ANTSEL_RX, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, + { PRISM2_PARAM_MONITOR_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, + { PRISM2_PARAM_MONITOR_TYPE, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, + { PRISM2_PARAM_WDS_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, + { PRISM2_PARAM_WDS_TYPE, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, + { PRISM2_PARAM_HOSTSCAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, + { PRISM2_PARAM_HOSTSCAN, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, + { PRISM2_PARAM_AP_SCAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, + { PRISM2_PARAM_AP_SCAN, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, + { PRISM2_PARAM_ENH_SEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, + { PRISM2_PARAM_ENH_SEC, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, +#ifdef PRISM2_IO_DEBUG + { PRISM2_PARAM_IO_DEBUG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, + { PRISM2_PARAM_IO_DEBUG, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, +#endif /* PRISM2_IO_DEBUG */ + { PRISM2_PARAM_BASIC_RATES, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, + { PRISM2_PARAM_BASIC_RATES, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, + { PRISM2_PARAM_OPER_RATES, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, + { PRISM2_PARAM_OPER_RATES, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, + { PRISM2_PARAM_HOSTAPD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, + { PRISM2_PARAM_HOSTAPD, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, +#endif /* PRISM2_USE_WE_SUB_IOCTLS */ +#endif /* WIRELESS_EXT >= 12 */ +}; + + +#if WIRELESS_EXT <= 12 +static int prism2_ioctl_giwpriv(struct net_device *dev, struct iw_point *data) +{ + + if (!data->pointer || + verify_area(VERIFY_WRITE, data->pointer, sizeof(prism2_priv))) + return -EINVAL; + + data->length = sizeof(prism2_priv) / sizeof(prism2_priv[0]); + if (copy_to_user(data->pointer, prism2_priv, sizeof(prism2_priv))) + return -EINVAL; + return 0; +} +#endif /* WIRELESS_EXT <= 12 */ + + +static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL)) + return -EOPNOTSUPP; + + return 0; +} + + +static int prism2_ioctl_priv_prism2_param(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int *i = (int *) extra; + int param = *i; + int value = *(i + 1); + int ret = 0; + u16 val; + + switch (param) { + case PRISM2_PARAM_PTYPE: + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, value)) { + ret = -EOPNOTSUPP; + break; + } + + if (local->func->reset_port(dev)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_TXRATECTRL: + local->fw_tx_rate_control = value; + break; + + case PRISM2_PARAM_BEACON_INT: + if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || + local->func->reset_port(dev)) + ret = -EINVAL; + else + local->beacon_int = value; + break; + +#ifndef PRISM2_NO_STATION_MODES + case PRISM2_PARAM_PSEUDO_IBSS: + if (value == local->pseudo_adhoc) + break; + + if (value != 0 && value != 1) { + ret = -EINVAL; + break; + } + + printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", + dev->name, local->pseudo_adhoc, value); + local->pseudo_adhoc = value; + if (local->iw_mode != IW_MODE_ADHOC) + break; + + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, + hostap_get_porttype(local))) { + ret = -EOPNOTSUPP; + break; + } + + if (local->func->reset_port(dev)) + ret = -EINVAL; + break; +#endif /* PRISM2_NO_STATION_MODES */ + + case PRISM2_PARAM_ALC: + printk(KERN_DEBUG "%s: %s ALC\n", dev->name, + value == 0 ? "Disabling" : "Enabling"); + val = HFA384X_TEST_CFG_BIT_ALC; + local->func->cmd(dev, HFA384X_CMDCODE_TEST | + (HFA384X_TEST_CFG_BITS << 8), + value == 0 ? 0 : 1, &val, NULL); + break; + + case PRISM2_PARAM_TXPOWER: + val = value; + if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, + HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_DUMP: + local->frame_dump = value; + break; + + case PRISM2_PARAM_OTHER_AP_POLICY: + if (value < 0 || value > 3) { + ret = -EINVAL; + break; + } + if (local->ap != NULL) + local->ap->ap_policy = value; + break; + + case PRISM2_PARAM_AP_MAX_INACTIVITY: + if (value < 0 || value > 7 * 24 * 60 * 60) { + ret = -EINVAL; + break; + } + if (local->ap != NULL) + local->ap->max_inactivity = value * HZ; + break; + + case PRISM2_PARAM_AP_BRIDGE_PACKETS: + if (local->ap != NULL) + local->ap->bridge_packets = value; + break; + + case PRISM2_PARAM_DTIM_PERIOD: + if (value < 0 || value > 65535) { + ret = -EINVAL; + break; + } + if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) + || local->func->reset_port(dev)) + ret = -EINVAL; + else + local->dtim_period = value; + break; + + case PRISM2_PARAM_AP_NULLFUNC_ACK: + if (local->ap != NULL) + local->ap->nullfunc_ack = value; + break; + + case PRISM2_PARAM_MAX_WDS: + local->wds_max_connections = value; + break; + + case PRISM2_PARAM_AP_AUTOM_AP_WDS: + if (local->ap != NULL) { + if (!local->ap->autom_ap_wds && value) { + /* add WDS link to all APs in STA table */ + hostap_add_wds_links(local); + } + local->ap->autom_ap_wds = value; + } + break; + + case PRISM2_PARAM_AP_AUTH_ALGS: + local->auth_algs = value; + if (hostap_set_auth_algs(local)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: + local->monitor_allow_fcserr = value; + break; + + case PRISM2_PARAM_HOST_ENCRYPT: + local->host_encrypt = value; + if (hostap_set_encryption(local) || + local->func->reset_port(dev)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_HOST_DECRYPT: + local->host_decrypt = value; + if (hostap_set_encryption(local) || + local->func->reset_port(dev)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX: + local->bus_master_threshold_rx = value; + break; + + case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX: + local->bus_master_threshold_tx = value; + break; + +#ifndef PRISM2_NO_STATION_MODES + case PRISM2_PARAM_HOST_ROAMING: + if (value < 0 || value > 2) { + ret = -EINVAL; + break; + } + local->host_roaming = value; + if (hostap_set_roaming(local) || local->func->reset_port(dev)) + ret = -EINVAL; + break; +#endif /* PRISM2_NO_STATION_MODES */ + + case PRISM2_PARAM_BCRX_STA_KEY: + local->bcrx_sta_key = value; + break; + + case PRISM2_PARAM_IEEE_802_1X: + local->ieee_802_1x = value; + break; + + case PRISM2_PARAM_ANTSEL_TX: + if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { + ret = -EINVAL; + break; + } + local->antsel_tx = value; + hostap_set_antsel(local); + break; + + case PRISM2_PARAM_ANTSEL_RX: + if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { + ret = -EINVAL; + break; + } + local->antsel_rx = value; + hostap_set_antsel(local); + break; + + case PRISM2_PARAM_MONITOR_TYPE: + if (value != PRISM2_MONITOR_80211 && + value != PRISM2_MONITOR_CAPHDR && + value != PRISM2_MONITOR_PRISM) { + ret = -EINVAL; + break; + } + local->monitor_type = value; + if (local->iw_mode == IW_MODE_MONITOR) + hostap_monitor_set_type(local); + break; + + case PRISM2_PARAM_WDS_TYPE: + local->wds_type = value; + break; + + case PRISM2_PARAM_HOSTSCAN: + { + struct hfa384x_hostscan_request scan_req; + u16 rate; + + memset(&scan_req, 0, sizeof(scan_req)); + scan_req.channel_list = __constant_cpu_to_le16(0x3fff); + switch (value) { + case 1: rate = HFA384X_RATES_1MBPS; break; + case 2: rate = HFA384X_RATES_2MBPS; break; + case 3: rate = HFA384X_RATES_5MBPS; break; + case 4: rate = HFA384X_RATES_11MBPS; break; + default: rate = HFA384X_RATES_1MBPS; break; + } + scan_req.txrate = cpu_to_le16(rate); + /* leave SSID empty to accept all SSIDs */ + + if (local->iw_mode == IW_MODE_MASTER) { + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, + HFA384X_PORTTYPE_BSS) || + local->func->reset_port(dev)) + printk(KERN_DEBUG "Leaving Host AP mode " + "for HostScan failed\n"); + } + + if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, + sizeof(scan_req))) { + printk(KERN_DEBUG "HOSTSCAN failed\n"); + ret = -EINVAL; + } + if (local->iw_mode == IW_MODE_MASTER) { + wait_queue_t __wait; + init_waitqueue_entry(&__wait, current); + add_wait_queue(&local->hostscan_wq, &__wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + if (signal_pending(current)) + ret = -EINTR; + set_current_state(TASK_RUNNING); + remove_wait_queue(&local->hostscan_wq, &__wait); + + if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, + HFA384X_PORTTYPE_HOSTAP) || + local->func->reset_port(dev)) + printk(KERN_DEBUG "Returning to Host AP mode " + "after HostScan failed\n"); + } + break; + } + + case PRISM2_PARAM_AP_SCAN: + local->passive_scan_interval = value; + if (timer_pending(&local->passive_scan_timer)) + del_timer(&local->passive_scan_timer); + if (value > 0) { + local->passive_scan_timer.expires = jiffies + + local->passive_scan_interval * HZ; + add_timer(&local->passive_scan_timer); + } + break; + + case PRISM2_PARAM_ENH_SEC: + if (value < 0 || value > 3) { + ret = -EINVAL; + break; + } + local->enh_sec = value; + if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, + local->enh_sec) || + local->func->reset_port(dev)) { + printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " + "1.6.3 or newer\n", dev->name); + ret = -EOPNOTSUPP; + } + break; + +#ifdef PRISM2_IO_DEBUG + case PRISM2_PARAM_IO_DEBUG: + local->io_debug_enabled = value; + break; +#endif /* PRISM2_IO_DEBUG */ + + case PRISM2_PARAM_BASIC_RATES: + if ((value & local->tx_rate_control) != value || value == 0) { + printk(KERN_INFO "%s: invalid basic rate set - basic " + "rates must be in supported rate set\n", + dev->name); + ret = -EINVAL; + break; + } + local->basic_rates = value; + if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, + local->basic_rates) || + local->func->reset_port(dev)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_OPER_RATES: + local->tx_rate_control = value; + if (hostap_set_rate(dev)) + ret = -EINVAL; + break; + + case PRISM2_PARAM_HOSTAPD: + ret = hostap_set_hostapd(local, value, 1); + break; + + default: + printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", + dev->name, param); + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + + +#if WIRELESS_EXT >= 12 +static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int *param = (int *) extra; + int ret = 0; + u16 val; + + switch (*param) { + case PRISM2_PARAM_PTYPE: + if (local->func->get_rid(dev, HFA384X_RID_CNFPORTTYPE, + &val, 2, 1) < 0) + ret = -EINVAL; + else + *param = le16_to_cpu(val); + break; + + case PRISM2_PARAM_TXRATECTRL: + *param = local->fw_tx_rate_control; + break; + + case PRISM2_PARAM_BEACON_INT: + *param = local->beacon_int; + break; + + case PRISM2_PARAM_PSEUDO_IBSS: + *param = local->pseudo_adhoc; + break; + + case PRISM2_PARAM_ALC: + ret = -EOPNOTSUPP; /* FIX */ + break; + + case PRISM2_PARAM_TXPOWER: + if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, + HFA386X_CR_MANUAL_TX_POWER, NULL, &val)) + ret = -EOPNOTSUPP; + *param = val; + break; + + case PRISM2_PARAM_DUMP: + *param = local->frame_dump; + break; + + case PRISM2_PARAM_OTHER_AP_POLICY: + if (local->ap != NULL) + *param = local->ap->ap_policy; + else + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_AP_MAX_INACTIVITY: + if (local->ap != NULL) + *param = local->ap->max_inactivity / HZ; + else + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_AP_BRIDGE_PACKETS: + if (local->ap != NULL) + *param = local->ap->bridge_packets; + else + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_DTIM_PERIOD: + *param = local->dtim_period; + break; + + case PRISM2_PARAM_AP_NULLFUNC_ACK: + if (local->ap != NULL) + *param = local->ap->nullfunc_ack; + else + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_MAX_WDS: + *param = local->wds_max_connections; + break; + + case PRISM2_PARAM_AP_AUTOM_AP_WDS: + if (local->ap != NULL) + *param = local->ap->autom_ap_wds; + else + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_AP_AUTH_ALGS: + *param = local->auth_algs; + break; + + case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: + *param = local->monitor_allow_fcserr; + break; + + case PRISM2_PARAM_HOST_ENCRYPT: + *param = local->host_encrypt; + break; + + case PRISM2_PARAM_HOST_DECRYPT: + *param = local->host_decrypt; + break; + + case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX: + *param = local->bus_master_threshold_rx; + break; + + case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX: + *param = local->bus_master_threshold_tx; + break; + + case PRISM2_PARAM_HOST_ROAMING: + *param = local->host_roaming; + break; + + case PRISM2_PARAM_BCRX_STA_KEY: + *param = local->bcrx_sta_key; + break; + + case PRISM2_PARAM_IEEE_802_1X: + *param = local->ieee_802_1x; + break; + + case PRISM2_PARAM_ANTSEL_TX: + *param = local->antsel_tx; + break; + + case PRISM2_PARAM_ANTSEL_RX: + *param = local->antsel_rx; + break; + + case PRISM2_PARAM_MONITOR_TYPE: + *param = local->monitor_type; + break; + + case PRISM2_PARAM_WDS_TYPE: + *param = local->wds_type; + break; + + case PRISM2_PARAM_HOSTSCAN: + ret = -EOPNOTSUPP; + break; + + case PRISM2_PARAM_AP_SCAN: + *param = local->passive_scan_interval; + break; + + case PRISM2_PARAM_ENH_SEC: + *param = local->enh_sec; + break; + +#ifdef PRISM2_IO_DEBUG + case PRISM2_PARAM_IO_DEBUG: + *param = local->io_debug_enabled; + break; +#endif /* PRISM2_IO_DEBUG */ + + case PRISM2_PARAM_BASIC_RATES: + *param = local->basic_rates; + break; + + case PRISM2_PARAM_OPER_RATES: + *param = local->tx_rate_control; + break; + + case PRISM2_PARAM_HOSTAPD: + *param = local->hostapd; + break; + + default: + printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", + dev->name, *param); + ret = -EOPNOTSUPP; + break; + } + + return ret; +} +#endif /* WIRELESS_EXT >= 12 */ + + +static int prism2_ioctl_priv_readmif(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 resp0; + + if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, + &resp0)) + return -EOPNOTSUPP; + else + *extra = resp0; + + return 0; +} + + +static int prism2_ioctl_priv_writemif(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, char *extra) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u16 cr, val; + + cr = *extra; + val = *(extra + 1); + if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) + return -EOPNOTSUPP; + + return 0; +} + + +static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret = 0; + u32 mode; + + printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor " + "- update software to use iwconfig mode monitor\n", + dev->name, current->pid, current->comm); + + /* Backward compatibility code - this can be removed at some point */ + + if (*i == 0) { + /* Disable monitor mode - old mode was not saved, so go to + * Master mode */ + mode = IW_MODE_MASTER; + ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); + } else if (*i == 1) { + /* netlink socket mode is not supported anymore since it did + * not separate different devices from each other and was not + * best method for delivering large amount of packets to + * user space */ + ret = -EOPNOTSUPP; + } else if (*i == 2 || *i == 3) { + switch (*i) { + case 2: + local->monitor_type = PRISM2_MONITOR_80211; + break; + case 3: + local->monitor_type = PRISM2_MONITOR_PRISM; + break; + } + mode = IW_MODE_MONITOR; + ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); + hostap_monitor_mode_enable(local); + } else + ret = -EINVAL; + + return ret; +} + + +static int prism2_ioctl_priv_reset(struct net_device *dev, int *i) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i); + switch (*i) { + case 0: + /* Disable and enable card */ + local->func->hw_shutdown(dev, 1); + local->func->hw_config(dev, 0); + break; + + case 1: + /* COR sreset */ + local->func->hw_reset(dev); + break; + + case 2: + /* Disable and enable port 0 */ + local->func->reset_port(dev); + break; + + case 3: + if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, + NULL)) + return -EINVAL; + break; + + case 4: + if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, + NULL)) + return -EINVAL; + break; + + default: + printk(KERN_DEBUG "Unknown reset request %d\n", *i); + return -EOPNOTSUPP; + } + + return 0; +} + + +#ifndef PRISM2_USE_WE_TYPE_ADDR +static inline int hex2int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + return -1; +} + +static int macstr2addr(char *macstr, u8 *addr) +{ + int i, val, val2; + char *pos = macstr; + + for (i = 0; i < 6; i++) { + val = hex2int(*pos++); + if (val < 0) + return -1; + val2 = hex2int(*pos++); + if (val2 < 0) + return -1; + addr[i] = (val * 16 + val2) & 0xff; + + if (i < 5 && *pos++ != ':') + return -1; + } + + return 0; +} + + +static int prism2_ioctl_priv_wds(struct net_device *dev, int add, char *macstr) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + u8 addr[6]; + + if (macstr2addr(macstr, addr)) { + printk(KERN_DEBUG "Invalid MAC address\n"); + return -EINVAL; + } + + if (add) + return prism2_wds_add(local, addr, 1); + else + return prism2_wds_del(local, addr, 1, 0); +} +#endif /* PRISM2_USE_WE_TYPE_ADDR */ + + +static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i) +{ + int rid = *i; + int value = *(i + 1); + + printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value); + + if (hostap_set_word(dev, rid, value)) + return -EINVAL; + + return 0; +} + + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT +static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd) +{ + int ret = 0; + + switch (*cmd) { + case AP_MAC_CMD_POLICY_OPEN: + local->ap->mac_restrictions.policy = MAC_POLICY_OPEN; + break; + case AP_MAC_CMD_POLICY_ALLOW: + local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW; + break; + case AP_MAC_CMD_POLICY_DENY: + local->ap->mac_restrictions.policy = MAC_POLICY_DENY; + break; + case AP_MAC_CMD_FLUSH: + ap_control_flush_macs(&local->ap->mac_restrictions); + break; + case AP_MAC_CMD_KICKALL: + ap_control_kickall(local->ap); + hostap_deauth_all_stas(local->dev, local->ap, 0); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + + +enum { AP_CTRL_MAC_ADD, AP_CTRL_MAC_DEL, AP_CTRL_MAC_KICK }; + +#ifndef PRISM2_USE_WE_TYPE_ADDR +static int ap_mac_ioctl(local_info_t *local, char *macstr, int cmd) +{ + u8 addr[6]; + + if (macstr2addr(macstr, addr)) { + printk(KERN_DEBUG "Invalid MAC address '%s'\n", macstr); + return -EINVAL; + } + + switch (cmd) { + case AP_CTRL_MAC_ADD: + return ap_control_add_mac(&local->ap->mac_restrictions, addr); + case AP_CTRL_MAC_DEL: + return ap_control_del_mac(&local->ap->mac_restrictions, addr); + case AP_CTRL_MAC_KICK: + return ap_control_kick_mac(local->ap, local->dev, addr); + default: + return -EOPNOTSUPP; + } +} +#endif /* PRISM2_USE_WE_TYPE_ADDR */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + +#ifdef PRISM2_DOWNLOAD_SUPPORT +static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) +{ + struct prism2_download_param *param; + int ret = 0; + + if (p->length < sizeof(struct prism2_download_param) || + p->length > 1024 || !p->pointer) + return -EINVAL; + + param = (struct prism2_download_param *) + kmalloc(p->length, GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + ret = -EFAULT; + goto out; + } + + if (p->length < sizeof(struct prism2_download_param) + + param->num_areas * sizeof(struct prism2_download_area)) { + ret = -EINVAL; + goto out; + } + + ret = local->func->download(local, param); + + out: + if (param != NULL) + kfree(param); + + return ret; +} +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + + +static int prism2_ioctl_set_encryption(local_info_t *local, + struct prism2_hostapd_param *param, + int param_len) +{ + int ret = 0; + struct hostap_crypto_ops *ops; + struct prism2_crypt_data **crypt; + void *sta_ptr; + + param->u.crypt.err = 0; + param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len != + (int) ((char *) param->u.crypt.key - (char *) param) + + param->u.crypt.key_len) + return -EINVAL; + + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + sta_ptr = NULL; + crypt = &local->crypt; + } else { + sta_ptr = ap_crypt_get_ptrs( + local->ap, param->sta_addr, + (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), + &crypt); + + if (sta_ptr == NULL) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; + return -EINVAL; + } + } + + if (strcmp(param->u.crypt.alg, "none") == 0) { + prism2_crypt_delayed_deinit(local, crypt); + goto done; + } + + ops = hostap_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { + request_module("hostap_crypt_wep"); + ops = hostap_get_crypto_ops(param->u.crypt.alg); + } + if (ops == NULL) { + printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", + local->dev->name, param->u.crypt.alg); + param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; + ret = -EINVAL; + goto done; + } + + /* station based encryption and other than WEP algorithms require + * host-based encryption, so force them on automatically */ + local->host_decrypt = local->host_encrypt = 1; + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct prism2_crypt_data *new_crypt; + + prism2_crypt_delayed_deinit(local, crypt); + + new_crypt = (struct prism2_crypt_data *) + kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); + new_crypt->ops = ops; + new_crypt->priv = new_crypt->ops->init(); + if (new_crypt->priv == NULL) { + kfree(new_crypt); + param->u.crypt.err = + HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; + ret = -EINVAL; + goto done; + } + + *crypt = new_crypt; + } + + if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || + param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(param->u.crypt.idx, param->u.crypt.key, + param->u.crypt.key_len, (*crypt)->priv) < 0) { + printk(KERN_DEBUG "%s: key setting failed\n", + local->dev->name); + param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + if ((param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) && + (*crypt)->ops->set_key_idx && + (*crypt)->ops->set_key_idx(param->u.crypt.idx, (*crypt)->priv) < 0) + { + printk(KERN_DEBUG "%s: TX key idx setting failed\n", + local->dev->name); + param->u.crypt.err = HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + done: + if (sta_ptr) + hostap_handle_sta_release(sta_ptr); + + if (ret == 0 && + (hostap_set_encryption(local) || + local->func->reset_port(local->dev))) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; + return -EINVAL; + } + + return ret; +} + + +static int prism2_ioctl_get_encryption(local_info_t *local, + struct prism2_hostapd_param *param, + int param_len) +{ + struct prism2_crypt_data **crypt; + void *sta_ptr; + int max_key_len; + + param->u.crypt.err = 0; + + max_key_len = param_len - + (int) ((char *) param->u.crypt.key - (char *) param); + if (max_key_len < 0) + return -EINVAL; + + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + sta_ptr = NULL; + crypt = &local->crypt; + } else { + sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, + &crypt); + + if (sta_ptr == NULL) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; + return -EINVAL; + } + } + + if (*crypt == NULL || (*crypt)->ops == NULL) { + memcpy(param->u.crypt.alg, "none", 5); + param->u.crypt.key_len = 0; + param->u.crypt.idx = 0xff; + } else { + strncpy(param->u.crypt.alg, (*crypt)->ops->name, + HOSTAP_CRYPT_ALG_NAME_LEN); + param->u.crypt.key_len = 0; + if (param->u.crypt.idx >= WEP_KEYS && + (*crypt)->ops->get_key_idx) + param->u.crypt.idx = + (*crypt)->ops->get_key_idx((*crypt)->priv); + + if (param->u.crypt.idx < WEP_KEYS && (*crypt)->ops->get_key) + param->u.crypt.key_len = + (*crypt)->ops->get_key(param->u.crypt.idx, + param->u.crypt.key, + max_key_len, + (*crypt)->priv); + } + + if (sta_ptr) + hostap_handle_sta_release(sta_ptr); + + return 0; +} + + +static int prism2_ioctl_get_rid(local_info_t *local, + struct prism2_hostapd_param *param, + int param_len) +{ + int max_len, res; + + max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; + if (max_len < 0) + return -EINVAL; + + res = local->func->get_rid(local->dev, param->u.rid.rid, + param->u.rid.data, param->u.rid.len, 0); + if (res >= 0) { + param->u.rid.len = res; + return 0; + } + + return res; +} + + +static int prism2_ioctl_set_rid(local_info_t *local, + struct prism2_hostapd_param *param, + int param_len) +{ + int max_len; + + max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; + if (max_len < 0 || max_len < param->u.rid.len) + return -EINVAL; + + return local->func->set_rid(local->dev, param->u.rid.rid, + param->u.rid.data, param->u.rid.len); +} + + +static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, + struct prism2_hostapd_param *param, + int param_len) +{ + printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", + local->dev->name, MAC2STR(param->sta_addr)); + memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); + return 0; +} + + +static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) +{ + struct prism2_hostapd_param *param; + int ret = 0; + int ap_ioctl = 0; + + if (p->length < sizeof(struct prism2_hostapd_param) || + p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) + return -EINVAL; + + param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + ret = -EFAULT; + goto out; + } + + switch (param->cmd) { + case PRISM2_SET_ENCRYPTION: + ret = prism2_ioctl_set_encryption(local, param, p->length); + break; + case PRISM2_GET_ENCRYPTION: + ret = prism2_ioctl_get_encryption(local, param, p->length); + break; + case PRISM2_HOSTAPD_GET_RID: + ret = prism2_ioctl_get_rid(local, param, p->length); + break; + case PRISM2_HOSTAPD_SET_RID: + ret = prism2_ioctl_set_rid(local, param, p->length); + break; + case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: + ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); + break; + default: + ret = prism2_hostapd(local->ap, param); + ap_ioctl = 1; + break; + } + + if (ret == 1 || !ap_ioctl) { + if (copy_to_user(p->pointer, param, p->length)) { + ret = -EFAULT; + goto out; + } else if (ap_ioctl) + ret = 0; + } + + out: + if (param != NULL) + kfree(param); + + return ret; +} + + +#if WIRELESS_EXT > 12 +/* Structures to export the Wireless Handlers */ + +static const iw_handler prism2_handler[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) prism2_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) prism2_ioctl_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) prism2_ioctl_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) prism2_ioctl_siwmode, /* SIOCSIWMODE */ + (iw_handler) prism2_ioctl_giwmode, /* SIOCGIWMODE */ + (iw_handler) prism2_ioctl_siwsens, /* SIOCSIWSENS */ + (iw_handler) prism2_ioctl_giwsens, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) prism2_ioctl_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ +#if WIRELESS_EXT > 15 + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#else /* WIRELESS_EXT > 15 */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) prism2_ioctl_giwspy, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +#endif /* WIRELESS_EXT > 15 */ + (iw_handler) prism2_ioctl_siwap, /* SIOCSIWAP */ + (iw_handler) prism2_ioctl_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism2_ioctl_giwaplist, /* SIOCGIWAPLIST */ +#if WIRELESS_EXT > 13 + (iw_handler) prism2_ioctl_siwscan, /* SIOCSIWSCAN */ + (iw_handler) prism2_ioctl_giwscan, /* SIOCGIWSCAN */ +#else /* WIRELESS_EXT > 13 */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* WIRELESS_EXT > 13 */ + (iw_handler) prism2_ioctl_siwessid, /* SIOCSIWESSID */ + (iw_handler) prism2_ioctl_giwessid, /* SIOCGIWESSID */ + (iw_handler) prism2_ioctl_siwnickn, /* SIOCSIWNICKN */ + (iw_handler) prism2_ioctl_giwnickn, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism2_ioctl_siwrate, /* SIOCSIWRATE */ + (iw_handler) prism2_ioctl_giwrate, /* SIOCGIWRATE */ + (iw_handler) prism2_ioctl_siwrts, /* SIOCSIWRTS */ + (iw_handler) prism2_ioctl_giwrts, /* SIOCGIWRTS */ + (iw_handler) prism2_ioctl_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) prism2_ioctl_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) prism2_ioctl_siwtxpow, /* SIOCSIWTXPOW */ + (iw_handler) prism2_ioctl_giwtxpow, /* SIOCGIWTXPOW */ + (iw_handler) prism2_ioctl_siwretry, /* SIOCSIWRETRY */ + (iw_handler) prism2_ioctl_giwretry, /* SIOCGIWRETRY */ + (iw_handler) prism2_ioctl_siwencode, /* SIOCSIWENCODE */ + (iw_handler) prism2_ioctl_giwencode, /* SIOCGIWENCODE */ + (iw_handler) prism2_ioctl_siwpower, /* SIOCSIWPOWER */ + (iw_handler) prism2_ioctl_giwpower, /* SIOCGIWPOWER */ +}; + +static const iw_handler prism2_private_handler[] = +{ /* SIOCIWFIRSTPRIV + */ + (iw_handler) prism2_ioctl_priv_prism2_param, /* 0 */ + (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */ + (iw_handler) prism2_ioctl_priv_writemif, /* 2 */ + (iw_handler) prism2_ioctl_priv_readmif, /* 3 */ +}; + +static const struct iw_handler_def hostap_iw_handler_def = +{ + .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), + .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), + .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), + .standard = (iw_handler *) prism2_handler, + .private = (iw_handler *) prism2_private_handler, + .private_args = (struct iw_priv_args *) prism2_priv, +#if WIRELESS_EXT > 15 + .spy_offset = offsetof(struct hostap_interface, spy_data), +#endif /* WIRELESS_EXT > 15 */ +}; +#endif /* WIRELESS_EXT > 12 */ + + +int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct iwreq *wrq = (struct iwreq *) ifr; + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + int ret = 0; + + switch (cmd) { + +#if WIRELESS_EXT <= 12 + case SIOCGIWNAME: + ret = prism2_get_name(dev, NULL, (char *) &wrq->u, NULL); + break; + + case SIOCSIWFREQ: + ret = prism2_ioctl_siwfreq(dev, NULL, &wrq->u.freq, NULL); + break; + case SIOCGIWFREQ: + ret = prism2_ioctl_giwfreq(dev, NULL, &wrq->u.freq, NULL); + break; + + case SIOCSIWAP: + ret = prism2_ioctl_siwap(dev, NULL, &wrq->u.ap_addr, NULL); + break; + case SIOCGIWAP: + ret = prism2_ioctl_giwap(dev, NULL, &wrq->u.ap_addr, NULL); + break; + + case SIOCSIWESSID: + if (!wrq->u.essid.pointer) + ret = -EINVAL; + else if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) + ret = -E2BIG; + else { + char ssid[IW_ESSID_MAX_SIZE]; + if (copy_from_user(ssid, wrq->u.essid.pointer, + wrq->u.essid.length)) { + ret = -EFAULT; + break; + } + ret = prism2_ioctl_siwessid(dev, NULL, &wrq->u.essid, + ssid); + } + break; + case SIOCGIWESSID: + if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) + ret = -E2BIG; + else if (wrq->u.essid.pointer) { + char ssid[IW_ESSID_MAX_SIZE]; + ret = prism2_ioctl_giwessid(dev, NULL, &wrq->u.essid, + ssid); + if (copy_to_user(wrq->u.essid.pointer, ssid, + wrq->u.essid.length)) + ret = -EFAULT; + } + break; + + case SIOCSIWRATE: + ret = prism2_ioctl_siwrate(dev, NULL, &wrq->u.bitrate, NULL); + break; + case SIOCGIWRATE: + ret = prism2_ioctl_giwrate(dev, NULL, &wrq->u.bitrate, NULL); + break; + + case SIOCSIWRTS: + ret = prism2_ioctl_siwrts(dev, NULL, &wrq->u.rts, NULL); + break; + case SIOCGIWRTS: + ret = prism2_ioctl_giwrts(dev, NULL, &wrq->u.rts, NULL); + break; + + case SIOCSIWFRAG: + ret = prism2_ioctl_siwfrag(dev, NULL, &wrq->u.rts, NULL); + break; + case SIOCGIWFRAG: + ret = prism2_ioctl_giwfrag(dev, NULL, &wrq->u.rts, NULL); + break; + + case SIOCSIWENCODE: + { + char keybuf[WEP_KEY_LEN]; + if (wrq->u.encoding.pointer) { + if (wrq->u.encoding.length > WEP_KEY_LEN) { + ret = -E2BIG; + break; + } + if (copy_from_user(keybuf, + wrq->u.encoding.pointer, + wrq->u.encoding.length)) { + ret = -EFAULT; + break; + } + } else if (wrq->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + ret = prism2_ioctl_siwencode(dev, NULL, + &wrq->u.encoding, keybuf); + } + break; + case SIOCGIWENCODE: + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else if (wrq->u.encoding.pointer) { + char keybuf[WEP_KEY_LEN]; + ret = prism2_ioctl_giwencode(dev, NULL, + &wrq->u.encoding, keybuf); + if (copy_to_user(wrq->u.encoding.pointer, keybuf, + wrq->u.encoding.length)) + ret = -EFAULT; + } + break; + + case SIOCSIWNICKN: + if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) + ret = -E2BIG; + else if (wrq->u.essid.pointer) { + char nickbuf[IW_ESSID_MAX_SIZE + 1]; + if (copy_from_user(nickbuf, wrq->u.essid.pointer, + wrq->u.essid.length)) { + ret = -EFAULT; + break; + } + ret = prism2_ioctl_siwnickn(dev, NULL, &wrq->u.essid, + nickbuf); + } + break; + case SIOCGIWNICKN: + if (wrq->u.essid.pointer) { + char nickbuf[IW_ESSID_MAX_SIZE + 1]; + ret = prism2_ioctl_giwnickn(dev, NULL, &wrq->u.essid, + nickbuf); + if (copy_to_user(wrq->u.essid.pointer, nickbuf, + wrq->u.essid.length)) + ret = -EFAULT; + } + break; + + case SIOCGIWSPY: + { + char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) + + sizeof(struct iw_quality))]; + ret = prism2_ioctl_giwspy(dev, NULL, &wrq->u.data, + buffer); + if (ret == 0 && wrq->u.data.pointer && + copy_to_user(wrq->u.data.pointer, buffer, + wrq->u.data.length * + (sizeof(struct sockaddr) + + sizeof(struct iw_quality)))) + ret = -EFAULT; + } + break; + + case SIOCGIWRANGE: + { + struct iw_range range; + ret = prism2_ioctl_giwrange(dev, NULL, &wrq->u.data, + (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; + + case SIOCSIWSENS: + ret = prism2_ioctl_siwsens(dev, NULL, &wrq->u.sens, NULL); + break; + case SIOCGIWSENS: + ret = prism2_ioctl_giwsens(dev, NULL, &wrq->u.sens, NULL); + break; + + case SIOCGIWAPLIST: + if (wrq->u.data.pointer) { + char buffer[IW_MAX_AP * (sizeof(struct sockaddr) + + sizeof(struct iw_quality))]; + ret = prism2_ioctl_giwaplist(dev, NULL, &wrq->u.data, + buffer); + if (copy_to_user(wrq->u.data.pointer, buffer, + (wrq->u.data.length * + (sizeof(struct sockaddr) + + sizeof(struct iw_quality))))) + ret = -EFAULT; + } + break; + + case SIOCSIWMODE: + ret = prism2_ioctl_siwmode(dev, NULL, &wrq->u.mode, NULL); + break; + case SIOCGIWMODE: + ret = prism2_ioctl_giwmode(dev, NULL, &wrq->u.mode, NULL); + break; + + case SIOCSIWPOWER: + ret = prism2_ioctl_siwpower(dev, NULL, &wrq->u.power, NULL); + break; + case SIOCGIWPOWER: + ret = prism2_ioctl_giwpower(dev, NULL, &wrq->u.power, NULL); + break; + + case SIOCGIWPRIV: + ret = prism2_ioctl_giwpriv(dev, &wrq->u.data); + break; + +#if WIRELESS_EXT > 9 + case SIOCSIWTXPOW: + ret = prism2_ioctl_siwtxpow(dev, NULL, &wrq->u.txpower, NULL); + break; + case SIOCGIWTXPOW: + ret = prism2_ioctl_giwtxpow(dev, NULL, &wrq->u.txpower, NULL); + break; +#endif /* WIRELESS_EXT > 9 */ + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + ret = prism2_ioctl_siwretry(dev, NULL, &wrq->u.retry, NULL); + break; + case SIOCGIWRETRY: + ret = prism2_ioctl_giwretry(dev, NULL, &wrq->u.retry, NULL); + break; +#endif /* WIRELESS_EXT > 10 */ + + /* not supported wireless extensions */ + case SIOCSIWNWID: + case SIOCGIWNWID: + ret = -EOPNOTSUPP; + break; + + /* FIX: add support for this: */ + case SIOCSIWSPY: + printk(KERN_DEBUG "%s unsupported WIRELESS_EXT ioctl(0x%04x)\n" + , dev->name, cmd); + ret = -EOPNOTSUPP; + break; + + + /* Private ioctls (iwpriv); these are in SIOCDEVPRIVATE range + * if WIRELESS_EXT < 12, so better check privileges */ + + case PRISM2_IOCTL_PRISM2_PARAM: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_prism2_param(dev, NULL, &wrq->u, + (char *) &wrq->u); + break; +#if WIRELESS_EXT >= 12 + case PRISM2_IOCTL_GET_PRISM2_PARAM: + ret = prism2_ioctl_priv_get_prism2_param(dev, NULL, &wrq->u, + (char *) &wrq->u); + break; +#endif /* WIRELESS_EXT >= 12 */ + + case PRISM2_IOCTL_WRITEMIF: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_writemif(dev, NULL, &wrq->u, + (char *) &wrq->u); + break; + + case PRISM2_IOCTL_READMIF: + ret = prism2_ioctl_priv_readmif(dev, NULL, &wrq->u, + (char *) &wrq->u); + break; + +#endif /* WIRELESS_EXT <= 12 */ + + + /* Private ioctls (iwpriv) that have not yet been converted + * into new wireless extensions API */ + + case PRISM2_IOCTL_INQUIRE: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name); + break; + + case PRISM2_IOCTL_MONITOR: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name); + break; + + case PRISM2_IOCTL_RESET: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name); + break; + +#ifdef PRISM2_USE_WE_TYPE_ADDR + case PRISM2_IOCTL_WDS_ADD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1); + break; + + case PRISM2_IOCTL_WDS_DEL: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0); + break; +#else /* PRISM2_USE_WE_TYPE_ADDR */ + case PRISM2_IOCTL_WDS_ADD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else if (wrq->u.data.pointer) { + char addrbuf[18]; + if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) { + ret = -EFAULT; + break; + } + ret = prism2_ioctl_priv_wds(dev, 1, addrbuf); + } + break; + + case PRISM2_IOCTL_WDS_DEL: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else if (wrq->u.data.pointer) { + char addrbuf[18]; + if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) { + ret = -EFAULT; + break; + } + ret = prism2_ioctl_priv_wds(dev, 0, addrbuf); + } + break; +#endif /* PRISM2_USE_WE_TYPE_ADDR */ + + case PRISM2_IOCTL_SET_RID_WORD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_set_rid_word(dev, + (int *) wrq->u.name); + break; + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + case PRISM2_IOCTL_MACCMD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name); + break; + +#ifdef PRISM2_USE_WE_TYPE_ADDR + case PRISM2_IOCTL_ADDMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = ap_control_add_mac(&local->ap->mac_restrictions, + wrq->u.ap_addr.sa_data); + break; + case PRISM2_IOCTL_DELMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = ap_control_del_mac(&local->ap->mac_restrictions, + wrq->u.ap_addr.sa_data); + break; + case PRISM2_IOCTL_KICKMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = ap_control_kick_mac(local->ap, local->dev, + wrq->u.ap_addr.sa_data); + break; +#else /* PRISM2_USE_WE_TYPE_ADDR */ + case PRISM2_IOCTL_ADDMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else if (wrq->u.data.pointer) { + char addrbuf[18]; + if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) { + ret = -EFAULT; + break; + } + ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_ADD); + } + break; + + case PRISM2_IOCTL_DELMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else if (wrq->u.data.pointer) { + char addrbuf[18]; + if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) { + ret = -EFAULT; + break; + } + ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_DEL); + } + break; + + case PRISM2_IOCTL_KICKMAC: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else if (wrq->u.data.pointer) { + char addrbuf[18]; + if (copy_from_user(addrbuf, wrq->u.data.pointer, 18)) { + ret = -EFAULT; + break; + } + ret = ap_mac_ioctl(local, addrbuf, AP_CTRL_MAC_KICK); + } + break; +#endif /* PRISM2_USE_WE_TYPE_ADDR */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + + + /* Private ioctls that are not used with iwpriv; + * in SIOCDEVPRIVATE range */ + +#ifdef PRISM2_DOWNLOAD_SUPPORT + case PRISM2_IOCTL_DOWNLOAD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_download(local, &wrq->u.data); + break; +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + + case PRISM2_IOCTL_HOSTAPD: + if (!capable(CAP_NET_ADMIN)) ret = -EPERM; + else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); + break; + + default: +#if WIRELESS_EXT > 12 + if (cmd >= SIOCSIWCOMMIT && cmd <= SIOCGIWPOWER) { + /* unsupport wireless extensions get through here - do + * not report these to debug log */ + ret = -EOPNOTSUPP; + break; + } +#endif /* WIRELESS_EXT > 12 */ + printk(KERN_DEBUG "%s unsupported ioctl(0x%04x)\n", + dev->name, cmd); + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +#endif /* WIRELESS_EXT */ diff -Nru a/drivers/net/wireless/hostap_pci.c b/drivers/net/wireless/hostap_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_pci.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,433 @@ +#define PRISM2_PCI + +/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on + * driver patches from Reyk Floeter and + * Andy Warner */ + +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) +#include +#else +#include +#endif +#include "hostap_wext.h" + +#include +#include + +#include "hostap_wlan.h" + + +static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static char *dev_info = "hostap_pci"; + + +MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen"); +MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " + "PCI cards."); +MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards"); +MODULE_LICENSE("GPL"); + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +/* PCI initialization uses Linux 2.4.x version and older kernels do not support + * this */ +#error Prism2.5 PCI version requires at least Linux kernel version 2.4.0 +#endif /* kernel < 2.4.0 */ + + +/* FIX: do we need mb/wmb/rmb with memory operations? */ + + +static struct pci_device_id prism2_pci_id_table[] __devinitdata = { + /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ + { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, + /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ + { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, + /* Samsung MagicLAN SWL-2210P */ + { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + + +#ifdef PRISM2_IO_DEBUG + +static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); + writeb(v, dev->mem_start + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u8 v; + + spin_lock_irqsave(&local->lock, flags); + v = readb(dev->mem_start + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); + writew(v, dev->mem_start + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u16 v; + + spin_lock_irqsave(&local->lock, flags); + v = readw(dev->mem_start + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) +#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) +#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) +#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) +#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v))) +#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a))) + +#else /* PRISM2_IO_DEBUG */ + +#define HFA384X_OUTB(v,a) writeb((v), dev->mem_start + (a)) +#define HFA384X_INB(a) (u8) readb(dev->mem_start + (a)) +#define HFA384X_OUTW(v,a) writew((v), dev->mem_start + (a)) +#define HFA384X_INW(a) (u16) readw(dev->mem_start + (a)) +#define HFA384X_OUTW_DATA(v,a) writew(cpu_to_le16(v), dev->mem_start + (a)) +#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(readw(dev->mem_start + (a))) + +#endif /* PRISM2_IO_DEBUG */ + + +static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, + int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + for ( ; len > 1; len -= 2) + *pos++ = HFA384X_INW_DATA(d_off); + + if (len & 1) + *((char *) pos) = HFA384X_INB(d_off); + + return 0; +} + + +static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + for ( ; len > 1; len -= 2) + HFA384X_OUTW_DATA(*pos++, d_off); + + if (len & 1) + HFA384X_OUTB(*((char *) pos), d_off); + + return 0; +} + + +/* FIX: This might change at some point.. */ +#include "hostap_hw.c" + +static void prism2_pci_cor_sreset(local_info_t *local) +{ + struct net_device *dev = local->dev; + + /* linux-wlan-ng uses extremely long hold and settle times for + * COR sreset. A comment in the driver code mentions that the long + * delays appear to be necessary. However, at least IBM 22P6901 seems + * to work fine with shorter delays. + * + * Longer delays can be configured by uncommenting following line: */ +/* #define PRISM2_PCI_USE_LONG_DELAYS */ + +#ifdef PRISM2_PCI_USE_LONG_DELAYS + int i; + + HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF); + mdelay(250); + + HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF); + mdelay(500); + + /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ + i = 2000000 / 10; + while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) + udelay(10); + +#else /* PRISM2_PCI_USE_LONG_DELAYS */ + + HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF); + mdelay(1); + HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF); + mdelay(1); + +#endif /* PRISM2_PCI_USE_LONG_DELAYS */ + + if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { + printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); + } +} + + +static void prism2_pci_genesis_reset(local_info_t *local, int hcr) +{ + struct net_device *dev = local->dev; + + HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); + mdelay(10); + HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); + mdelay(10); + HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); + mdelay(10); +} + + +static struct prism2_helper_functions prism2_pci_funcs = +{ + .card_present = NULL, + .cor_sreset = prism2_pci_cor_sreset, + .dev_open = NULL, + .dev_close = NULL, + .genesis_reset = prism2_pci_genesis_reset, +}; + + +static int prism2_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned long phymem; + unsigned long mem = 0; + local_info_t *local = NULL; + struct net_device *dev = NULL; + static int cards_found /* = 0 */; + int irq_registered = 0; + struct hostap_interface *iface; + + if (pci_enable_device(pdev)) + return -EIO; + + phymem = pci_resource_start(pdev, 0); + + if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { + printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); + goto err_out_disable; + } + + mem = (unsigned long) ioremap(phymem, pci_resource_len(pdev, 0)); + if (!mem) { + printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; + goto fail; + } + +#ifdef PRISM2_BUS_MASTER + pci_set_master(pdev); +#endif /* PRISM2_BUS_MASTER */ + + dev = prism2_init_local_data(&prism2_pci_funcs, cards_found); + if (dev == NULL) + goto fail; + iface = dev->priv; + local = iface->local; + cards_found++; + + dev->irq = pdev->irq; + dev->mem_start = mem; + dev->mem_end = mem + pci_resource_len(pdev, 0); + + if (prism2_init_dev(local)) + goto fail; + + prism2_pci_cor_sreset(local); + + pci_set_drvdata(pdev, dev); + + if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, + dev)) { + printk(KERN_WARNING "%s: request_irq failed\n", dev->name); + goto fail; + } else + irq_registered = 1; + + if (!local->pri_only && prism2_hw_config(dev, 1)) { + printk(KERN_DEBUG "%s: hardware initialization failed\n", + dev_info); + goto fail; + } + + printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " + "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); + + return 0; + + fail: + if (irq_registered && dev) + free_irq(dev->irq, dev); + + if (mem) + iounmap((void *) mem); + + release_mem_region(phymem, pci_resource_len(pdev, 0)); + + err_out_disable: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)) + pci_disable_device(pdev); +#endif + + prism2_free_local_data(dev); + + return -ENODEV; +} + + +static void prism2_pci_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct hostap_interface *iface = dev->priv; + unsigned long mem_start; + + /* Reset the hardware, and ensure interrupts are disabled. */ + prism2_pci_cor_sreset(iface->local); + hfa384x_disable_interrupts(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + + mem_start = dev->mem_start; + prism2_free_local_data(dev); + + iounmap((void *) mem_start); + + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)) + pci_disable_device(pdev); +#endif +} + + +#ifdef CONFIG_PM +static int prism2_pci_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + if (netif_running(dev)) { + hostap_netif_stop_queues(dev); + netif_device_detach(dev); + } + prism2_hw_shutdown(dev, 0); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6)) + pci_save_state(pdev, local->pci_save_state); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)) + pci_disable_device(pdev); +#endif + pci_set_power_state(pdev, 3); + + return 0; +} + +static int prism2_pci_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + + pci_enable_device(pdev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6)) + pci_restore_state(pdev, local->pci_save_state); +#endif + prism2_hw_config(dev, 0); + if (netif_running(dev)) { + netif_device_attach(dev); + netif_start_queue(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + + +MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); + +static struct pci_driver prism2_pci_drv_id = { + .name = "prism2_pci", + .id_table = prism2_pci_id_table, + .probe = prism2_pci_probe, + .remove = prism2_pci_remove, +#ifdef CONFIG_PM + .suspend = prism2_pci_suspend, + .resume = prism2_pci_resume, +#endif /* CONFIG_PM */ + /* Linux 2.4.6 added save_state and enable_wake that are not used here + */ +}; + + +static int __init init_prism2_pci(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + + if (pci_register_driver(&prism2_pci_drv_id) <= 0) { + printk("hostap_pci: No devices found, driver not " + "installed.\n"); + pci_unregister_driver(&prism2_pci_drv_id); + return -ENODEV; + } + + return 0; +} + + +static void __exit exit_prism2_pci(void) +{ + pci_unregister_driver(&prism2_pci_drv_id); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} + + +module_init(init_prism2_pci); +module_exit(exit_prism2_pci); diff -Nru a/drivers/net/wireless/hostap_plx.c b/drivers/net/wireless/hostap_plx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_plx.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,619 @@ +#define PRISM2_PLX + +/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is + * based on: + * - Host AP driver patch from james@madingley.org + * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. + */ + + +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)) +#include +#else +#include +#endif +#include "hostap_wext.h" + +#include +#include + +#include "hostap_wlan.h" + + +static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static char *dev_info = "hostap_plx"; + + +MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen"); +MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " + "cards (PLX)."); +MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)"); +MODULE_LICENSE("GPL"); + + +static int ignore_cis = 0; +MODULE_PARM(ignore_cis, "i"); +MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +/* PCI initialization uses Linux 2.4.x version and older kernels do not support + * this */ +#error PLX9052 version requires at least Linux kernel version 2.4.0 +#endif /* kernel < 2.4.0 */ + + +#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ +#define COR_SRESET 0x80 +#define COR_LEVLREQ 0x40 +#define COR_ENABLE_FUNC 0x01 +/* PCI Configuration Registers */ +#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ +/* Local Configuration Registers */ +#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ +#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ +#define PLX_CNTRL 0x50 +#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) + + +#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } + +static struct pci_device_id prism2_plx_id_table[] __devinitdata = { + PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), + PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), + PLXDEV(0x126c, 0x8030, "Nortel emobility"), + PLXDEV(0x1385, 0x4100, "Netgear MA301"), + PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), + PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), + PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), + PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), + PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), + PLXDEV(0x16ab, 0x1103, "Longshine 8031"), + PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), + PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), + { 0 } +}; + + +/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid + * is not listed here, you will need to add it here to get the driver + * initialized. */ +static struct prism2_plx_manfid { + u16 manfid1, manfid2; +} prism2_plx_known_manfids[] = { + { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, + { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, + { 0x0126, 0x8000 } /* Proxim RangeLAN */, + { 0x0138, 0x0002 } /* Compaq WL100 */, + { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, + { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, + { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, + { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, + { 0x028a, 0x0002 } /* D-Link DRC-650 */, + { 0x0250, 0x0002 } /* Samsung SWL2000-N */, + { 0xc250, 0x0002 } /* EMTAC A2424i */, + { 0xd601, 0x0002 } /* Z-Com XI300 */, + { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, + { 0, 0} +}; + + +#ifdef PRISM2_IO_DEBUG + +static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); + outb(v, dev->base_addr + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u8 v; + + spin_lock_irqsave(&local->lock, flags); + v = inb(dev->base_addr + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); + outw(v, dev->base_addr + a); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + u16 v; + + spin_lock_irqsave(&local->lock, flags); + v = inw(dev->base_addr + a); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); + spin_unlock_irqrestore(&local->lock, flags); + return v; +} + +static inline void hfa384x_outsw_debug(struct net_device *dev, int a, + u8 *buf, int wc) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); + outsw(dev->base_addr + a, buf, wc); + spin_unlock_irqrestore(&local->lock, flags); +} + +static inline void hfa384x_insw_debug(struct net_device *dev, int a, + u8 *buf, int wc) +{ + struct hostap_interface *iface = dev->priv; + local_info_t *local = iface->local; + unsigned long flags; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); + insw(dev->base_addr + a, buf, wc); + spin_unlock_irqrestore(&local->lock, flags); +} + +#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) +#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) +#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) +#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) +#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) +#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) + +#else /* PRISM2_IO_DEBUG */ + +#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) +#define HFA384X_INB(a) inb(dev->base_addr + (a)) +#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) +#define HFA384X_INW(a) inw(dev->base_addr + (a)) +#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) +#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) + +#endif /* PRISM2_IO_DEBUG */ + + +static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, + int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + if (len / 2) + HFA384X_INSW(d_off, buf, len / 2); + pos += len / 2; + + if (len & 1) + *((char *) pos) = HFA384X_INB(d_off); + + return 0; +} + + +static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) +{ + u16 d_off; + u16 *pos; + + d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; + pos = (u16 *) buf; + + if (len / 2) + HFA384X_OUTSW(d_off, buf, len / 2); + pos += len / 2; + + if (len & 1) + HFA384X_OUTB(*((char *) pos), d_off); + + return 0; +} + + +/* FIX: This might change at some point.. */ +#include "hostap_hw.c" + + +static void prism2_plx_cor_sreset(local_info_t *local) +{ + unsigned char corsave; + + printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", + dev_info); + + /* Set sreset bit of COR and clear it after hold time */ + + if (local->attr_mem == 0) { + /* TMD7160 - COR at card's first I/O addr */ + corsave = inb(local->cor_offset); + outb(corsave | COR_SRESET, local->cor_offset); + mdelay(1); + outb(corsave & ~COR_SRESET, local->cor_offset); + mdelay(1); + } else { + /* PLX9052 */ + corsave = readb(local->attr_mem + local->cor_offset); + writeb(corsave | COR_SRESET, + local->attr_mem + local->cor_offset); + mdelay(1); + writeb(corsave & ~COR_SRESET, + local->attr_mem + local->cor_offset); + mdelay(1); + } +} + + +static void prism2_plx_genesis_reset(local_info_t *local, int hcr) +{ + unsigned char corsave; + + if (local->attr_mem == 0) { + /* TMD7160 - COR at card's first I/O addr */ + corsave = inb(local->cor_offset); + outb(corsave | COR_SRESET, local->cor_offset); + mdelay(10); + outb(hcr, local->cor_offset + 2); + mdelay(10); + outb(corsave & ~COR_SRESET, local->cor_offset); + mdelay(10); + } else { + /* PLX9052 */ + corsave = readb(local->attr_mem + local->cor_offset); + writeb(corsave | COR_SRESET, + local->attr_mem + local->cor_offset); + mdelay(10); + writeb(hcr, local->attr_mem + local->cor_offset + 2); + mdelay(10); + writeb(corsave & ~COR_SRESET, + local->attr_mem + local->cor_offset); + mdelay(10); + } +} + + +static struct prism2_helper_functions prism2_plx_funcs = +{ + .card_present = NULL, + .cor_sreset = prism2_plx_cor_sreset, + .dev_open = NULL, + .dev_close = NULL, + .genesis_reset = prism2_plx_genesis_reset, +}; + + +static int prism2_plx_check_cis(unsigned long attr_mem, int attr_len, + unsigned int *cor_offset, + unsigned int *cor_index) +{ +#define CISTPL_CONFIG 0x1A +#define CISTPL_MANFID 0x20 +#define CISTPL_END 0xFF +#define CIS_MAX_LEN 256 + u8 cis[CIS_MAX_LEN]; + int i, pos; + unsigned int rmsz, rasz, manfid1, manfid2; + struct prism2_plx_manfid *manfid; + + /* read CIS; it is in even offsets in the beginning of attr_mem */ + for (i = 0; i < CIS_MAX_LEN; i++) + cis[i] = readb(attr_mem + 2 * i); + printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n", + dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]); + + /* set reasonable defaults for Prism2 cards just in case CIS parsing + * fails */ + *cor_offset = 0x3e0; + *cor_index = 0x01; + manfid1 = manfid2 = 0; + + pos = 0; + while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { + if (pos + cis[pos + 1] >= CIS_MAX_LEN) + goto cis_error; + + switch (cis[pos]) { + case CISTPL_CONFIG: + if (cis[pos + 1] < 1) + goto cis_error; + rmsz = (cis[pos + 2] & 0x3c) >> 2; + rasz = cis[pos + 2] & 0x03; + if (4 + rasz + rmsz > cis[pos + 1]) + goto cis_error; + *cor_index = cis[pos + 3] & 0x3F; + *cor_offset = 0; + for (i = 0; i <= rasz; i++) + *cor_offset += cis[pos + 4 + i] << (8 * i); + printk(KERN_DEBUG "%s: cor_index=0x%x " + "cor_offset=0x%x\n", dev_info, + *cor_index, *cor_offset); + if (*cor_offset > attr_len) { + printk(KERN_ERR "%s: COR offset not within " + "attr_mem\n", dev_info); + return -1; + } + break; + + case CISTPL_MANFID: + if (cis[pos + 1] < 4) + goto cis_error; + manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); + manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); + printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", + dev_info, manfid1, manfid2); + break; + } + + pos += cis[pos + 1] + 2; + } + + if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) + goto cis_error; + + for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) + if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) + return 0; + + printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" + " not supported card\n", dev_info, manfid1, manfid2); + goto fail; + + cis_error: + printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); + + fail: + if (ignore_cis) { + printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " + "errors during CIS verification\n", dev_info); + return 0; + } + return -1; +} + + +static int prism2_plx_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned int pccard_ioaddr, plx_ioaddr; + unsigned long pccard_attr_mem; + unsigned int pccard_attr_len; + unsigned long attr_mem = 0; + unsigned int cor_offset, cor_index; + u32 reg; + local_info_t *local = NULL; + struct net_device *dev = NULL; + struct hostap_interface *iface; + static int cards_found /* = 0 */; + int irq_registered = 0; + int tmd7160; + + if (pci_enable_device(pdev)) + return -EIO; + + /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ + tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); + + plx_ioaddr = pci_resource_start(pdev, 1); + pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); + + if (tmd7160) { + /* TMD7160 */ + attr_mem = 0; /* no access to PC Card attribute memory */ + + printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " + "irq=%d, pccard_io=0x%x\n", + plx_ioaddr, pdev->irq, pccard_ioaddr); + + cor_offset = plx_ioaddr; + cor_index = 0x04; + + outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); + mdelay(1); + reg = inb(plx_ioaddr); + if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { + printk(KERN_ERR "%s: Error setting COR (expected=" + "0x%02x, was=0x%02x)\n", dev_info, + cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); + goto fail; + } + } else { + /* PLX9052 */ + pccard_attr_mem = pci_resource_start(pdev, 2); + pccard_attr_len = pci_resource_len(pdev, 2); + if (pccard_attr_len < PLX_MIN_ATTR_LEN) + goto fail; + + + attr_mem = (unsigned long) ioremap(pccard_attr_mem, + pccard_attr_len); + if (!attr_mem) { + printk(KERN_ERR "%s: cannot remap attr_mem\n", + dev_info); + goto fail; + } + + printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " + "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", + pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); + + if (prism2_plx_check_cis(attr_mem, pccard_attr_len, + &cor_offset, &cor_index)) { + printk(KERN_INFO "Unknown PC Card CIS - not a " + "Prism2/2.5 card?\n"); + goto fail; + } + + printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " + "adapter\n"); + + /* Write COR to enable PC Card */ + writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, + attr_mem + cor_offset); + + /* Enable PCI interrupts if they are not already enabled */ + reg = inl(plx_ioaddr + PLX_INTCSR); + printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); + if (!(reg & PLX_INTCSR_PCI_INTEN)) { + outl(reg | PLX_INTCSR_PCI_INTEN, + plx_ioaddr + PLX_INTCSR); + if (!(inl(plx_ioaddr + PLX_INTCSR) & + PLX_INTCSR_PCI_INTEN)) { + printk(KERN_WARNING "%s: Could not enable " + "Local Interrupts\n", dev_info); + goto fail; + } + } + + reg = inl(plx_ioaddr + PLX_CNTRL); + printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " + "present=%d)\n", + reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); + /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is + * not present; but are there really such cards in use(?) */ + } + + dev = prism2_init_local_data(&prism2_plx_funcs, cards_found); + if (dev == NULL) + goto fail; + iface = dev->priv; + local = iface->local; + cards_found++; + + dev->irq = pdev->irq; + dev->base_addr = pccard_ioaddr; + local->attr_mem = attr_mem; + local->cor_offset = cor_offset; + + if (prism2_init_dev(local)) + goto fail; + + pci_set_drvdata(pdev, dev); + + if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, + dev)) { + printk(KERN_WARNING "%s: request_irq failed\n", dev->name); + goto fail; + } else + irq_registered = 1; + + if (prism2_hw_config(dev, 1)) { + printk(KERN_DEBUG "%s: hardware initialization failed\n", + dev_info); + goto fail; + } + + return 0; + + fail: + prism2_free_local_data(dev); + + if (irq_registered && dev) + free_irq(dev->irq, dev); + + if (attr_mem) + iounmap((void *) attr_mem); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)) + pci_disable_device(pdev); +#endif + + return -ENODEV; +} + + +static void prism2_plx_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct hostap_interface *iface = dev->priv; + + /* Reset the hardware, and ensure interrupts are disabled. */ + prism2_plx_cor_sreset(iface->local); + hfa384x_disable_interrupts(dev); + + if (iface->local->attr_mem) + iounmap((void *) iface->local->attr_mem); + if (dev->irq) + free_irq(dev->irq, dev); + + prism2_free_local_data(dev); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)) + pci_disable_device(pdev); +#endif +} + + +MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); + +static struct pci_driver prism2_plx_drv_id = { + .name = "prism2_plx", + .id_table = prism2_plx_id_table, + .probe = prism2_plx_probe, + .remove = prism2_plx_remove, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6)) + .suspend = NULL, + .resume = NULL, + .enable_wake = NULL +#else /* Linux < 2.4.6 */ + .suspend = NULL, + .resume = NULL +#endif /* Linux >= 2.4.6 */ +}; + + +static int __init init_prism2_plx(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + + if (pci_register_driver(&prism2_plx_drv_id) <= 0) { + printk("hostap_plx: No devices found, driver not " + "installed.\n"); + pci_unregister_driver(&prism2_plx_drv_id); + return -ENODEV; + } + + return 0; +} + + +static void __exit exit_prism2_plx(void) +{ + pci_unregister_driver(&prism2_plx_drv_id); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} + + +module_init(init_prism2_plx); +module_exit(exit_prism2_plx); diff -Nru a/drivers/net/wireless/hostap_proc.c b/drivers/net/wireless/hostap_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_proc.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,344 @@ +/* /proc routines for Host AP driver */ + +#define PROC_LIMIT (PAGE_SIZE - 80) + + +#ifndef PRISM2_NO_PROCFS_DEBUG +static int prism2_debug_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + local_info_t *local = (local_info_t *) data; + int i; + + if (off != 0) { + *eof = 1; + return 0; + } + + p += sprintf(p, "next_txfid=%d next_alloc=%d\n", + local->next_txfid, local->next_alloc); + for (i = 0; i < PRISM2_TXFID_COUNT; i++) + p += sprintf(p, "FID: tx=%04X intransmit=%04X\n", + local->txfid[i], local->intransmitfid[i]); + p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control); + p += sprintf(p, "beacon_int=%d\n", local->beacon_int); + p += sprintf(p, "dtim_period=%d\n", local->dtim_period); + p += sprintf(p, "wds_max_connections=%d\n", + local->wds_max_connections); + p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); + p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); + if (local->crypt && local->crypt->ops) + p += sprintf(p, "crypt=%s\n", local->crypt->ops->name); + p += sprintf(p, "pri_only=%d\n", local->pri_only); + + return (p - page); +} +#endif /* PRISM2_NO_PROCFS_DEBUG */ + + +static int prism2_stats_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + local_info_t *local = (local_info_t *) data; + struct comm_tallies_sums *sums = (struct comm_tallies_sums *) + &local->comm_tallies; + + if (off != 0) { + *eof = 1; + return 0; + } + + p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); + p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames); + p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments); + p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); + p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); + p += sprintf(p, "TxDeferredTransmissions=%u\n", + sums->tx_deferred_transmissions); + p += sprintf(p, "TxSingleRetryFrames=%u\n", + sums->tx_single_retry_frames); + p += sprintf(p, "TxMultipleRetryFrames=%u\n", + sums->tx_multiple_retry_frames); + p += sprintf(p, "TxRetryLimitExceeded=%u\n", + sums->tx_retry_limit_exceeded); + p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards); + p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); + p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); + p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments); + p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); + p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); + p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors); + p += sprintf(p, "RxDiscardsNoBuffer=%u\n", + sums->rx_discards_no_buffer); + p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); + p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n", + sums->rx_discards_wep_undecryptable); + p += sprintf(p, "RxMessageInMsgFragments=%u\n", + sums->rx_message_in_msg_fragments); + p += sprintf(p, "RxMessageInBadMsgFragments=%u\n", + sums->rx_message_in_bad_msg_fragments); + /* FIX: this may grow too long for one page(?) */ + + return (p - page); +} + + +static int prism2_wds_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + local_info_t *local = (local_info_t *) data; + struct list_head *ptr; + struct hostap_interface *iface; + + if (off > PROC_LIMIT) { + *eof = 1; + return 0; + } + + read_lock_bh(&local->iface_lock); + list_for_each(ptr, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type != HOSTAP_INTERFACE_WDS) + continue; + p += sprintf(p, "%s\t" MACSTR "\n", + iface->dev->name, + MAC2STR(iface->u.wds.remote_addr)); + if ((p - page) > PROC_LIMIT) { + printk(KERN_DEBUG "%s: wds proc did not fit\n", + local->dev->name); + break; + } + } + read_unlock_bh(&local->iface_lock); + + if ((p - page) <= off) { + *eof = 1; + return 0; + } + + *start = page + off; + + return (p - page - off); +} + + +static int prism2_pda_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + local_info_t *local = (local_info_t *) data; + + if (local->pda == NULL || off >= PRISM2_PDA_SIZE) { + *eof = 1; + return 0; + } + + if (off + count > PRISM2_PDA_SIZE) + count = PRISM2_PDA_SIZE - off; + + memcpy(page, local->pda + off, count); + return count; +} + + +#ifdef PRISM2_IO_DEBUG +static int prism2_io_debug_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + local_info_t *local = (local_info_t *) data; + int head = local->io_debug_head; + int start_bytes, left, copy, copied; + + if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { + *eof = 1; + if (off >= PRISM2_IO_DEBUG_SIZE * 4) + return 0; + count = PRISM2_IO_DEBUG_SIZE * 4 - off; + } + + copied = 0; + start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; + left = count; + + if (off < start_bytes) { + copy = start_bytes - off; + if (copy > count) + copy = count; + memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); + left -= copy; + if (left > 0) + memcpy(&page[copy], local->io_debug, left); + } else { + memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), + left); + } + + *start = page; + + return count; +} +#endif /* PRISM2_IO_DEBUG */ + + +#ifndef PRISM2_NO_STATION_MODES +static int prism2_scan_results_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + local_info_t *local = (local_info_t *) data; + int entries, entry, i, len, total = 0, hostscan; + struct hfa384x_scan_result *scanres; + struct hfa384x_hostscan_result *hscanres; + u8 *pos; + + p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " + "SSID\n"); + + spin_lock_bh(&local->lock); + hostscan = local->last_scan_type == PRISM2_HOSTSCAN; + entries = hostscan ? local->last_hostscan_results_count : + local->last_scan_results_count; + for (entry = 0; entry < entries; entry++) { + hscanres = &local->last_hostscan_results[entry]; + scanres = &local->last_scan_results[entry]; + + if (total + (p - page) <= off) { + total += p - page; + p = page; + } + if (total + (p - page) > off + count) + break; + if ((p - page) > (PAGE_SIZE - 200)) + break; + + if (hostscan) { + p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", + le16_to_cpu(hscanres->chid), + (s16) le16_to_cpu(hscanres->anl), + (s16) le16_to_cpu(hscanres->sl), + le16_to_cpu(hscanres->beacon_interval), + le16_to_cpu(hscanres->capability), + le16_to_cpu(hscanres->rate), + MAC2STR(hscanres->bssid), + le16_to_cpu(hscanres->atim)); + } else { + p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR + " N/A ", + le16_to_cpu(scanres->chid), + (s16) le16_to_cpu(scanres->anl), + (s16) le16_to_cpu(scanres->sl), + le16_to_cpu(scanres->beacon_interval), + le16_to_cpu(scanres->capability), + le16_to_cpu(scanres->rate), + MAC2STR(scanres->bssid)); + } + + pos = hostscan ? hscanres->sup_rates : scanres->sup_rates; + for (i = 0; i < sizeof(hscanres->sup_rates); i++) { + if (pos[i] == 0) + break; + p += sprintf(p, "<%02x>", pos[i]); + } + p += sprintf(p, " "); + + pos = hostscan ? hscanres->ssid : scanres->ssid; + len = le16_to_cpu(hostscan ? hscanres->ssid_len : + scanres->ssid_len); + if (len > 32) + len = 32; + for (i = 0; i < len; i++) { + unsigned char c = pos[i]; + if (c >= 32 && c < 127) + p += sprintf(p, "%c", c); + else + p += sprintf(p, "<%02x>", c); + } + p += sprintf(p, "\n"); + } + spin_unlock_bh(&local->lock); + + total += (p - page); + if (total >= off + count) + *eof = 1; + + if (total < off) { + *eof = 1; + return 0; + } + + len = total - off; + if (len > (p - page)) + len = p - page; + *start = p - len; + if (len > count) + len = count; + + return len; +} +#endif /* PRISM2_NO_STATION_MODES */ + + +void hostap_init_proc(local_info_t *local) +{ + local->proc = NULL; + + if (hostap_proc == NULL) { + printk(KERN_WARNING "%s: hostap proc directory not created\n", + local->dev->name); + return; + } + + local->proc = proc_mkdir(local->dev->name, hostap_proc); + if (local->proc == NULL) { + printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", + local->dev->name); + return; + } + +#ifndef PRISM2_NO_PROCFS_DEBUG + create_proc_read_entry("debug", 0, local->proc, + prism2_debug_proc_read, local); +#endif /* PRISM2_NO_PROCFS_DEBUG */ + create_proc_read_entry("stats", 0, local->proc, + prism2_stats_proc_read, local); + create_proc_read_entry("wds", 0, local->proc, + prism2_wds_proc_read, local); + create_proc_read_entry("pda", 0, local->proc, + prism2_pda_proc_read, local); +#ifdef PRISM2_IO_DEBUG + create_proc_read_entry("io_debug", 0, local->proc, + prism2_io_debug_proc_read, local); +#endif /* PRISM2_IO_DEBUG */ +#ifndef PRISM2_NO_STATION_MODES + create_proc_read_entry("scan_results", 0, local->proc, + prism2_scan_results_proc_read, local); +#endif /* PRISM2_NO_STATION_MODES */ +} + + +void hostap_remove_proc(local_info_t *local) +{ + if (local->proc != NULL) { +#ifndef PRISM2_NO_STATION_MODES + remove_proc_entry("scan_results", local->proc); +#endif /* PRISM2_NO_STATION_MODES */ +#ifdef PRISM2_IO_DEBUG + remove_proc_entry("io_debug", local->proc); +#endif /* PRISM2_IO_DEBUG */ + remove_proc_entry("pda", local->proc); + remove_proc_entry("wds", local->proc); + remove_proc_entry("stats", local->proc); +#ifndef PRISM2_NO_PROCFS_DEBUG + remove_proc_entry("debug", local->proc); +#endif /* PRISM2_NO_PROCFS_DEBUG */ + if (local->dev != NULL && local->dev->name != NULL && + hostap_proc != NULL) + remove_proc_entry(local->dev->name, hostap_proc); + } +} + + +EXPORT_SYMBOL(hostap_init_proc); +EXPORT_SYMBOL(hostap_remove_proc); diff -Nru a/drivers/net/wireless/hostap_wext.h b/drivers/net/wireless/hostap_wext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_wext.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,77 @@ +#ifndef HOSTAP_WEXT_H +#define HOSTAP_WEXT_H + +/* Linux Wireless Extensions compatibility code */ + +#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) +#include +#if WIRELESS_EXT > 12 +#include +#endif /* WIRELESS_EXT > 12 */ +#if WIRELESS_EXT < 9 +#warning Linux wireless extensions versions older than 9 are not supported +/* Compile limited version without wireless ext support */ +#undef WIRELESS_EXT +#endif /* WIRELESS_EXT < 9 */ +#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + + +/* if wireless ext is not supported */ +#ifndef IW_MODE_ADHOC +#define IW_MODE_ADHOC 1 +#endif +#ifndef IW_MODE_INFRA +#define IW_MODE_INFRA 2 +#endif +#ifndef IW_MODE_MASTER +#define IW_MODE_MASTER 3 +#endif +#ifndef IW_MODE_REPEAT +#define IW_MODE_REPEAT 4 +#endif +#ifndef IW_MODE_SECOND +#define IW_MODE_SECOND 5 +#endif +#ifndef IW_MODE_MONITOR +#define IW_MODE_MONITOR 6 +#endif + + + +#ifdef WIRELESS_EXT +/* Conversion to new driver API by Jean II */ + +#if WIRELESS_EXT <= 12 +/* Wireless extensions backward compatibility */ + +/* Dummy prototype, as we don't really need it */ +struct iw_request_info; +#endif /* WIRELESS_EXT <= 12 */ + + +#if WIRELESS_EXT >= 15 +/* Wireless ext ver15 allows verification of iwpriv support and sub-ioctls can + * be included even if not especially configured. */ +#ifndef PRISM2_USE_WE_SUB_IOCTLS +#define PRISM2_USE_WE_SUB_IOCTLS +#endif /* PRISM2_USE_WE_SUB_IOCTLS */ + +/* Assume that hosts using new wireless ext also have new wireless tools + * (ver >= 25) */ +#ifndef PRISM2_USE_WE_TYPE_ADDR +#define PRISM2_USE_WE_TYPE_ADDR +#endif /* PRISM2_USE_WE_TYPE_ADDR */ +#endif /* WIRELESS_EXT >= 15 */ + + +#ifdef PRISM2_USE_WE_TYPE_ADDR +/* Added in WIRELESS_EXT 15, but can be used with older versions assuming + * iwpriv ver >= 25 */ +#ifndef IW_PRIV_TYPE_ADDR +#define IW_PRIV_TYPE_ADDR 0x6000 +#endif /* IW_PRIV_TYPE_ADDR */ +#endif /* PRISM2_USE_WE_TYPE_ADDR */ + +#endif /* WIRELESS_EXT */ + +#endif /* HOSTAP_WEXT_H */ diff -Nru a/drivers/net/wireless/hostap_wlan.h b/drivers/net/wireless/hostap_wlan.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/hostap_wlan.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,1018 @@ +#ifndef HOSTAP_WLAN_H +#define HOSTAP_WLAN_H + +#include "hostap_config.h" +#ifdef __KERNEL__ +#include "hostap_compat.h" +#endif +#include "hostap_crypt.h" +#include "hostap_common.h" + +#define MAX_PARM_DEVICES 8 +#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) +#define DEF_INTS -1, -1, -1, -1, -1, -1, -1 +#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] + + +/* Specific skb->protocol value that indicates that the packet already contains + * txdesc header. + * FIX: This might need own value that would be allocated especially for Prism2 + * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". + * However, these skb's should have only minimal path in the kernel side since + * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ +#define ETH_P_HOSTAP ETH_P_CONTROL + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 +#endif +#ifndef ARPHRD_IEEE80211_PRISM +#define ARPHRD_IEEE80211_PRISM 802 +#endif + +/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header + * (from linux-wlan-ng) */ +struct linux_wlan_ng_val { + u32 did; + u16 status, len; + u32 data; +} __attribute__ ((packed)); + +struct linux_wlan_ng_prism_hdr { + u32 msgcode, msglen; + char devname[16]; + struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, + noise, rate, istx, frmlen; +} __attribute__ ((packed)); + +struct linux_wlan_ng_cap_hdr { + u32 version; + u32 length; + u64 mactime; + u64 hosttime; + u32 phytype; + u32 channel; + u32 datarate; + u32 antenna; + u32 priority; + u32 ssi_type; + s32 ssi_signal; + s32 ssi_noise; + u32 preamble; + u32 encoding; +} __attribute__ ((packed)); + +#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ +#define LWNG_CAPHDR_VERSION 0x80211001 + +struct hfa384x_rx_frame { + /* HFA384X RX frame descriptor */ + u16 status; /* HFA384X_RX_STATUS_ flags */ + u32 time; /* timestamp, 1 microsecond resolution */ + u8 silence; /* 27 .. 154; seems to be 0 */ + u8 signal; /* 27 .. 154 */ + u8 rate; /* 10, 20, 55, or 110 */ + u8 rxflow; + u32 reserved; + + /* 802.11 */ + u16 frame_control; + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + u16 seq_ctrl; + u8 addr4[6]; + u16 data_len; + + /* 802.3 */ + u8 dst_addr[6]; + u8 src_addr[6]; + u16 len; + + /* followed by frame data; max 2304 bytes */ +} __attribute__ ((packed)); + + +struct hfa384x_tx_frame { + /* HFA384X TX frame descriptor */ + u16 status; /* HFA384X_TX_STATUS_ flags */ + u16 reserved1; + u16 reserved2; + u32 sw_support; + u8 retry_count; /* not yet implemented */ + u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ + u16 tx_control; /* HFA384X_TX_CTRL_ flags */ + + /* 802.11 */ + u16 frame_control; /* parts not used */ + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; /* filled by firmware */ + u8 addr3[6]; + u16 seq_ctrl; /* filled by firmware */ + u8 addr4[6]; + u16 data_len; + + /* 802.3 */ + u8 dst_addr[6]; + u8 src_addr[6]; + u16 len; + + /* followed by frame data; max 2304 bytes */ +} __attribute__ ((packed)); + + +struct hfa384x_rid_hdr +{ + u16 len; + u16 rid; +} __attribute__ ((packed)); + + +/* Macro for converting signal levels (range 27 .. 154) to wireless ext + * dBm value with some accuracy */ +#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 + +/* Macro for converting signal/silence levels (RSSI) from RX descriptor to + * dBm */ +#define HFA384X_RSSI_LEVEL_TO_dBm(v) ((v) - 100) + +struct hfa384x_scan_request { + u16 channel_list; + u16 txrate; /* HFA384X_RATES_* */ +} __attribute__ ((packed)); + +struct hfa384x_hostscan_request { + u16 channel_list; + u16 txrate; + u16 target_ssid_len; + u8 target_ssid[32]; +} __attribute__ ((packed)); + +struct hfa384x_join_request { + u8 bssid[6]; + u16 channel; +} __attribute__ ((packed)); + +struct hfa384x_info_frame { + u16 len; + u16 type; +} __attribute__ ((packed)); + +struct hfa384x_comm_tallies { + u16 tx_unicast_frames; + u16 tx_multicast_frames; + u16 tx_fragments; + u16 tx_unicast_octets; + u16 tx_multicast_octets; + u16 tx_deferred_transmissions; + u16 tx_single_retry_frames; + u16 tx_multiple_retry_frames; + u16 tx_retry_limit_exceeded; + u16 tx_discards; + u16 rx_unicast_frames; + u16 rx_multicast_frames; + u16 rx_fragments; + u16 rx_unicast_octets; + u16 rx_multicast_octets; + u16 rx_fcs_errors; + u16 rx_discards_no_buffer; + u16 tx_discards_wrong_sa; + u16 rx_discards_wep_undecryptable; + u16 rx_message_in_msg_fragments; + u16 rx_message_in_bad_msg_fragments; +} __attribute__ ((packed)); + +struct hfa384x_comm_tallies32 { + u32 tx_unicast_frames; + u32 tx_multicast_frames; + u32 tx_fragments; + u32 tx_unicast_octets; + u32 tx_multicast_octets; + u32 tx_deferred_transmissions; + u32 tx_single_retry_frames; + u32 tx_multiple_retry_frames; + u32 tx_retry_limit_exceeded; + u32 tx_discards; + u32 rx_unicast_frames; + u32 rx_multicast_frames; + u32 rx_fragments; + u32 rx_unicast_octets; + u32 rx_multicast_octets; + u32 rx_fcs_errors; + u32 rx_discards_no_buffer; + u32 tx_discards_wrong_sa; + u32 rx_discards_wep_undecryptable; + u32 rx_message_in_msg_fragments; + u32 rx_message_in_bad_msg_fragments; +} __attribute__ ((packed)); + +struct hfa384x_scan_result_hdr { + u16 reserved; + u16 scan_reason; +#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ +#define HFA384X_SCAN_HOST_INITIATED 1 +#define HFA384X_SCAN_FIRMWARE_INITIATED 2 +#define HFA384X_SCAN_INQUIRY_FROM_HOST 3 +} __attribute__ ((packed)); + +#define HFA384X_SCAN_MAX_RESULTS 32 + +struct hfa384x_scan_result { + u16 chid; + u16 anl; + u16 sl; + u8 bssid[6]; + u16 beacon_interval; + u16 capability; + u16 ssid_len; + u8 ssid[32]; + u8 sup_rates[10]; + u16 rate; +} __attribute__ ((packed)); + +struct hfa384x_hostscan_result { + u16 chid; + u16 anl; + u16 sl; + u8 bssid[6]; + u16 beacon_interval; + u16 capability; + u16 ssid_len; + u8 ssid[32]; + u8 sup_rates[10]; + u16 rate; + u16 atim; +} __attribute__ ((packed)); + +struct comm_tallies_sums { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_wep_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + + +struct hfa384x_regs { + u16 cmd; + u16 evstat; + u16 offset0; + u16 offset1; + u16 swsupport0; +}; + + +#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) +/* I/O ports for HFA384X Controller access */ +#define HFA384X_CMD_OFF 0x00 +#define HFA384X_PARAM0_OFF 0x02 +#define HFA384X_PARAM1_OFF 0x04 +#define HFA384X_PARAM2_OFF 0x06 +#define HFA384X_STATUS_OFF 0x08 +#define HFA384X_RESP0_OFF 0x0A +#define HFA384X_RESP1_OFF 0x0C +#define HFA384X_RESP2_OFF 0x0E +#define HFA384X_INFOFID_OFF 0x10 +#define HFA384X_CONTROL_OFF 0x14 +#define HFA384X_SELECT0_OFF 0x18 +#define HFA384X_SELECT1_OFF 0x1A +#define HFA384X_OFFSET0_OFF 0x1C +#define HFA384X_OFFSET1_OFF 0x1E +#define HFA384X_RXFID_OFF 0x20 +#define HFA384X_ALLOCFID_OFF 0x22 +#define HFA384X_TXCOMPLFID_OFF 0x24 +#define HFA384X_SWSUPPORT0_OFF 0x28 +#define HFA384X_SWSUPPORT1_OFF 0x2A +#define HFA384X_SWSUPPORT2_OFF 0x2C +#define HFA384X_EVSTAT_OFF 0x30 +#define HFA384X_INTEN_OFF 0x32 +#define HFA384X_EVACK_OFF 0x34 +#define HFA384X_DATA0_OFF 0x36 +#define HFA384X_DATA1_OFF 0x38 +#define HFA384X_AUXPAGE_OFF 0x3A +#define HFA384X_AUXOFFSET_OFF 0x3C +#define HFA384X_AUXDATA_OFF 0x3E +#endif /* PRISM2_PCCARD || PRISM2_PLX */ + +#ifdef PRISM2_PCI +/* Memory addresses for ISL3874 controller access */ +#define HFA384X_CMD_OFF 0x00 +#define HFA384X_PARAM0_OFF 0x04 +#define HFA384X_PARAM1_OFF 0x08 +#define HFA384X_PARAM2_OFF 0x0C +#define HFA384X_STATUS_OFF 0x10 +#define HFA384X_RESP0_OFF 0x14 +#define HFA384X_RESP1_OFF 0x18 +#define HFA384X_RESP2_OFF 0x1C +#define HFA384X_INFOFID_OFF 0x20 +#define HFA384X_CONTROL_OFF 0x28 +#define HFA384X_SELECT0_OFF 0x30 +#define HFA384X_SELECT1_OFF 0x34 +#define HFA384X_OFFSET0_OFF 0x38 +#define HFA384X_OFFSET1_OFF 0x3C +#define HFA384X_RXFID_OFF 0x40 +#define HFA384X_ALLOCFID_OFF 0x44 +#define HFA384X_TXCOMPLFID_OFF 0x48 +#define HFA384X_PCICOR_OFF 0x4C +#define HFA384X_SWSUPPORT0_OFF 0x50 +#define HFA384X_SWSUPPORT1_OFF 0x54 +#define HFA384X_SWSUPPORT2_OFF 0x58 +#define HFA384X_PCIHCR_OFF 0x5C +#define HFA384X_EVSTAT_OFF 0x60 +#define HFA384X_INTEN_OFF 0x64 +#define HFA384X_EVACK_OFF 0x68 +#define HFA384X_DATA0_OFF 0x6C +#define HFA384X_DATA1_OFF 0x70 +#define HFA384X_AUXPAGE_OFF 0x74 +#define HFA384X_AUXOFFSET_OFF 0x78 +#define HFA384X_AUXDATA_OFF 0x7C +#define HFA384X_PCI_M0_ADDRH_OFF 0x80 +#define HFA384X_PCI_M0_ADDRL_OFF 0x84 +#define HFA384X_PCI_M0_LEN_OFF 0x88 +#define HFA384X_PCI_M0_CTL_OFF 0x8C +#define HFA384X_PCI_STATUS_OFF 0x98 +#define HFA384X_PCI_M1_ADDRH_OFF 0xA0 +#define HFA384X_PCI_M1_ADDRL_OFF 0xA4 +#define HFA384X_PCI_M1_LEN_OFF 0xA8 +#define HFA384X_PCI_M1_CTL_OFF 0xAC + +/* PCI bus master control bits (these are undocumented; based on guessing and + * experimenting..) */ +#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) +#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) + +#endif /* PRISM2_PCI */ + + +/* Command codes for CMD reg. */ +#define HFA384X_CMDCODE_INIT 0x00 +#define HFA384X_CMDCODE_ENABLE 0x01 +#define HFA384X_CMDCODE_DISABLE 0x02 +#define HFA384X_CMDCODE_ALLOC 0x0A +#define HFA384X_CMDCODE_TRANSMIT 0x0B +#define HFA384X_CMDCODE_INQUIRE 0x11 +#define HFA384X_CMDCODE_ACCESS 0x21 +#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) +#define HFA384X_CMDCODE_DOWNLOAD 0x22 +#define HFA384X_CMDCODE_READMIF 0x30 +#define HFA384X_CMDCODE_WRITEMIF 0x31 +#define HFA384X_CMDCODE_TEST 0x38 + +#define HFA384X_CMDCODE_MASK 0x3F + +/* Test mode operations */ +#define HFA384X_TEST_CHANGE_CHANNEL 0x08 +#define HFA384X_TEST_MONITOR 0x0B +#define HFA384X_TEST_STOP 0x0F +#define HFA384X_TEST_CFG_BITS 0x15 +#define HFA384X_TEST_CFG_BIT_ALC BIT(3) + +#define HFA384X_CMD_BUSY BIT(15) + +#define HFA384X_CMD_TX_RECLAIM BIT(8) + +#define HFA384X_OFFSET_ERR BIT(14) +#define HFA384X_OFFSET_BUSY BIT(15) + + +/* ProgMode for download command */ +#define HFA384X_PROGMODE_DISABLE 0 +#define HFA384X_PROGMODE_ENABLE_VOLATILE 1 +#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 +#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 + +#define HFA384X_AUX_MAGIC0 0xfe01 +#define HFA384X_AUX_MAGIC1 0xdc23 +#define HFA384X_AUX_MAGIC2 0xba45 + +#define HFA384X_AUX_PORT_DISABLED 0 +#define HFA384X_AUX_PORT_DISABLE BIT(14) +#define HFA384X_AUX_PORT_ENABLE BIT(15) +#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) +#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) + +#define PRISM2_PDA_SIZE 1024 + + +/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ +#define HFA384X_EV_TICK BIT(15) +#define HFA384X_EV_WTERR BIT(14) +#define HFA384X_EV_INFDROP BIT(13) +#ifdef PRISM2_PCI +#define HFA384X_EV_PCI_M1 BIT(9) +#define HFA384X_EV_PCI_M0 BIT(8) +#endif /* PRISM2_PCI */ +#define HFA384X_EV_INFO BIT(7) +#define HFA384X_EV_DTIM BIT(5) +#define HFA384X_EV_CMD BIT(4) +#define HFA384X_EV_ALLOC BIT(3) +#define HFA384X_EV_TXEXC BIT(2) +#define HFA384X_EV_TX BIT(1) +#define HFA384X_EV_RX BIT(0) + + +/* HFA384X Information frames */ +#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ +#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ +#define HFA384X_INFO_COMMTALLIES 0xF100 +#define HFA384X_INFO_SCANRESULTS 0xF101 +#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ +#define HFA384X_INFO_HOSTSCANRESULTS 0xF103 +#define HFA384X_INFO_LINKSTATUS 0xF200 +#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ +#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ +#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ +#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ + +enum { HFA384X_LINKSTATUS_CONNECTED = 1, + HFA384X_LINKSTATUS_DISCONNECTED = 2, + HFA384X_LINKSTATUS_AP_CHANGE = 3, + HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, + HFA384X_LINKSTATUS_AP_IN_RANGE = 5, + HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; + +enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, + HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, + HFA384X_PORTTYPE_HOSTAP = 6 }; + +#define HFA384X_RATES_1MBPS BIT(0) +#define HFA384X_RATES_2MBPS BIT(1) +#define HFA384X_RATES_5MBPS BIT(2) +#define HFA384X_RATES_11MBPS BIT(3) + +#define HFA384X_ROAMING_FIRMWARE 1 +#define HFA384X_ROAMING_HOST 2 +#define HFA384X_ROAMING_DISABLED 3 + +#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) +#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) +#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) +#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) + +#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) +#define HFA384X_RX_STATUS_PCF BIT(12) +#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) +#define HFA384X_RX_STATUS_UNDECR BIT(1) +#define HFA384X_RX_STATUS_FCSERR BIT(0) + +#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ +(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) +#define HFA384X_RX_STATUS_GET_MACPORT(s) \ +(((s) & HFA384X_RX_STATUS_MACPORT) >> 8) + +enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, + HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; + + +#define HFA384X_TX_CTRL_ALT_RTRY BIT(5) +#define HFA384X_TX_CTRL_802_11 BIT(3) +#define HFA384X_TX_CTRL_802_3 0 +#define HFA384X_TX_CTRL_TX_EX BIT(2) +#define HFA384X_TX_CTRL_TX_OK BIT(1) + +#define HFA384X_TX_STATUS_RETRYERR BIT(0) +#define HFA384X_TX_STATUS_AGEDERR BIT(1) +#define HFA384X_TX_STATUS_DISCON BIT(2) +#define HFA384X_TX_STATUS_FORMERR BIT(3) + +/* HFA3861/3863 (BBP) Control Registers */ +#define HFA386X_CR_TX_CONFIGURE 0x12 +#define HFA386X_CR_RX_CONFIGURE 0x14 +#define HFA386X_CR_A_D_TEST_MODES2 0x1A +#define HFA386X_CR_MANUAL_TX_POWER 0x3E + + +#ifdef __KERNEL__ + +#define PRISM2_TXFID_COUNT 8 +#define PRISM2_DATA_MAXLEN 2304 +#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) +#define PRISM2_TXFID_EMPTY 0xffff +#define PRISM2_TXFID_RESERVED 0xfffe +#define PRISM2_DUMMY_FID 0xffff +#define MAX_SSID_LEN 32 +#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ + +#define PRISM2_DUMP_RX_HDR BIT(0) +#define PRISM2_DUMP_TX_HDR BIT(1) +#define PRISM2_DUMP_TXEXC_HDR BIT(2) + +struct hostap_tx_callback_info { + u16 idx; + void (*func)(struct sk_buff *, int ok, void *); + void *data; + struct hostap_tx_callback_info *next; +}; + + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define PRISM2_FRAG_CACHE_LEN 4 + +struct prism2_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + + +struct prism2_crypt_data { + struct list_head list; /* delayed deletion list */ + struct hostap_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +struct hostap_cmd_queue { + struct list_head list; + wait_queue_head_t compl; + volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; + void (*callback)(struct net_device *dev, void *context, u16 resp0, + u16 res); + void *context; + u16 cmd, param0, param1; + u16 resp0, res; + volatile int issued, issuing; + + atomic_t usecnt; + int del_req; +}; + +/* options for hw_shutdown */ +#define HOSTAP_HW_NO_DISABLE BIT(0) +#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) + +typedef struct local_info local_info_t; + +struct prism2_helper_functions { + /* these functions are defined in hardware model specific files + * (hostap_{cs,plx,pci}.c */ + int (*card_present)(local_info_t *local); + void (*cor_sreset)(local_info_t *local); + int (*dev_open)(local_info_t *local); + int (*dev_close)(local_info_t *local); + void (*genesis_reset)(local_info_t *local, int hcr); + + /* the following functions are from hostap_hw.c, but they may have some + * hardware model specific code */ + + /* FIX: low-level commands like cmd might disappear at some point to + * make it easier to change them if needed (e.g., cmd would be replaced + * with write_mif/read_mif/testcmd/inquire); at least get_rid and + * set_rid might move to hostap_{cs,plx,pci}.c */ + int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, + u16 *resp0); + void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); + int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, + int exact_len); + int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); + int (*hw_enable)(struct net_device *dev, int initial); + int (*hw_config)(struct net_device *dev, int initial); + void (*hw_reset)(struct net_device *dev); + void (*hw_shutdown)(struct net_device *dev, int no_disable); + int (*reset_port)(struct net_device *dev); + int (*tx)(struct sk_buff *skb, struct net_device *dev); + void (*schedule_reset)(local_info_t *local); +#ifdef PRISM2_DOWNLOAD_SUPPORT + int (*download)(local_info_t *local, + struct prism2_download_param *param); +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + int (*tx_80211)(struct sk_buff *skb, struct net_device *dev); +}; + + +struct prism2_download_data { + u32 dl_cmd; + u32 start_addr; + u32 num_areas; + struct prism2_download_data_area { + u32 addr; /* wlan card address */ + u32 len; + u8 *data; /* allocated data */ + } data[0]; +}; + + +/* Per radio private Host AP data - shared by all net devices interfaces used + * by each radio (wlan#, wlan#ap, wlan#sta, WDS). + * ((struct hostap_interface *) dev->priv)->local points to this structure. */ +struct local_info { + struct module *hw_module; + int card_idx; + int dev_enabled; + struct net_device *dev; /* main radio device */ + struct list_head hostap_interfaces; /* Host AP interface list (contains + * struct hostap_interface entries) + */ + rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock + * when removing entries from the list. + * TX and RX paths can use read lock. */ + spinlock_t cmdlock, baplock, lock; + struct semaphore rid_bap_sem; + u16 infofid; /* MAC buffer id for info frame */ + /* txfid, intransmitfid, next_txtid, and next_alloc are protected by + * txfidlock */ + spinlock_t txfidlock; + int txfid_len; /* length of allocated TX buffers */ + u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ + /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if + * corresponding txfid is free for next TX frame */ + u16 intransmitfid[PRISM2_TXFID_COUNT]; + int next_txfid; /* index to the next txfid to be checked for + * availability */ + int next_alloc; /* index to the next intransmitfid to be checked for + * allocation events */ + + /* bitfield for atomic bitops */ +#define HOSTAP_BITS_TRANSMIT 0 +#define HOSTAP_BITS_BAP_TASKLET 1 +#define HOSTAP_BITS_BAP_TASKLET2 2 + long bits; + + struct ap_data *ap; + + char essid[MAX_SSID_LEN + 1]; + char name[MAX_NAME_LEN + 1]; + int name_set; + u16 channel_mask; + struct comm_tallies_sums comm_tallies; + struct net_device_stats stats; + struct proc_dir_entry *proc; + int iw_mode; /* operating mode (IW_MODE_*) */ + int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS + * 1: IW_MODE_ADHOC is "pseudo IBSS" */ + char bssid[ETH_ALEN]; + int channel; + int beacon_int; + int dtim_period; + int disable_on_close; + int mtu; + int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ + int fw_tx_rate_control; + u16 tx_rate_control; + u16 basic_rates; + int hw_resetting; + int hw_ready; + int hw_reset_tries; /* how many times reset has been tried */ + int hw_downloading; + int shutdown; + int pri_only; + + enum { + PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, + PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN + } txpower_type; + int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ + + /* command queue for hfa384x_cmd(); protected with cmdlock */ + struct list_head cmd_queue; + /* max_len for cmd_queue; in addition, cmd_callback can use two + * additional entries to prevent sleeping commands from stopping + * transmits */ +#define HOSTAP_CMD_QUEUE_MAX_LEN 16 + int cmd_queue_len; /* number of entries in cmd_queue */ + + /* if card timeout is detected in interrupt context, reset_queue is + * used to schedule card reseting to be done in user context */ + HOSTAP_QUEUE reset_queue; + + /* For scheduling a change of the promiscuous mode RID */ + int is_promisc; + HOSTAP_QUEUE set_multicast_list_queue; + + int wds_max_connections; + int wds_connections; +#define HOSTAP_WDS_BROADCAST_RA BIT(0) +#define HOSTAP_WDS_AP_CLIENT BIT(1) +#define HOSTAP_WDS_STANDARD_FRAME BIT(2) + u32 wds_type; + u16 tx_control; /* flags to be used in TX description */ + int manual_retry_count; /* -1 = use f/w default; otherwise retry count + * to be used with all frames */ + +#ifdef WIRELESS_EXT + struct iw_statistics wstats; +#if WIRELESS_EXT > 13 + unsigned long scan_timestamp; /* Time started to scan */ +#endif /* WIRELESS_EXT > 13 */ +#endif /* WIRELESS_EXT */ + enum { + PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, + PRISM2_MONITOR_CAPHDR = 2 + } monitor_type; + int (*saved_eth_header_parse)(struct sk_buff *skb, + unsigned char *haddr); + int monitor_allow_fcserr; + + int hostapd; /* whether user space daemon, hostapd, is used for AP + * management */ + struct net_device *apdev; + struct net_device_stats apdevstats; + + char assoc_ap_addr[ETH_ALEN]; + struct net_device *stadev; + struct net_device_stats stadevstats; + + struct prism2_crypt_data *crypt; + struct timer_list crypt_deinit_timer; + struct list_head crypt_deinit_list; + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 + int open_wep; /* allow unencrypted frames */ + int host_encrypt; + int host_decrypt; + int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working + * in Host AP mode (STA f/w 1.4.9 or newer) */ + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; + unsigned int frag_next_idx; + + int ieee_802_1x; /* is IEEE 802.1X used */ + + int antsel_tx, antsel_rx; + int rts_threshold; /* dot11RTSThreshold */ + int fragm_threshold; /* dot11FragmentationThreshold */ + int auth_algs; /* PRISM2_AUTH_ flags */ + + int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ + int tallies32; /* 32-bit tallies in use */ + + struct prism2_helper_functions *func; + + int bus_master_threshold_tx; + int bus_master_threshold_rx; + u8 *bus_m1_buf; + + u8 *pda; + int fw_ap; +#define PRISM2_FW_VER(major, minor, variant) \ +(((major) << 16) | ((minor) << 8) | variant) + u32 sta_fw_ver; + + /* Tasklets for handling hardware IRQ related operations outside hw IRQ + * handler */ + HOSTAP_TASKLET bap_tasklet; + + HOSTAP_TASKLET info_tasklet; + struct sk_buff_head info_list; /* info frames as skb's for + * info_tasklet */ + + struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks + */ + + HOSTAP_TASKLET rx_tasklet; + struct sk_buff_head rx_list; + + HOSTAP_TASKLET sta_tx_exc_tasklet; + struct sk_buff_head sta_tx_exc_list; + + int host_roaming; + unsigned long last_join_time; /* time of last JoinRequest */ + struct hfa384x_scan_result *last_scan_results; + int last_scan_results_count; + struct hfa384x_hostscan_result *last_hostscan_results; + int last_hostscan_results_count; + enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; + HOSTAP_QUEUE info_queue; + long pending_info; /* bit field of pending info_queue items */ +#define PRISM2_INFO_PENDING_LINKSTATUS 0 +#define PRISM2_INFO_PENDING_SCANRESULTS 1 + int prev_link_status; /* previous received LinkStatus info */ + u8 preferred_ap[6]; /* use this AP if possible */ + +#ifdef PRISM2_CALLBACK + void *callback_data; /* Can be used in callbacks; e.g., allocate + * on enable event and free on disable event. + * Host AP driver code does not touch this. */ +#endif /* PRISM2_CALLBACK */ + + wait_queue_head_t hostscan_wq; + + /* Passive scan in Host AP mode */ + struct timer_list passive_scan_timer; + int passive_scan_interval; /* in seconds, 0 = disabled */ + int passive_scan_channel; + enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; + + struct timer_list tick_timer; + unsigned long last_tick_timer; + unsigned int sw_tick_stuck; + +#ifdef PRISM2_DOWNLOAD_SUPPORT + /* Persistent volatile download data */ + struct prism2_download_data *dl_pri; + struct prism2_download_data *dl_sec; +#endif /* PRISM2_DOWNLOAD_SUPPORT */ + +#ifdef PRISM2_IO_DEBUG +#define PRISM2_IO_DEBUG_SIZE 10000 + u32 io_debug[PRISM2_IO_DEBUG_SIZE]; + int io_debug_head; + int io_debug_enabled; +#endif /* PRISM2_IO_DEBUG */ + + /* struct local_info is used also in hostap.o that does not define + * any PRISM2_{PCCARD,PLX,PCI}. Make sure that the hardware version + * specific fields are in the end of the struct (these could also be + * moved to void *priv or something like that). */ +#ifdef PRISM2_PCCARD + dev_node_t node; + dev_link_t *link; +#endif /* PRISM2_PCCARD */ + +#ifdef PRISM2_PLX + unsigned long attr_mem; + unsigned int cor_offset; +#endif /* PRISM2_PLX */ + +#ifdef PRISM2_PCI +#ifdef PRISM2_BUS_MASTER + /* bus master for BAP0 (TX) */ + int bus_m0_tx_idx; + u8 *bus_m0_buf; + + /* bus master for BAP1 (RX) */ + struct sk_buff *rx_skb; +#endif /* PRISM2_BUS_MASTER */ +#ifdef CONFIG_PM + u32 pci_save_state[16]; +#endif /* CONFIG_PM */ +#endif /* PRISM2_PCI */ + + /* NOTE! Do not add common entries here after hardware version + * specific blocks. */ +}; + + +/* Per interface private Host AP data + * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, + * WDS) and dev->priv points to this structure. */ +struct hostap_interface { + struct list_head list; /* list entry in Host AP interface list */ + struct net_device *dev; /* pointer to this device */ + struct local_info *local; /* pointer to shared private data */ + struct net_device_stats stats; +#if WIRELESS_EXT > 15 + /* Note: this data area must be at a fixed offset from dev->priv. + * Unfortunately, this model does not fit the current Host AP netdev + * data structure because this should really be in local_into_t that is + * shared by all virtual interfaces. Currently, only the main data + * device (wlan#) is used for iwspy entries. */ + struct iw_spy_data spy_data; /* iwspy support */ +#endif /* WIRELESS_EXT > 15 */ + + enum { + HOSTAP_INTERFACE_MAIN, + HOSTAP_INTERFACE_AP, + HOSTAP_INTERFACE_STA, + HOSTAP_INTERFACE_WDS, + } type; + + union { + struct hostap_interface_wds { + u8 remote_addr[ETH_ALEN]; + } wds; + } u; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + /* struct net_device did not allocate buffer for device name in + * Linux 2.2, so reserve space for it here to provide backwards + * compatibility. */ + char name[IFNAMSIZ]; +#endif +}; + + +#ifndef PRISM2_NO_DEBUG + +#define DEBUG_FID BIT(0) +#define DEBUG_PS BIT(1) +#define DEBUG_FLOW BIT(2) +#define DEBUG_AP BIT(3) +#define DEBUG_HW BIT(4) +#define DEBUG_EXTRA BIT(5) +#define DEBUG_EXTRA2 BIT(6) +#define DEBUG_PS2 BIT(7) +#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) +#define PDEBUG(n, args...) \ +do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) +#define PDEBUG2(n, args...) \ +do { if ((n) & DEBUG_MASK) printk(args); } while (0) + +#else /* PRISM2_NO_DEBUG */ + +#define PDEBUG(n, args...) +#define PDEBUG2(n, args...) + +#endif /* PRISM2_NO_DEBUG */ + +enum { BAP0 = 0, BAP1 = 1 }; + +#define PRISM2_IO_DEBUG_CMD_INB 0 +#define PRISM2_IO_DEBUG_CMD_INW 1 +#define PRISM2_IO_DEBUG_CMD_INSW 2 +#define PRISM2_IO_DEBUG_CMD_OUTB 3 +#define PRISM2_IO_DEBUG_CMD_OUTW 4 +#define PRISM2_IO_DEBUG_CMD_OUTSW 5 +#define PRISM2_IO_DEBUG_CMD_ERROR 6 +#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 + +#ifdef PRISM2_IO_DEBUG + +#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ +(((cmd) << 24) | ((reg) << 16) | value) + +static inline void prism2_io_debug_add(struct net_device *dev, int cmd, + int reg, int value) +{ + local_info_t *local = dev->priv; + + if (!local->io_debug_enabled) + return; + + local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; + if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) + local->io_debug_head = 0; + local->io_debug[local->io_debug_head] = + PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); + if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) + local->io_debug_head = 0; +} + + +static inline void prism2_io_debug_error(struct net_device *dev, int err) +{ + local_info_t *local = dev->priv; + unsigned long flags; + + if (!local->io_debug_enabled) + return; + + spin_lock_irqsave(&local->lock, flags); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); + if (local->io_debug_enabled == 1) { + local->io_debug_enabled = 0; + printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); + } + spin_unlock_irqrestore(&local->lock, flags); +} + +#else /* PRISM2_IO_DEBUG */ + +static inline void prism2_io_debug_add(struct net_device *dev, int cmd, + int reg, int value) +{ +} + +static inline void prism2_io_debug_error(struct net_device *dev, int err) +{ +} + +#endif /* PRISM2_IO_DEBUG */ + + +#ifdef PRISM2_CALLBACK +enum { + /* Called when card is enabled */ + PRISM2_CALLBACK_ENABLE, + + /* Called when card is disabled */ + PRISM2_CALLBACK_DISABLE, + + /* Called when RX/TX starts/ends */ + PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, + PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END +}; +void prism2_callback(local_info_t *local, int event); +#else /* PRISM2_CALLBACK */ +#define prism2_callback(d, e) do { } while (0) +#endif /* PRISM2_CALLBACK */ + +#endif /* __KERNEL__ */ + +#endif /* HOSTAP_WLAN_H */ diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Thu Dec 4 16:24:26 2003 +++ b/drivers/pci/pci.ids Thu Dec 4 16:24:26 2003 @@ -5985,6 +5985,7 @@ 104d 80df Vaio PCG-FX403 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller 8086 1161 82806AA PCI64 Hub APIC + 1162 XS80200 Big Endian Companion Chip (BECC) 1200 Intel IXP1200 Network Processor 172a 0000 AEP SSL Accelerator 1209 82559ER @@ -6406,6 +6407,7 @@ 84e4 460GX - 84460GX Memory Data Controller (MDC) 84e6 460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB) 84ea 460GX - 84460GX AGP Bridge (GXB function 1) + 9001 IXP2000 Network Processor 9621 Integrated RAID 9622 Integrated RAID 9641 Integrated RAID diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c Thu Dec 4 16:24:25 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c Thu Dec 4 16:24:25 2003 @@ -799,6 +799,20 @@ ahc->dev_softc->dma_mask = 0xFFFFFFFF; #endif } + +#ifdef CONFIG_ARM + /* pci_alloc_consistent() in ARM arch is not supported in */ + /* interrupt space. Although should really not alloc mem */ + /* in interupt space anyhow. Adaptec has no plan to fix */ + /* it any time soon and supporting alloc_consistent() */ + /* in IRQ space for ARM is not high on RMK's list. This */ + /* would be a temp hack until something better is done */ + if(in_interrupt()) + { + return ENOMEM; + } +#endif + *vaddr = pci_alloc_consistent(ahc->dev_softc, dmat->maxsize, &map->bus_addr); if (ahc->dev_softc != NULL) { diff -Nru a/drivers/serial/Config.in b/drivers/serial/Config.in --- a/drivers/serial/Config.in Thu Dec 4 16:24:25 2003 +++ b/drivers/serial/Config.in Thu Dec 4 16:24:25 2003 @@ -61,6 +61,7 @@ "$CONFIG_SERIAL_SA1100" = "y" -o \ "$CONFIG_SERIAL_ANAKIN" = "y" -o \ "$CONFIG_SERIAL_UART00" = "y" -o \ + "$CONFIG_SERIAL_IXP1200" = "y" -o \ "$CONFIG_SERIAL_8250" = "y" -o \ "$CONFIG_SERIAL_OMAHA" = "y" -o \ "$CONFIG_SERIAL_AT91" = "y" ]; then @@ -83,6 +84,7 @@ "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_8250_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_IXP1200_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_OMAHA" = "y" -o \ "$CONFIG_SERIAL_AT91_CONSOLE" = "y" ]; then define_bool CONFIG_SERIAL_CORE_CONSOLE y diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Thu Dec 4 16:24:25 2003 +++ b/drivers/serial/Makefile Thu Dec 4 16:24:25 2003 @@ -30,6 +30,7 @@ obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_UART00) += uart00.o +obj-$(CONFIG_SERIAL_IXP1200) += ixp1200.o obj-$(CONFIG_SERIAL_OMAHA) += omaha.o obj-$(CONFIG_SERIAL_AT91US3) += at91us3.o diff -Nru a/drivers/serial/ixp1200.c b/drivers/serial/ixp1200.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/ixp1200.c Thu Dec 4 16:24:26 2003 @@ -0,0 +1,585 @@ +/* + * linux/drivers/serial/serial_ixp1200.c + * + * Driver for IXP1200 serial console + * + * Copyright (c) 2001, 2002 MontaVista Software, Inc + * Author: Deepak Saxena + * + * Heavilly based on original code from Intel 2.3.99-pre3 driver. + * Deep Blue Solution's serial_sa1100.c driver used as a guide. + * + * 05/03/2001: + * Ported SA1xx driver to IXP1200 + * 02/12/2002: + * Massive rewrite to make it fit new serial layer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SERIAL_IXP1200_CONSOLE +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#define IXP1200_ISR_PASS_LIMIT 256 +#define NR_PORTS 1 + +static struct tty_driver normal, callout; +static struct tty_struct *ixp1200_table[NR_PORTS]; +static struct termios *ixp1200_termios[NR_PORTS], + *ixp1200_termios_locked[NR_PORTS]; + + +#ifdef CONFIG_SERIAL_IXP1200_CONSOLE +static struct console ixp1200_console; +#endif + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_IXP1200_MAJOR 204 +#define CALLOUT_IXP1200_MAJOR 205 +#define MINOR_START 5 + +static inline unsigned int serial_in(struct uart_port*port, int offset) +{ + return ((volatile unsigned long *)port->membase)[offset]; +} + +static inline void serial_out(struct uart_port *port, int offset, int value) +{ + ((volatile unsigned long *)port->membase)[offset] = value; +} + +static void ixp1200_stop_tx(struct uart_port *port, u_int from_tty) +{ + u32 utcr = serial_in(port, UTCR); + serial_out(port, UTCR, utcr & ~UTCR_XIE); + port->read_status_mask &= ~UTSR_TXR; +} + +static void ixp1200_start_tx(struct uart_port *port, u_int nonempty, + u_int from_tty) +{ + if(nonempty) + { + u32 utcr; + unsigned long flags; + + local_irq_save(flags); + utcr = serial_in(port, UTCR); + port->read_status_mask |= UTSR_TXR; + serial_out(port, UTCR, utcr | UTCR_XIE); + local_irq_restore(flags); + } +} + +static void ixp1200_stop_rx(struct uart_port *port) +{ + u32 utcr = serial_in(port, UTCR); + serial_out(port, UTCR, utcr & ~UTCR_RIE); +} + +static void ixp1200_enable_ms(struct uart_port *port) +{ + return; +} + +static void inline ixp1200_rx_chars(struct uart_info *info) +{ + struct tty_struct *tty = info->tty; + unsigned char status, ch, flg, ignored = 0; + struct uart_port *port = info->port; + + status = serial_in(port, UTSR); + + while(status & UTSR_RXR) + { + ch = (unsigned char)serial_in(port, UART_RX); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + port->icount.rx++; + + flg = TTY_NORMAL; + + if (status & (UTSR_RPE | UTSR_RFE | UTSR_ROR)) + goto handle_error; + if(uart_handle_sysrq_char(info, ch, regs)) + goto ignore_char; + + error_return: + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + ignore_char: + status = serial_in(port, UTSR); + } +out: + tty_flip_buffer_push(tty); + return; + +handle_error: + if(status & UTSR_RPE) + port->icount.parity++; + if(status & UTSR_RFE) + port->icount.frame++; + if(status & UTSR_ROR) + port->icount.overrun++; + + if(status & port->ignore_status_mask) + { + if(++ignored > 100) + goto out; + goto ignore_char; + } + + status &= port->read_status_mask; + + if(status & UTSR_RPE) + flg = TTY_PARITY; + else if(status & UTSR_RFE) + flg = TTY_FRAME; + + if (status & UTSR_ROR) { + /* + * overrun does *not* affect the character + * we read from the FIFO + */ + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + ch = 0; + flg = TTY_OVERRUN; + } +#ifdef SUPPORT_SYSRQ + info->sysrq = 0; +#endif + goto error_return; +} + +static void inline ixp1200_tx_chars(struct uart_info *info) +{ + int count; + struct uart_port *port = info->port; + + if (port->x_char) { + serial_out(port, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + ixp1200_stop_tx(info->port, 0); + return; + } + + while(serial_in(port, UTSR) & UTSR_TXR) { + serial_out(port, UART_TX, info->xmit.buf[info->xmit.tail]); + info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE-1); + port->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + }; + + if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < + WAKEUP_CHARS) + uart_event(info, EVT_WRITE_WAKEUP); + + if (info->xmit.head == info->xmit.tail) + ixp1200_stop_tx(info->port, 0); +} + +static void ixp1200_serial_int(int irq, void *dev_id, struct pt_regs * regs) +{ + struct uart_info *info = (struct uart_info *)dev_id; + struct uart_port *port = info->port; + int status; + int pass_counter = 0; + + status = serial_in(port, UTSR); + status &= (port->read_status_mask | UTSR_TXE); + do { + if (status & UTSR_RXR) + ixp1200_rx_chars(info); + + if (status & UTSR_TXE) + ixp1200_tx_chars(info); + + if (pass_counter++ > IXP1200_ISR_PASS_LIMIT) { + break; + } + + status = serial_in(port, UTSR); + status &= port->read_status_mask | UTSR_TXE; + + } while (status); +} + + +static u_int ixp1200_tx_empty(struct uart_port *port) +{ + return (serial_in(port, UTSR) & UTSR_TXE); +} + +static void ixp1200_set_mctrl(struct uart_port *port, u_int mctrl) +{ + return; +} + +static u_int ixp1200_get_mctrl(struct uart_port *unused) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void ixp1200_break_ctl(struct uart_port *port, int break_state) +{ + u32 utcr = serial_in(port, UTCR); + + if(break_state == -1) + utcr |= UTCR_BRK; + else + utcr &= ~UTCR_BRK; + + serial_out(port, UTCR, utcr); +} + +static int ixp1200_startup(struct uart_port *port, struct uart_info *info) +{ + int retval=0; + + retval = request_irq(port->irq, ixp1200_serial_int, SA_INTERRUPT, + "serial_ixp1200", (void*)info); + if (retval) + return retval; + + /* + * Enable interrupts + */ + serial_out(port, UTCR, UTCR_EN | UTCR_RIE | UTCR_XIE); + + return 0; +} + +static void ixp1200_shutdown(struct uart_port *port, struct uart_info *info) +{ + free_irq(port->irq, info); + + serial_out(port, UTCR, 0); /* disable UART */ +} + +static void ixp1200_change_speed(struct uart_port *port, u_int cflag, + u_int iflag, u_int quot) +{ + unsigned long flags; + unsigned int utcr, utcr_old; + u32 status; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS7: + utcr = UTCR_7_BIT; + break; + case CS8: + default: + utcr = UTCR_8_BIT; + break; + } + + if (cflag & CSTOPB) { + utcr |= UTCR_2_STOP_BIT; + } + else + utcr |= UTCR_1_STOP_BIT; + + port->read_status_mask = UTSR_RXR | UTSR_ROR | UTSR_TXE | UTSR_RXF; + + if(iflag & INPCK) + port->read_status_mask |= UTSR_RPE | UTSR_RFE; + + port->ignore_status_mask = 0; + + if(iflag & IGNPAR) + port->ignore_status_mask |= UTSR_RPE | UTSR_RFE; + + save_flags_cli(flags); + + /* + * Wait for transmiter to empty; + */ + do { + status = serial_in(port, UTSR); + } while ( !(status & UTSR_TXE )); + + utcr_old = serial_in(port, UTCR); + + /* + * Keep same interrupt state as before + */ + utcr_old &= (UTCR_XIE | UTCR_RIE); + + /* Disable everything */ + serial_out(port, UTCR, 0); + + utcr |= UTCR_EN; + utcr |= utcr_old; + + quot -= 1; + utcr |= (quot << 16); + + serial_out(port, UTCR, utcr); + + restore_flags(flags); +} + +static int ixp1200_request_port(struct uart_port *port) +{ + if(request_mem_region(port->membase, (u32)0xc00, "serial_ixp100")) + return 0; + + return -EBUSY; +} + +static void ixp1200_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 0xc00); +} + +static void ixp1200_config_port(struct uart_port *port, int flags) +{ + if(flags & UART_CONFIG_TYPE && !ixp1200_request_port(port)) + port->type = PORT_IXP1200; +} + +static int ixp1200_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if(ser->type != PORT_UNKNOWN && ser->type != PORT_IXP1200) + return -EINVAL; + if (port->irq != ser->irq) + return -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + return -EINVAL; + if (port->uartclk / 16 != ser->baud_base) + return -EINVAL; + if ((void *)port->mapbase != ser->iomem_base) + return -EINVAL; + if (port->iobase != ser->port) + return -EINVAL; + if (ser->hub6 != 0) + return -EINVAL; + + return 0; +} + +static const char *ixp1200_type(struct uart_port *port) +{ + return port->type == PORT_IXP1200 ? "IXP1200" : NULL; +} + +static struct uart_ops ixp1200_pops = { + tx_empty: ixp1200_tx_empty, + set_mctrl: ixp1200_set_mctrl, + get_mctrl: ixp1200_get_mctrl, + stop_tx: ixp1200_stop_tx, + start_tx: ixp1200_start_tx, + stop_rx: ixp1200_stop_rx, + enable_ms: ixp1200_enable_ms, + startup: ixp1200_startup, + shutdown: ixp1200_shutdown, + change_speed: ixp1200_change_speed, + release_port: ixp1200_release_port, + request_port: ixp1200_request_port, + config_port: ixp1200_config_port, + verify_port: ixp1200_verify_port, + type: ixp1200_type, +}; + +static struct uart_port ixp1200_port = +{ + uartclk:3686400, + ops:&ixp1200_pops, + fifosize:8, + membase:(void *)CSR_UARTSR, + mapbase:0x90003400, + irq:IXP1200_IRQ_UART, + iotype:SERIAL_IO_MEM, + flags:ASYNC_BOOT_AUTOCONF +}; + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_IXP1200_CONSOLE + +static kdev_t ixp1200_console_device(struct console *co) +{ + return MKDEV(SERIAL_IXP1200_MAJOR, MINOR_START + co->index); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void ixp1200_console_write(struct console *co, const char *s, + unsigned count) +{ + struct uart_port *port = &ixp1200_port; + int utcr; + unsigned i, flags; + + /* + * Save the UTCR, disable IRQs + */ + save_flags_cli(flags); + utcr = serial_in(port, UTCR); + serial_out(port, UTCR, utcr & ~(UTCR_RIE | UTCR_XIE)); + restore_flags(flags); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + while(!(serial_in(port, UTSR) & UTSR_TXR)); + serial_out(port, UART_TX, *s); + /* + * Send the character out. + * If a LF, also do CR... + */ + if (*s == '\n') { + while(!(serial_in(port, UTSR) & UTSR_TXR)); + serial_out(port, UART_TX, '\r'); + } + } + + /* + * Wait for the tranceiver to empty + */ + while(!(serial_in(port, UTSR) & UTSR_TXE)); + + /* + * Re-enable IRQs + */ + serial_out(port, UTCR, utcr); +} + +static int __init +ixp1200_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = CONFIG_IXP1200_DEFAULT_BAUDRATE; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + unsigned long utcr; + + port = uart_get_console(&ixp1200_port, NR_PORTS, co); + + serial_out(port, UTCR, 0); + + if(options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console ixp1200_console = { + name: "ttyIXP", + write: ixp1200_console_write, + device: ixp1200_console_device, + setup: ixp1200_console_setup, + flags: CON_PRINTBUFFER, + index: -1 +}; + +/* + * Register console. + */ +void __init ixp1200_console_init(void) +{ + register_console(&ixp1200_console); +} +#endif + + +#ifdef CONFIG_SERIAL_IXP1200_CONSOLE +#define IXP1200_CONSOLE &ixp1200_console +#else +#define IXP1200_CONSOLE NULL +#endif + +static struct uart_driver ixp1200_uart = { + owner: THIS_MODULE, + normal_major: SERIAL_IXP1200_MAJOR, +#ifdef CONFIG_DEVFS_FS + normal_name: "ttySA%d", + callout_name: "cusa%d", +#else + normal_name: "ttySA", + callout_name: "cusa", +#endif + normal_driver: &normal, + callout_major: CALLOUT_IXP1200_MAJOR, + callout_driver: &callout, + table: ixp1200_table, + termios: ixp1200_termios, + termios_locked: ixp1200_termios_locked, + minor: MINOR_START, + nr: NR_PORTS, + port: &ixp1200_port, + cons: IXP1200_CONSOLE +}; + +/* + * The serial driver boot-time initialization code! + */ +static int __init ixp1200_serial_init(void) +{ + return uart_register_driver(&ixp1200_uart); +} + +static void __exit ixp1200_serial_exit(void) +{ + uart_unregister_driver(&ixp1200_uart); +} + +module_init(ixp1200_serial_init); +module_exit(ixp1200_serial_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Deepak Saxena ") +MODULE_DESCRIPTION("IXP12xx serial port driver"); +MODULE_LICENSE("GPL"); + diff -Nru a/fs/Config.in b/fs/Config.in --- a/fs/Config.in Thu Dec 4 16:24:25 2003 +++ b/fs/Config.in Thu Dec 4 16:24:25 2003 @@ -45,6 +45,7 @@ dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0 + bool 'JFFS2 support for NAND chips' CONFIG_JFFS2_FS_NAND fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Thu Dec 4 16:24:25 2003 +++ b/fs/inode.c Thu Dec 4 16:24:25 2003 @@ -204,7 +204,8 @@ if ((inode->i_state & flags) != flags) { inode->i_state |= flags; /* Only add valid (ie hashed) inodes to the dirty list */ - if (!(inode->i_state & I_LOCK) && !list_empty(&inode->i_hash)) { + if (!(inode->i_state & (I_LOCK|I_FREEING|I_CLEAR)) && + !list_empty(&inode->i_hash)) { list_del(&inode->i_list); list_add(&inode->i_list, &sb->s_dirty); } @@ -233,6 +234,30 @@ __wait_on_inode(inode); } +/* + * If we try to find an inode in the inode hash while it is being deleted, we + * have to wait until the filesystem completes its deletion before reporting + * that it isn't found. This is because iget will immediately call + * ->read_inode, and we want to be sure that evidence of the deletion is found + * by ->read_inode. + * + * This call might return early if an inode which shares the waitq is woken up. + * This is most easily handled by the caller which will loop around again + * looking for the inode. + * + * This is called with inode_lock held. + */ +static void __wait_on_freeing_inode(struct inode *inode) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&inode->i_wait, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock(&inode_lock); + schedule(); + remove_wait_queue(&inode->i_wait, &wait); + spin_lock(&inode_lock); +} static inline void write_inode(struct inode *inode, int sync) { @@ -594,6 +619,11 @@ if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); + spin_lock(&inode_lock); + list_del(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_hash); + spin_unlock(&inode_lock); + wake_up(&inode->i_wait); destroy_inode(inode); inodes_stat.nr_inodes--; } @@ -702,6 +732,14 @@ * * We don't expect to have to call this very often. * + * We leave the inode in the inode hash table until *after* + * the filesystem's ->delete_inode (in dispose_list) completes. + * This ensures that an iget (such as nfsd might instigate) will + * always find up-to-date information either in the hash or on disk. + * + * I_FREEING is set so that no-one will take a new reference + * to the inode while it is being deleted. + * * N.B. The spinlock is released during the call to * dispose_list. */ @@ -734,8 +772,6 @@ if (atomic_read(&inode->i_count)) continue; list_del(tmp); - list_del(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_hash); list_add(tmp, freeable); inode->i_state |= I_FREEING; count++; @@ -788,6 +824,7 @@ struct list_head *tmp; struct inode * inode; +repeat: tmp = head; for (;;) { tmp = tmp->next; @@ -801,6 +838,10 @@ continue; if (find_actor && !find_actor(inode, ino, opaque)) continue; + if (inode->i_state & (I_FREEING|I_CLEAR)) { + __wait_on_freeing_inode(inode); + goto repeat; + } break; } return inode; @@ -942,6 +983,37 @@ } +/** + * ilookup - search for an inode in the inode cache + * @sb: super block of file system to search + * @ino: inode number to search for + * + * If the inode is in the cache, the inode is returned with an + * incremented reference count. + * + * Otherwise, %NULL is returned. + * + * This is almost certainly not the function you are looking for. + * If you think you need to use this, consult an expert first. + */ +struct inode *ilookup(struct super_block *sb, unsigned long ino) +{ + struct list_head * head = inode_hashtable + hash(sb,ino); + struct inode * inode; + + spin_lock(&inode_lock); + inode = find_inode(sb, ino, head, NULL, NULL); + if (inode) { + __iget(inode); + spin_unlock(&inode_lock); + wait_on_inode(inode); + return inode; + } + spin_unlock(&inode_lock); + + return inode; +} + struct inode *igrab(struct inode *inode) { spin_lock(&inode_lock); @@ -1040,8 +1112,6 @@ return; if (!inode->i_nlink) { - list_del(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_hash); list_del(&inode->i_list); INIT_LIST_HEAD(&inode->i_list); inode->i_state|=I_FREEING; @@ -1059,6 +1129,11 @@ delete(inode); } else clear_inode(inode); + spin_lock(&inode_lock); + list_del(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_hash); + spin_unlock(&inode_lock); + wake_up(&inode->i_wait); if (inode->i_state != I_CLEAR) BUG(); } else { diff -Nru a/fs/jffs2/Makefile b/fs/jffs2/Makefile --- a/fs/jffs2/Makefile Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/Makefile Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ # # Makefile for the linux Journalling Flash FileSystem (JFFS) routines. # -# $Id: Makefile,v 1.25.2.1 2002/10/11 09:04:44 dwmw2 Exp $ +# $Id: Makefile.common,v 1.1 2003/05/27 09:34:41 dwmw2 Exp $ # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -10,16 +10,31 @@ # Note 2! The CFLAGS definitions are now in the main makefile... -COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \ - compr_zlib.o -JFFS2_OBJS := crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \ - read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \ - symlink.o build.o erase.o background.o +obj-$(CONFIG_JFFS2_FS) := jffs2.o -O_TARGET := jffs2.o +COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o compr_zlib.o +JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \ + read.o nodemgmt.o readinode.o write.o scan.o gc.o \ + symlink.o build.o erase.o background.o fs.o writev.o + +BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/) + +ifeq ($(BELOW25),y) +LINUX_OBJS := super-v24.o crc32.o rbtree.o +else +LINUX_OBJS := super.o +endif -obj-y := $(COMPR_OBJS) $(JFFS2_OBJS) -obj-m := $(O_TARGET) +NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o +jffs2-objs := $(COMPR_OBJS) $(JFFS2_OBJS) $(VERS_OBJS) $(NAND_OBJS-y) \ + $(LINUX_OBJS) + + +# 2.4 build compatibility +ifeq ($(BELOW25),y) +obj-y := $(jffs2-objs) +O_TARGET := jffs2.o include $(TOPDIR)/Rules.make +endif diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c --- a/fs/jffs2/background.c Thu Dec 4 16:24:26 2003 +++ b/fs/jffs2/background.c Thu Dec 4 16:24:26 2003 @@ -1,61 +1,36 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: background.c,v 1.16 2001/10/08 09:22:38 dwmw2 Exp $ + * $Id: background.c,v 1.47 2003/11/26 15:30:58 dwmw2 Exp $ * */ #define __KERNEL_SYSCALLS__ #include -#include -#include #include #include -#include #include +#include +#include +#include #include "nodelist.h" static int jffs2_garbage_collect_thread(void *); -static int thread_should_wake(struct jffs2_sb_info *c); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { - spin_lock_bh(&c->erase_completion_lock); - if (c->gc_task && thread_should_wake(c)) + spin_lock(&c->erase_completion_lock); + if (c->gc_task && jffs2_thread_should_wake(c)) send_sig(SIGHUP, c->gc_task, 1); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); } /* This must only ever be called when no GC thread is currently running */ @@ -86,12 +61,12 @@ void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) { - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (c->gc_task) { D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); send_sig(SIGKILL, c->gc_task, 1); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wait_for_completion(&c->gc_thread_exit); } @@ -99,57 +74,59 @@ { struct jffs2_sb_info *c = _c; - daemonize(); - current->tty = NULL; + daemonize("jffs2_gcd_mtd%d", c->mtd->index); + allow_signal(SIGKILL); + allow_signal(SIGSTOP); + allow_signal(SIGCONT); + c->gc_task = current; up(&c->gc_thread_start); - sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); - - /* FIXME in the 2.2 backport */ - current->nice = 10; + set_user_nice(current, 10); for (;;) { - spin_lock_irq(¤t->sigmask_lock); - siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + allow_signal(SIGHUP); - if (!thread_should_wake(c)) { - set_current_state (TASK_INTERRUPTIBLE); + if (!jffs2_thread_should_wake(c)) { + set_current_state (TASK_INTERRUPTIBLE); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); - /* Yes, there's a race here; we checked thread_should_wake() before - setting current->state to TASK_INTERRUPTIBLE. But it doesn't + /* Yes, there's a race here; we checked jffs2_thread_should_wake() + before setting current->state to TASK_INTERRUPTIBLE. But it doesn't matter - We don't care if we miss a wakeup, because the GC thread is only an optimisation anyway. */ schedule(); } - - if (current->need_resched) - schedule(); - /* Put_super will send a SIGKILL and then wait on the sem. - */ - while (signal_pending(current)) { - siginfo_t info; - unsigned long signr; - - spin_lock_irq(¤t->sigmask_lock); - signr = dequeue_signal(¤t->blocked, &info); - spin_unlock_irq(¤t->sigmask_lock); - - switch(signr) { - case SIGSTOP: - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n")); - set_current_state(TASK_STOPPED); - schedule(); - break; - - case SIGKILL: - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); - spin_lock_bh(&c->erase_completion_lock); - c->gc_task = NULL; - spin_unlock_bh(&c->erase_completion_lock); + if (current->flags & PF_FREEZE) { + refrigerator(0); + /* refrigerator() should recalc sigpending for us + but doesn't. No matter - allow_signal() will. */ + continue; + } + + cond_resched(); + + /* Put_super will send a SIGKILL and then wait on the sem. + */ + while (signal_pending(current)) { + siginfo_t info; + unsigned long signr; + + signr = dequeue_signal_lock(current, ¤t->blocked, &info); + + switch(signr) { + case SIGSTOP: + D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n")); + set_current_state(TASK_STOPPED); + schedule(); + break; + + case SIGKILL: + D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); + die: + spin_lock(&c->erase_completion_lock); + c->gc_task = NULL; + spin_unlock(&c->erase_completion_lock); complete_and_exit(&c->gc_thread_exit, 0); case SIGHUP: @@ -157,27 +134,15 @@ break; default: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr)); - - } - } + } + } /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ - spin_lock_irq(¤t->sigmask_lock); - siginitsetinv (¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + disallow_signal(SIGHUP); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n")); - jffs2_garbage_collect_pass(c); + if (jffs2_garbage_collect_pass(c) == -ENOSPC) { + printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n"); + goto die; + } } -} - -static int thread_should_wake(struct jffs2_sb_info *c) -{ - D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n", - c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size)); - if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && - c->dirty_size > c->sector_size) - return 1; - else - return 0; } diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c --- a/fs/jffs2/build.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/build.c Thu Dec 4 16:24:25 2003 @@ -1,47 +1,22 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: build.c,v 1.16.2.3 2003/04/30 09:43:32 dwmw2 Exp $ + * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $ * */ #include -#include +#include #include #include "nodelist.h" -int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); -int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); +static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); static inline struct jffs2_inode_cache * first_inode_chain(int *i, struct jffs2_sb_info *c) @@ -68,16 +43,52 @@ ic; \ ic = next_inode(&i, ic, (c))) + +static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_full_dirent *fd; + + D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino)); + + /* For each child, increase nlink */ + for(fd = ic->scan_dents; fd; fd = fd->next) { + struct jffs2_inode_cache *child_ic; + if (!fd->ino) + continue; + + /* XXX: Can get high latency here with huge directories */ + + child_ic = jffs2_get_ino_cache(c, fd->ino); + if (!child_ic) { + printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", + fd->name, fd->ino, ic->ino); + continue; + } + + if (child_ic->nlink++ && fd->type == DT_DIR) { + printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino); + if (fd->ino == 1 && ic->ino == 1) { + printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); + printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); + } + /* What do we do about it? */ + } + D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); + /* Can't free them. We might need them in pass 2 */ + } +} + /* Scan plan: - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go - Scan directory tree from top down, setting nlink in inocaches - Scan inocaches for inodes with nlink==0 */ -int jffs2_build_filesystem(struct jffs2_sb_info *c) +static int jffs2_build_filesystem(struct jffs2_sb_info *c) { int ret; int i; struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *dead_fds = NULL; /* First, scan the medium and build all the inode caches with lists of physical nodes */ @@ -90,14 +101,17 @@ return ret; D1(printk(KERN_DEBUG "Scanned flash completely\n")); - /* Now build the data map for each inode, marking obsoleted nodes - as such, and also increase nlink of any children. */ + D1(jffs2_dump_block_lists(c)); + + /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); - ret = jffs2_build_inode_pass1(c, ic); - if (ret) { - D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret)); - return ret; + + D1(BUG_ON(ic->ino > c->highest_ino)); + + if (ic->scan_dents) { + jffs2_build_inode_pass1(c, ic); + cond_resched(); } } D1(printk(KERN_DEBUG "Pass 1 complete\n")); @@ -107,164 +121,89 @@ children too, and repeat the scan. As that's going to be a fairly uncommon occurrence, it's not so evil to do it this way. Recursion bad. */ - do { - D1(printk(KERN_DEBUG "Pass 2 (re)starting\n")); - ret = 0; - for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); - if (ic->nlink) - continue; + D1(printk(KERN_DEBUG "Pass 2 starting\n")); + + for_each_inode(i, c, ic) { + D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); + if (ic->nlink) + continue; - ret = jffs2_build_remove_unlinked_inode(c, ic); - if (ret) - break; - /* -EAGAIN means the inode's nlink was zero, so we deleted it, - and furthermore that it had children and their nlink has now - gone to zero too. So we have to restart the scan. */ - } - } while(ret == -EAGAIN); - + jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); + cond_resched(); + } + + D1(printk(KERN_DEBUG "Pass 2a starting\n")); + + while (dead_fds) { + struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *fd = dead_fds; + + dead_fds = fd->next; + + ic = jffs2_get_ino_cache(c, fd->ino); + D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic)); + + if (ic) + jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); + jffs2_free_full_dirent(fd); + } + D1(printk(KERN_DEBUG "Pass 2 complete\n")); - /* Finally, we can scan again and free the dirent nodes and scan_info structs */ + /* Finally, we can scan again and free the dirent structs */ for_each_inode(i, c, ic) { - struct jffs2_scan_info *scan = ic->scan; struct jffs2_full_dirent *fd; D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); - if (!scan) { - if (ic->nlink) { - D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink)); - } - continue; - } - ic->scan = NULL; - while(scan->dents) { - fd = scan->dents; - scan->dents = fd->next; + + while(ic->scan_dents) { + fd = ic->scan_dents; + ic->scan_dents = fd->next; jffs2_free_full_dirent(fd); } - kfree(scan); + ic->scan_dents = NULL; + cond_resched(); } D1(printk(KERN_DEBUG "Pass 3 complete\n")); + D1(jffs2_dump_block_lists(c)); - return ret; -} - -int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -{ - struct jffs2_tmp_dnode_info *tn; - struct jffs2_full_dirent *fd; - struct jffs2_node_frag *fraglist = NULL; - struct jffs2_tmp_dnode_info *metadata = NULL; - - D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino)); - if (ic->ino > c->highest_ino) - c->highest_ino = ic->ino; - - if (!ic->scan->tmpnodes && ic->ino != 1) { - D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino)); - } - /* Build the list to make sure any obsolete nodes are marked as such */ - while(ic->scan->tmpnodes) { - tn = ic->scan->tmpnodes; - ic->scan->tmpnodes = tn->next; - - if (metadata && tn->version > metadata->version) { - D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n", - metadata->fn->raw->flash_offset &~3)); - - jffs2_free_full_dnode(metadata->fn); - jffs2_free_tmp_dnode_info(metadata); - metadata = NULL; - } - - if (tn->fn->size) { - jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn); - jffs2_free_tmp_dnode_info(tn); - } else { - if (!metadata) { - metadata = tn; - } else { - D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n", - tn->fn->raw->flash_offset &~3)); - - jffs2_free_full_dnode(tn->fn); - jffs2_free_tmp_dnode_info(tn); - } - } - } - - /* OK. Now clear up */ - if (metadata) { - jffs2_free_full_dnode(metadata->fn); - jffs2_free_tmp_dnode_info(metadata); - } - metadata = NULL; - - while (fraglist) { - struct jffs2_node_frag *frag; - frag = fraglist; - fraglist = fraglist->next; - - if (frag->node && !(--frag->node->frags)) { - jffs2_free_full_dnode(frag->node); - } - jffs2_free_node_frag(frag); - } - - /* Now for each child, increase nlink */ - for(fd=ic->scan->dents; fd; fd = fd->next) { - struct jffs2_inode_cache *child_ic; - if (!fd->ino) - continue; + /* Rotate the lists by some number to ensure wear levelling */ + jffs2_rotate_lists(c); - child_ic = jffs2_get_ino_cache(c, fd->ino); - if (!child_ic) { - printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", - fd->name, fd->ino, ic->ino); - continue; - } - - if (child_ic->nlink++ && fd->type == DT_DIR) { - printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino); - if (fd->ino == 1 && ic->ino == 1) { - printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); - printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); - } - /* What do we do about it? */ - } - D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); - /* Can't free them. We might need them in pass 2 */ - } - return 0; + return ret; } -int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; - int ret = 0; - - if(!ic->scan) { - D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino)); - return 0; - } D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { - D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3)); + D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw))); jffs2_mark_node_obsolete(c, raw); } - if (ic->scan->dents) { - printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); - - while(ic->scan->dents) { + if (ic->scan_dents) { + int whinged = 0; + D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino)); + + while(ic->scan_dents) { struct jffs2_inode_cache *child_ic; - fd = ic->scan->dents; - ic->scan->dents = fd->next; + fd = ic->scan_dents; + ic->scan_dents = fd->next; + + if (!fd->ino) { + /* It's a deletion dirent. Ignore it */ + D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name)); + jffs2_free_full_dirent(fd); + continue; + } + if (!whinged) { + whinged = 1; + printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); + } D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", fd->name, fd->ino)); @@ -272,16 +211,136 @@ child_ic = jffs2_get_ino_cache(c, fd->ino); if (!child_ic) { printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); + jffs2_free_full_dirent(fd); continue; } - jffs2_free_full_dirent(fd); + + /* Reduce nlink of the child. If it's now zero, stick it on the + dead_fds list to be cleaned up later. Else just free the fd */ + child_ic->nlink--; + + if (!child_ic->nlink) { + D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n", + fd->ino, fd->name)); + fd->next = *dead_fds; + *dead_fds = fd; + } else { + D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", + fd->ino, fd->name, child_ic->nlink)); + jffs2_free_full_dirent(fd); + } } - ret = -EAGAIN; } - kfree(ic->scan); - ic->scan = NULL; - // jffs2_del_ino_cache(c, ic); - // jffs2_free_inode_cache(ic); - return ret; + + /* + We don't delete the inocache from the hash list and free it yet. + The erase code will do that, when all the nodes are completely gone. + */ +} + +static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) +{ + uint32_t size; + + /* Deletion should almost _always_ be allowed. We're fairly + buggered once we stop allowing people to delete stuff + because there's not enough free space... */ + c->resv_blocks_deletion = 2; + + /* Be conservative about how much space we need before we allow writes. + On top of that which is required for deletia, require an extra 2% + of the medium to be available, for overhead caused by nodes being + split across blocks, etc. */ + + size = c->flash_size / 50; /* 2% of flash size */ + size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */ + size += c->sector_size - 1; /* ... and round up */ + + c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size); + + /* When do we let the GC thread run in the background */ + + c->resv_blocks_gctrigger = c->resv_blocks_write + 1; + + /* When do we allow garbage collection to merge nodes to make + long-term progress at the expense of short-term space exhaustion? */ + c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1; + + /* When do we allow garbage collection to eat from bad blocks rather + than actually making progress? */ + c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; + + /* If there's less than this amount of dirty space, don't bother + trying to GC to make more space. It'll be a fruitless task */ + c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); + + D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", + c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks)); + D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n", + c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024)); + D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n", + c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024)); + D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n", + c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024)); + D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n", + c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024)); + D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n", + c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024)); + D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n", + c->nospc_dirty_size)); +} + +int jffs2_do_mount_fs(struct jffs2_sb_info *c) +{ + int i; + + c->free_size = c->flash_size; + c->nr_blocks = c->flash_size / c->sector_size; + c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); + if (!c->blocks) + return -ENOMEM; + for (i=0; inr_blocks; i++) { + INIT_LIST_HEAD(&c->blocks[i].list); + c->blocks[i].offset = i * c->sector_size; + c->blocks[i].free_size = c->sector_size; + c->blocks[i].dirty_size = 0; + c->blocks[i].wasted_size = 0; + c->blocks[i].unchecked_size = 0; + c->blocks[i].used_size = 0; + c->blocks[i].first_node = NULL; + c->blocks[i].last_node = NULL; + } + + init_MUTEX(&c->alloc_sem); + init_MUTEX(&c->erase_free_sem); + init_waitqueue_head(&c->erase_wait); + init_waitqueue_head(&c->inocache_wq); + spin_lock_init(&c->erase_completion_lock); + spin_lock_init(&c->inocache_lock); + + INIT_LIST_HEAD(&c->clean_list); + INIT_LIST_HEAD(&c->very_dirty_list); + INIT_LIST_HEAD(&c->dirty_list); + INIT_LIST_HEAD(&c->erasable_list); + INIT_LIST_HEAD(&c->erasing_list); + INIT_LIST_HEAD(&c->erase_pending_list); + INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); + INIT_LIST_HEAD(&c->erase_complete_list); + INIT_LIST_HEAD(&c->free_list); + INIT_LIST_HEAD(&c->bad_list); + INIT_LIST_HEAD(&c->bad_used_list); + c->highest_ino = 1; + + if (jffs2_build_filesystem(c)) { + D1(printk(KERN_DEBUG "build_fs failed\n")); + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + kfree(c->blocks); + return -EIO; + } + + jffs2_calc_trigger_levels(c); + + return 0; } diff -Nru a/fs/jffs2/compr.c b/fs/jffs2/compr.c --- a/fs/jffs2/compr.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/compr.c Thu Dec 4 16:24:25 2003 @@ -1,59 +1,37 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * * Created by Arjan van de Ven * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: compr.c,v 1.17 2001/09/23 09:56:46 dwmw2 Exp $ + * $Id: compr.c,v 1.31 2003/11/26 13:01:12 dwmw2 Exp $ * */ #include #include -#include #include +#include +#include #include +#include "nodelist.h" -int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); -void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); -int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); -void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); -int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); -void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); -int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); -void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); +int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); +void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); +int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); +void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); +int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); +void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); +int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); +void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); /* jffs2_compress: * @data: Pointer to uncompressed data - * @cdata: Pointer to buffer for compressed data + * @cdata: Pointer to returned pointer to buffer for compressed data * @datalen: On entry, holds the amount of data available for compression. * On exit, expected to hold the amount of data actually compressed. * @cdatalen: On entry, holds the amount of space available for compressed @@ -68,47 +46,58 @@ * jffs2_compress should compress as much as will fit, and should set * *datalen accordingly to show the amount of data which were compressed. */ -unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *datalen, __u32 *cdatalen) +unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen) { +#ifdef JFFS2_COMPRESSION int ret; - ret = zlib_compress(data_in, cpage_out, datalen, cdatalen); + *cpage_out = kmalloc(*cdatalen, GFP_KERNEL); + if (!*cpage_out) { + printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n"); + return JFFS2_COMPR_NONE; + } + +#ifdef JFFS2_USE_ZLIB + ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_ZLIB; } -#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */ - ret = dynrubin_compress(data_in, cpage_out, datalen, cdatalen); +#endif +#ifdef JFFS2_USE_DYNRUBIN + ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_DYNRUBIN; } #endif -#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */ - ret = rubinmips_compress(data_in, cpage_out, datalen, cdatalen); +#ifdef JFFS2_USE_RUBINMIPS + ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_RUBINMIPS; } #endif +#ifdef JFFS2_USE_RTIME /* rtime does manage to recompress already-compressed data */ - ret = rtime_compress(data_in, cpage_out, datalen, cdatalen); + ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_RTIME; } -#if 0 - /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */ - /* If we get here, no compression is going to work */ - /* But we might want to use the fragmentation part -- Arjan */ - memcpy(cpage_out,data_in,min(*datalen,*cdatalen)); - if (*datalen > *cdatalen) - *datalen = *cdatalen; -#endif +#endif + kfree(*cpage_out); +#endif /* Compression */ + *cpage_out = data_in; + *datalen = *cdatalen; return JFFS2_COMPR_NONE; /* We failed to compress */ - } +void jffs2_free_comprbuf(unsigned char *orig, unsigned char *comprbuf) +{ + if (orig != comprbuf) + kfree(comprbuf); +} int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, - unsigned char *data_out, __u32 cdatalen, __u32 datalen) + unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) { switch (comprtype) { case JFFS2_COMPR_NONE: @@ -119,30 +108,27 @@ case JFFS2_COMPR_ZERO: memset(data_out, 0, datalen); break; - +#ifdef JFFS2_USE_ZLIB case JFFS2_COMPR_ZLIB: - zlib_decompress(cdata_in, data_out, cdatalen, datalen); + jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen); break; - +#endif +#ifdef JFFS2_USE_RTIME case JFFS2_COMPR_RTIME: - rtime_decompress(cdata_in, data_out, cdatalen, datalen); + jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen); break; - - case JFFS2_COMPR_RUBINMIPS: -#if 0 /* Disabled 23/9/1 */ - rubinmips_decompress(cdata_in, data_out, cdatalen, datalen); -#else - printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n"); #endif +#ifdef JFFS2_USE_RUBINMIPS + case JFFS2_COMPR_RUBINMIPS: + jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen); break; - case JFFS2_COMPR_DYNRUBIN: -#if 1 /* Phase this one out */ - dynrubin_decompress(cdata_in, data_out, cdatalen, datalen); -#else - printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n"); #endif - break; +#ifdef JFFS2_USE_DYNRUBIN + case JFFS2_COMPR_DYNRUBIN: + jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen); + break; +#endif default: printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype); return -EIO; diff -Nru a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c --- a/fs/jffs2/compr_rtime.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/compr_rtime.c Thu Dec 4 16:24:25 2003 @@ -1,43 +1,19 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * * Created by Arjan van de Ven * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: compr_rtime.c,v 1.5 2001/03/15 15:38:23 dwmw2 Exp $ + * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $ * * * Very simple lz77-ish encoder. * * Theory of operation: Both encoder and decoder have a list of "last - * occurances" for every possible source-value; after sending the + * occurrences" for every possible source-value; after sending the * first source-byte, the second byte indicated the "run" length of * matches * @@ -51,10 +27,10 @@ #include /* _compress returns the compressed size, -1 if bigger */ -int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *sourcelen, __u32 *dstlen) +int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; @@ -91,10 +67,10 @@ } -void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, - __u32 srclen, __u32 destlen) +void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; diff -Nru a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c --- a/fs/jffs2/compr_rubin.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/compr_rubin.c Thu Dec 4 16:24:25 2003 @@ -1,37 +1,13 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001, 2002 Red Hat, Inc. * * Created by Arjan van de Ven * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: compr_rubin.c,v 1.13 2001/09/23 10:06:05 rmk Exp $ + * $Id: compr_rubin.c,v 1.17 2002/05/20 14:56:37 dwmw2 Exp $ * */ @@ -43,7 +19,7 @@ -void init_rubin(struct rubin_state *rs, int div, int *bits) +static void init_rubin(struct rubin_state *rs, int div, int *bits) { int c; @@ -56,7 +32,7 @@ } -int encode(struct rubin_state *rs, long A, long B, int symbol) +static int encode(struct rubin_state *rs, long A, long B, int symbol) { long i0, i1; @@ -91,7 +67,7 @@ } -void end_rubin(struct rubin_state *rs) +static void end_rubin(struct rubin_state *rs) { int i; @@ -104,7 +80,7 @@ } -void init_decode(struct rubin_state *rs, int div, int *bits) +static void init_decode(struct rubin_state *rs, int div, int *bits) { init_rubin(rs, div, bits); @@ -151,7 +127,7 @@ rs->rec_q = rec_q; } -int decode(struct rubin_state *rs, long A, long B) +static int decode(struct rubin_state *rs, long A, long B) { unsigned long p = rs->p, q = rs->q; long i0, threshold; @@ -212,8 +188,8 @@ -int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, - unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) +static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, + unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { int outpos = 0; int pos=0; @@ -246,20 +222,20 @@ } #if 0 /* _compress returns the compressed size, -1 if bigger */ -int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *sourcelen, __u32 *dstlen) +int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) { return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); } #endif -int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *sourcelen, __u32 *dstlen) +int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) { int bits[8]; unsigned char histo[256]; int i; int ret; - __u32 mysrclen, mydstlen; + uint32_t mysrclen, mydstlen; mysrclen = *sourcelen; mydstlen = *dstlen - 8; @@ -315,8 +291,8 @@ return 0; } -void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, - unsigned char *page_out, __u32 srclen, __u32 destlen) +static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, + unsigned char *page_out, uint32_t srclen, uint32_t destlen) { int outpos = 0; struct rubin_state rs; @@ -330,14 +306,14 @@ } -void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, - __u32 sourcelen, __u32 dstlen) +void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t sourcelen, uint32_t dstlen) { rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); } -void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, - __u32 sourcelen, __u32 dstlen) +void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t sourcelen, uint32_t dstlen) { int bits[8]; int c; diff -Nru a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h --- a/fs/jffs2/compr_rubin.h Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/compr_rubin.h Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* Rubin encoder/decoder header */ /* work started at : aug 3, 1994 */ /* last modification : aug 15, 1994 */ -/* $Id: compr_rubin.h,v 1.5 2001/02/26 13:50:01 dwmw2 Exp $ */ +/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */ #include "pushpull.h" @@ -19,10 +19,3 @@ int bit_divider; int bits[8]; }; - - -void init_rubin (struct rubin_state *rs, int div, int *bits); -int encode (struct rubin_state *, long, long, int); -void end_rubin (struct rubin_state *); -void init_decode (struct rubin_state *, int div, int *bits); -int decode (struct rubin_state *, long, long); diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c --- a/fs/jffs2/compr_zlib.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/compr_zlib.c Thu Dec 4 16:24:25 2003 @@ -1,50 +1,28 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001, 2002 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: compr_zlib.c,v 1.8.2.1 2002/10/11 09:04:44 dwmw2 Exp $ + * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $ * */ -#ifndef __KERNEL__ +#if !defined(__KERNEL__) && !defined(__ECOS) #error "The userspace support got too messy and was removed. Update your mkfs.jffs2" #endif #include #include -#include /* for min() */ +#include +#include #include -#include #include +#include +#include #include "nodelist.h" /* Plan: call deflate() with avail_in == *sourcelen, @@ -58,21 +36,21 @@ static DECLARE_MUTEX(deflate_sem); static DECLARE_MUTEX(inflate_sem); -static void *deflate_workspace; -static void *inflate_workspace; +static z_stream inf_strm, def_strm; +#ifdef __KERNEL__ /* Linux-only */ int __init jffs2_zlib_init(void) { - deflate_workspace = vmalloc(zlib_deflate_workspacesize()); - if (!deflate_workspace) { + def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); + if (!def_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); - inflate_workspace = vmalloc(zlib_inflate_workspacesize()); - if (!inflate_workspace) { + inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); + if (!inf_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize()); - vfree(deflate_workspace); + vfree(def_strm.workspace); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize())); @@ -81,97 +59,120 @@ void jffs2_zlib_exit(void) { - vfree(deflate_workspace); - vfree(inflate_workspace); + vfree(def_strm.workspace); + vfree(inf_strm.workspace); } +#endif /* __KERNEL__ */ -int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *sourcelen, __u32 *dstlen) +int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) { - z_stream strm; int ret; if (*dstlen <= STREAM_END_SPACE) return -1; down(&deflate_sem); - strm.workspace = deflate_workspace; - if (Z_OK != zlib_deflateInit(&strm, 3)) { + if (Z_OK != zlib_deflateInit(&def_strm, 3)) { printk(KERN_WARNING "deflateInit failed\n"); up(&deflate_sem); return -1; } - strm.next_in = data_in; - strm.total_in = 0; + def_strm.next_in = data_in; + def_strm.total_in = 0; - strm.next_out = cpage_out; - strm.total_out = 0; + def_strm.next_out = cpage_out; + def_strm.total_out = 0; - while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { - strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); - strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); + while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) { + def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE); + def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out); D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", - strm.avail_in, strm.avail_out)); - ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH); + def_strm.avail_in, def_strm.avail_out)); + ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", - strm.avail_in, strm.avail_out, strm.total_in, strm.total_out)); + def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); if (ret != Z_OK) { D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); - zlib_deflateEnd(&strm); + zlib_deflateEnd(&def_strm); up(&deflate_sem); return -1; } } - strm.avail_out += STREAM_END_SPACE; - strm.avail_in = 0; - ret = zlib_deflate(&strm, Z_FINISH); - zlib_deflateEnd(&strm); - up(&deflate_sem); + def_strm.avail_out += STREAM_END_SPACE; + def_strm.avail_in = 0; + ret = zlib_deflate(&def_strm, Z_FINISH); + zlib_deflateEnd(&def_strm); + if (ret != Z_STREAM_END) { D1(printk(KERN_DEBUG "final deflate returned %d\n", ret)); - return -1; + ret = -1; + goto out; } - D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", - strm.total_in, strm.total_out)); + if (def_strm.total_out >= def_strm.total_in) { + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n", + def_strm.total_in, def_strm.total_out)); + ret = -1; + goto out; + } - if (strm.total_out >= strm.total_in) - return -1; + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", + def_strm.total_in, def_strm.total_out)); - *dstlen = strm.total_out; - *sourcelen = strm.total_in; - return 0; + *dstlen = def_strm.total_out; + *sourcelen = def_strm.total_in; + ret = 0; + out: + up(&deflate_sem); + return ret; } -void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, - __u32 srclen, __u32 destlen) +void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen) { - z_stream strm; int ret; + int wbits = MAX_WBITS; down(&inflate_sem); - strm.workspace = inflate_workspace; - if (Z_OK != zlib_inflateInit(&strm)) { + inf_strm.next_in = data_in; + inf_strm.avail_in = srclen; + inf_strm.total_in = 0; + + inf_strm.next_out = cpage_out; + inf_strm.avail_out = destlen; + inf_strm.total_out = 0; + + /* If it's deflate, and it's got no preset dictionary, then + we can tell zlib to skip the adler32 check. */ + if (srclen > 2 && !(data_in[1] & PRESET_DICT) && + ((data_in[0] & 0x0f) == Z_DEFLATED) && + !(((data_in[0]<<8) + data_in[1]) % 31)) { + + D2(printk(KERN_DEBUG "inflate skipping adler32\n")); + wbits = -((data_in[0] >> 4) + 8); + inf_strm.next_in += 2; + inf_strm.avail_in -= 2; + } else { + /* Let this remain D1 for now -- it should never happen */ + D1(printk(KERN_DEBUG "inflate not skipping adler32\n")); + } + + + if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { printk(KERN_WARNING "inflateInit failed\n"); up(&inflate_sem); return; } - strm.next_in = data_in; - strm.avail_in = srclen; - strm.total_in = 0; - - strm.next_out = cpage_out; - strm.avail_out = destlen; - strm.total_out = 0; - while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK) + while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) ; if (ret != Z_STREAM_END) { printk(KERN_NOTICE "inflate returned %d\n", ret); } - zlib_inflateEnd(&strm); + zlib_inflateEnd(&inf_strm); up(&inflate_sem); } diff -Nru a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c --- a/fs/jffs2/comprtest.c Thu Dec 4 16:24:26 2003 +++ b/fs/jffs2/comprtest.c Thu Dec 4 16:24:26 2003 @@ -1,4 +1,4 @@ -/* $Id: comprtest.c,v 1.4 2001/02/21 14:03:20 dwmw2 Exp $ */ +/* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */ #include #include @@ -266,13 +266,13 @@ static unsigned char decomprbuf[TESTDATA_LEN]; int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, - unsigned char *data_out, __u32 cdatalen, __u32 datalen); + unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *datalen, __u32 *cdatalen); + uint32_t *datalen, uint32_t *cdatalen); int init_module(void ) { unsigned char comprtype; - __u32 c, d; + uint32_t c, d; int ret; printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", diff -Nru a/fs/jffs2/crc32.c b/fs/jffs2/crc32.c --- a/fs/jffs2/crc32.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/crc32.c Thu Dec 4 16:24:25 2003 @@ -37,11 +37,11 @@ * polynomial $edb88320 */ -/* $Id: crc32.c,v 1.3 2001/02/07 16:45:32 dwmw2 Exp $ */ +/* $Id: crc32.c,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */ #include "crc32.h" -const __u32 crc32_table[256] = { +const uint32_t crc32_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, diff -Nru a/fs/jffs2/crc32.h b/fs/jffs2/crc32.h --- a/fs/jffs2/crc32.h Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/crc32.h Thu Dec 4 16:24:25 2003 @@ -1,16 +1,16 @@ #ifndef CRC32_H #define CRC32_H -/* $Id: crc32.h,v 1.3 2001/02/26 14:44:37 dwmw2 Exp $ */ +/* $Id: crc32.h,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */ #include -extern const __u32 crc32_table[256]; +extern const uint32_t crc32_table[256]; /* Return a 32-bit CRC of the contents of the buffer. */ -static inline __u32 -crc32(__u32 val, const void *ss, int len) +static inline uint32_t +crc32(uint32_t val, const void *ss, int len) { const unsigned char *s = ss; while (--len >= 0) diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c --- a/fs/jffs2/dir.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/dir.c Thu Dec 4 16:24:25 2003 @@ -1,84 +1,73 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: dir.c,v 1.45.2.7 2002/08/26 15:30:18 dwmw2 Exp $ + * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $ * */ #include #include +#include #include -#include /* For completion */ +#include #include #include #include +#include #include "nodelist.h" -#include "crc32.h" + +/* Urgh. Please tell me there's a nicer way of doing these. */ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) +typedef int mknod_arg_t; +#define NAMEI_COMPAT(x) ((void *)x) +#else +typedef dev_t mknod_arg_t; +#define NAMEI_COMPAT(x) (x) +#endif static int jffs2_readdir (struct file *, void *, filldir_t); -static int jffs2_create (struct inode *,struct dentry *,int); -static struct dentry *jffs2_lookup (struct inode *,struct dentry *); +static int jffs2_create (struct inode *,struct dentry *,int, + struct nameidata *); +static struct dentry *jffs2_lookup (struct inode *,struct dentry *, + struct nameidata *); static int jffs2_link (struct dentry *,struct inode *,struct dentry *); static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct inode *,struct dentry *,const char *); static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,int,int); +static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); static int jffs2_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); struct file_operations jffs2_dir_operations = { - read: generic_read_dir, - readdir: jffs2_readdir, - ioctl: jffs2_ioctl, - fsync: jffs2_null_fsync + .read = generic_read_dir, + .readdir = jffs2_readdir, + .ioctl = jffs2_ioctl, + .fsync = jffs2_fsync }; struct inode_operations jffs2_dir_inode_operations = { - create: jffs2_create, - lookup: jffs2_lookup, - link: jffs2_link, - unlink: jffs2_unlink, - symlink: jffs2_symlink, - mkdir: jffs2_mkdir, - rmdir: jffs2_rmdir, - mknod: jffs2_mknod, - rename: jffs2_rename, - setattr: jffs2_setattr, + .create = NAMEI_COMPAT(jffs2_create), + .lookup = NAMEI_COMPAT(jffs2_lookup), + .link = jffs2_link, + .unlink = jffs2_unlink, + .symlink = jffs2_symlink, + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, + .rename = jffs2_rename, + .setattr = jffs2_setattr, }; /***********************************************************************/ @@ -88,12 +77,13 @@ and we use the same hash function as the dentries. Makes this nice and simple */ -static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target) +static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, + struct nameidata *nd) { struct jffs2_inode_info *dir_f; struct jffs2_sb_info *c; struct jffs2_full_dirent *fd = NULL, *fd_list; - __u32 ino = 0; + uint32_t ino = 0; struct inode *inode = NULL; D1(printk(KERN_DEBUG "jffs2_lookup()\n")); @@ -153,8 +143,9 @@ offset++; } if (offset == 1) { - D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", filp->f_dentry->d_parent->d_inode->i_ino)); - if (filldir(dirent, "..", 2, 1, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + unsigned long pino = parent_ino(filp->f_dentry); + D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino)); + if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0) goto out; offset++; } @@ -188,18 +179,14 @@ /***********************************************************************/ -static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) + +static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, + struct nameidata *nd) { + struct jffs2_raw_inode *ri; struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; - struct jffs2_raw_inode *ri; - struct jffs2_raw_dirent *rd; - struct jffs2_full_dnode *fn; - struct jffs2_full_dirent *fd; - int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; int ret; ri = jffs2_alloc_raw_inode(); @@ -210,23 +197,11 @@ D1(printk(KERN_DEBUG "jffs2_create()\n")); - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though - */ - namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); - D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen)); - if (ret) { - jffs2_free_raw_inode(ri); - return ret; - } - inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); jffs2_free_raw_inode(ri); - jffs2_complete_reservation(c); return PTR_ERR(inode); } @@ -236,93 +211,22 @@ inode->i_mapping->nrpages = 0; f = JFFS2_INODE_INFO(inode); - - ri->data_crc = 0; - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - - fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); - D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode)); - jffs2_free_raw_inode(ri); - - if (IS_ERR(fn)) { - D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); - /* Eeek. Wave bye bye */ - up(&f->sem); - jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return PTR_ERR(fn); - } - /* No data here. Only a metadata node, which will be - obsoleted by the first data write - */ - f->metadata = fn; - - /* Work out where to put the dirent node now. */ - writtenlen = PAD(writtenlen); - phys_ofs += writtenlen; - alloclen -= writtenlen; - up(&f->sem); - - if (alloclen < sizeof(*rd)+namelen) { - /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - - if (ret) { - /* Eep. */ - D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); - jffs2_clear_inode(inode); - return ret; - } - } - - rd = jffs2_alloc_raw_dirent(); - if (!rd) { - /* Argh. Now we treat it like a normal delete */ - jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return -ENOMEM; - } - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + namelen; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = inode->i_ino; - rd->mctime = CURRENT_TIME; - rd->nsize = namelen; - rd->type = DT_REG; - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, namelen); - - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); + ret = jffs2_do_create(c, dir_f, f, ri, + dentry->d_name.name, dentry->d_name.len); - jffs2_complete_reservation(c); - - if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally - as if it were the final unlink() */ - jffs2_free_raw_dirent(rd); - up(&dir_f->sem); + if (ret) { jffs2_clear_inode(inode); - return PTR_ERR(fd); + make_bad_inode(inode); + iput(inode); + jffs2_free_raw_inode(ri); + return ret; } - dir_i->i_mtime = dir_i->i_ctime = rd->mctime; - - jffs2_free_raw_dirent(rd); - - /* Link the fd into the inode's list, obsoleting an old - one if necessary. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); - up(&dir_f->sem); + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); + jffs2_free_raw_inode(ri); d_instantiate(dentry, inode); D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", @@ -332,173 +236,48 @@ /***********************************************************************/ -static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename) -{ - struct jffs2_inode_info *dir_f, *f; - struct jffs2_sb_info *c; - struct jffs2_raw_dirent *rd; - struct jffs2_full_dirent *fd; - __u32 alloclen, phys_ofs; - int ret; - - c = JFFS2_SB_INFO(dir_i->i_sb); - - rd = jffs2_alloc_raw_dirent(); - if (!rd) - return -ENOMEM; - - ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION); - if (ret) { - jffs2_free_raw_dirent(rd); - return ret; - } - - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - - /* Build a deletion node */ - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + dentry->d_name.len; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = 0; - rd->mctime = CURRENT_TIME; - rd->nsize = dentry->d_name.len; - rd->type = DT_UNKNOWN; - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); - - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); - - jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - - if (IS_ERR(fd)) { - up(&dir_f->sem); - return PTR_ERR(fd); - } - - /* File it. This will mark the old one obsolete. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); - up(&dir_f->sem); - - if (!rename) { - f = JFFS2_INODE_INFO(dentry->d_inode); - down(&f->sem); - - while (f->dents) { - /* There can be only deleted ones */ - fd = f->dents; - - f->dents = fd->next; - - if (fd->ino) { - printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", - f->inocache->ino, fd->name, fd->ino); - } else { - D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino)); - } - jffs2_mark_node_obsolete(c, fd->raw); - jffs2_free_full_dirent(fd); - } - /* Don't oops on unlinking a bad inode */ - if (f->inocache) - f->inocache->nlink--; - dentry->d_inode->i_nlink--; - up(&f->sem); - } - - return 0; -} static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) { - return jffs2_do_unlink(dir_i, dentry, 0); -} -/***********************************************************************/ - -static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename) -{ - struct jffs2_inode_info *dir_f, *f; - struct jffs2_sb_info *c; - struct jffs2_raw_dirent *rd; - struct jffs2_full_dirent *fd; - __u32 alloclen, phys_ofs; + struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); int ret; - c = JFFS2_SB_INFO(dir_i->i_sb); - - rd = jffs2_alloc_raw_dirent(); - if (!rd) - return -ENOMEM; - - ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - jffs2_free_raw_dirent(rd); - return ret; - } - - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - - /* Build a deletion node */ - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + dentry->d_name.len; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = old_dentry->d_inode->i_ino; - rd->mctime = CURRENT_TIME; - rd->nsize = dentry->d_name.len; - - /* XXX: This is ugly. */ - rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; - if (!rd->type) rd->type = DT_REG; - - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); - - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); - - jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - - if (IS_ERR(fd)) { - up(&dir_f->sem); - return PTR_ERR(fd); - } - - /* File it. This will mark the old one obsolete. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); - up(&dir_f->sem); - - if (!rename) { - f = JFFS2_INODE_INFO(old_dentry->d_inode); - down(&f->sem); - old_dentry->d_inode->i_nlink = ++f->inocache->nlink; - up(&f->sem); - } - return 0; + ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, + dentry->d_name.len, dead_f); + if (dead_f->inocache) + dentry->d_inode->i_nlink = dead_f->inocache->nlink; + return ret; } +/***********************************************************************/ + static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; + uint8_t type; - /* Can't link a bad inode. */ - if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache) + /* Don't let people make hard links to bad inodes. */ + if (!f->inocache) return -EIO; if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; - ret = jffs2_do_link(old_dentry, dir_i, dentry, 0); + /* XXX: This is ugly */ + type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); + if (!ret) { + down(&f->sem); + old_dentry->d_inode->i_nlink = ++f->inocache->nlink; + up(&f->sem); d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); } @@ -517,8 +296,7 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; int ret; /* FIXME: If you care. We'd need to use frags for the target @@ -556,15 +334,16 @@ f = JFFS2_INODE_INFO(inode); - inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); - ri->totlen = sizeof(*ri) + ri->dsize; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); + inode->i_size = strlen(target); + ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); + ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; - ri->data_crc = crc32(0, target, strlen(target)); - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); + ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -581,20 +360,12 @@ f->metadata = fn; up(&f->sem); - /* Work out where to put the dirent node now. */ - writtenlen = (writtenlen+3)&~3; - phys_ofs += writtenlen; - alloclen -= writtenlen; - - if (alloclen < sizeof(*rd)+namelen) { - /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + jffs2_complete_reservation(c); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + /* Eep. */ + jffs2_clear_inode(inode); + return ret; } rd = jffs2_alloc_raw_dirent(); @@ -608,41 +379,42 @@ dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + namelen; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = inode->i_ino; - rd->mctime = CURRENT_TIME; + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); + rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; rd->type = DT_LNK; - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, namelen); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); + + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); - - jffs2_complete_reservation(c); - if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ + jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } - dir_i->i_mtime = dir_i->i_ctime = rd->mctime; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); + up(&dir_f->sem); + jffs2_complete_reservation(c); d_instantiate(dentry, inode); return 0; @@ -659,8 +431,7 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; int ret; mode |= S_IFDIR; @@ -692,13 +463,15 @@ inode->i_op = &jffs2_dir_inode_operations; inode->i_fop = &jffs2_dir_operations; + /* Directories get nlink 2 at start */ + inode->i_nlink = 2; f = JFFS2_INODE_INFO(inode); - ri->data_crc = 0; - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); + ri->data_crc = cpu_to_je32(0); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -715,20 +488,12 @@ f->metadata = fn; up(&f->sem); - /* Work out where to put the dirent node now. */ - writtenlen = PAD(writtenlen); - phys_ofs += writtenlen; - alloclen -= writtenlen; - - if (alloclen < sizeof(*rd)+namelen) { - /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + jffs2_complete_reservation(c); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + /* Eep. */ + jffs2_clear_inode(inode); + return ret; } rd = jffs2_alloc_raw_dirent(); @@ -742,41 +507,43 @@ dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + namelen; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = inode->i_ino; - rd->mctime = CURRENT_TIME; + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); + rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; rd->type = DT_DIR; - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, namelen); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); - - jffs2_complete_reservation(c); + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ + jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } - dir_i->i_mtime = dir_i->i_ctime = rd->mctime; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); + dir_i->i_nlink++; jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); + up(&dir_f->sem); + jffs2_complete_reservation(c); d_instantiate(dentry, inode); return 0; @@ -786,15 +553,19 @@ { struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); struct jffs2_full_dirent *fd; + int ret; for (fd = f->dents ; fd; fd = fd->next) { if (fd->ino) return -ENOTEMPTY; } - return jffs2_unlink(dir_i, dentry); + ret = jffs2_unlink(dir_i, dentry); + if (!ret) + dir_i->i_nlink--; + return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev) +static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -804,12 +575,14 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - unsigned short dev; + jint16_t dev; int devlen = 0; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; int ret; + if (!old_valid_dev(rdev)) + return -EINVAL; + ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; @@ -817,7 +590,7 @@ c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { - dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev)); + dev = cpu_to_je16(old_encode_dev(rdev)); devlen = sizeof(dev); } @@ -844,15 +617,15 @@ f = JFFS2_INODE_INFO(inode); - ri->dsize = ri->csize = devlen; - ri->totlen = sizeof(*ri) + ri->csize; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); + ri->dsize = ri->csize = cpu_to_je32(devlen); + ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; - ri->data_crc = crc32(0, &dev, devlen); - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); + ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -869,20 +642,12 @@ f->metadata = fn; up(&f->sem); - /* Work out where to put the dirent node now. */ - writtenlen = (writtenlen+3)&~3; - phys_ofs += writtenlen; - alloclen -= writtenlen; - - if (alloclen < sizeof(*rd)+namelen) { - /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + jffs2_complete_reservation(c); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + /* Eep. */ + jffs2_clear_inode(inode); + return ret; } rd = jffs2_alloc_raw_dirent(); @@ -896,44 +661,45 @@ dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); - rd->magic = JFFS2_MAGIC_BITMASK; - rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + namelen; - rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - - rd->pino = dir_i->i_ino; - rd->version = ++dir_f->highest_version; - rd->ino = inode->i_ino; - rd->mctime = CURRENT_TIME; + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); + rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; /* XXX: This is ugly. */ rd->type = (mode & S_IFMT) >> 12; - rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, namelen); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); - - jffs2_complete_reservation(c); + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ + jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } - dir_i->i_mtime = dir_i->i_ctime = rd->mctime; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); + up(&dir_f->sem); + jffs2_complete_reservation(c); d_instantiate(dentry, inode); @@ -944,7 +710,9 @@ struct inode *new_dir_i, struct dentry *new_dentry) { int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; + uint8_t type; /* 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, @@ -973,7 +741,15 @@ */ /* Make a hard link */ - ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1); + + /* XXX: This is ugly */ + type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), + old_dentry->d_inode->i_ino, type, + new_dentry->d_name.name, new_dentry->d_name.len); + if (ret) return ret; @@ -989,22 +765,36 @@ } } + /* If it was a directory we moved, and there was no victim, + increase i_nlink on its new parent */ + if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) + new_dir_i->i_nlink++; + /* Unlink the original */ - ret = jffs2_do_unlink(old_dir_i, old_dentry, 1); - + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + old_dentry->d_name.name, old_dentry->d_name.len, NULL); + + /* We don't touch inode->i_nlink */ + if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); down(&f->sem); + old_dentry->d_inode->i_nlink++; if (f->inocache) - old_dentry->d_inode->i_nlink = f->inocache->nlink++; + f->inocache->nlink++; up(&f->sem); - + printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); /* Might as well let the VFS know */ d_instantiate(new_dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); + return ret; } - return ret; + + if (S_ISDIR(old_dentry->d_inode->i_mode)) + old_dir_i->i_nlink--; + + return 0; } diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c --- a/fs/jffs2/erase.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/erase.c Thu Dec 4 16:24:25 2003 @@ -1,68 +1,60 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: erase.c,v 1.24 2001/12/06 16:38:38 dwmw2 Exp $ + * $Id: erase.c,v 1.58 2003/11/26 13:02:46 dwmw2 Exp $ * */ + #include #include #include -#include -#include +#include +#include +#include +#include #include "nodelist.h" -#include "crc32.h" struct erase_priv_struct { struct jffs2_eraseblock *jeb; struct jffs2_sb_info *c; }; +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *); +#endif +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct erase_info *instr; int ret; +#ifdef __ECOS + ret = jffs2_flash_erase(c, jeb); + if (!ret) { + jffs2_erase_succeeded(c, jeb); + return; + } +#else /* Linux */ + struct erase_info *instr; instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -77,19 +69,27 @@ ((struct erase_priv_struct *)instr->priv)->jeb = jeb; ((struct erase_priv_struct *)instr->priv)->c = c; + /* NAND , read out the fail counter, if possible */ + if (!jffs2_can_mark_obsolete(c)) + jffs2_nand_read_failcnt(c,jeb); + ret = c->mtd->erase(c->mtd, instr); - if (!ret) { + if (!ret) return; - } + + kfree(instr); +#endif /* __ECOS */ + if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); - kfree(instr); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -97,74 +97,101 @@ printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); else printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); - spin_lock_bh(&c->erase_completion_lock); - list_del(&jeb->list); - list_add(&jeb->list, &c->bad_list); - c->nr_erasing_blocks--; - c->bad_size += c->sector_size; - c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); - wake_up(&c->erase_wait); - kfree(instr); + + jffs2_erase_failed(c, jeb); } -void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) +void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) { struct jffs2_eraseblock *jeb; - spin_lock_bh(&c->erase_completion_lock); - while (!list_empty(&c->erase_pending_list)) { + down(&c->erase_free_sem); - jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list); + spin_lock(&c->erase_completion_lock); - D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); + while (!list_empty(&c->erase_complete_list) || + !list_empty(&c->erase_pending_list)) { + + if (!list_empty(&c->erase_complete_list)) { + jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); + list_del(&jeb->list); + spin_unlock(&c->erase_completion_lock); + jffs2_mark_erased_block(c, jeb); + + if (!--count) { + D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n")); + goto done; + } + + } else if (!list_empty(&c->erase_pending_list)) { + jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list); + D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); + list_del(&jeb->list); + c->erasing_size += c->sector_size; + c->wasted_size -= jeb->wasted_size; + c->free_size -= jeb->free_size; + c->used_size -= jeb->used_size; + c->dirty_size -= jeb->dirty_size; + jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0; + jffs2_free_all_node_refs(c, jeb); + list_add(&jeb->list, &c->erasing_list); + spin_unlock(&c->erase_completion_lock); + + jffs2_erase_block(c, jeb); + + } else { + BUG(); + } - list_del(&jeb->list); - c->erasing_size += c->sector_size; - c->free_size -= jeb->free_size; - c->used_size -= jeb->used_size; - c->dirty_size -= jeb->dirty_size; - jeb->used_size = jeb->dirty_size = jeb->free_size = 0; - jffs2_free_all_node_refs(c, jeb); - list_add(&jeb->list, &c->erasing_list); - spin_unlock_bh(&c->erase_completion_lock); - - jffs2_erase_block(c, jeb); /* Be nice */ - if (current->need_resched) - schedule(); - spin_lock_bh(&c->erase_completion_lock); + cond_resched(); + spin_lock(&c->erase_completion_lock); } - spin_unlock_bh(&c->erase_completion_lock); + + spin_unlock(&c->erase_completion_lock); + done: D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); + + up(&c->erase_free_sem); +} + +static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +{ + D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); + spin_lock(&c->erase_completion_lock); + list_del(&jeb->list); + list_add_tail(&jeb->list, &c->erase_complete_list); + spin_unlock(&c->erase_completion_lock); + /* Ensure that kupdated calls us again to mark them clean */ + jffs2_erase_pending_trigger(c); } +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +{ + spin_lock(&c->erase_completion_lock); + c->erasing_size -= c->sector_size; + c->bad_size += c->sector_size; + list_del(&jeb->list); + list_add(&jeb->list, &c->bad_list); + c->nr_erasing_blocks--; + spin_unlock(&c->erase_completion_lock); + wake_up(&c->erase_wait); +} +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *instr) { struct erase_priv_struct *priv = (void *)instr->priv; if(instr->state != MTD_ERASE_DONE) { printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state); - spin_lock(&priv->c->erase_completion_lock); - priv->c->erasing_size -= priv->c->sector_size; - priv->c->bad_size += priv->c->sector_size; - list_del(&priv->jeb->list); - list_add(&priv->jeb->list, &priv->c->bad_list); - priv->c->nr_erasing_blocks--; - spin_unlock(&priv->c->erase_completion_lock); - wake_up(&priv->c->erase_wait); + jffs2_erase_failed(priv->c, priv->jeb); } else { - D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", instr->addr)); - spin_lock(&priv->c->erase_completion_lock); - list_del(&priv->jeb->list); - list_add_tail(&priv->jeb->list, &priv->c->erase_complete_list); - spin_unlock(&priv->c->erase_completion_lock); + jffs2_erase_succeeded(priv->c, priv->jeb); } - /* Make sure someone picks up the block off the erase_complete list */ - OFNI_BS_2SFFJ(priv->c)->s_dirt = 1; kfree(instr); } +#endif /* !__ECOS */ /* Hmmm. Maybe we should accept the extra space it takes and make this a standard doubly-linked list? */ @@ -221,7 +248,7 @@ this = ic->nodes; while(this) { - printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3); + printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); if (++i == 5) { printk("\n" KERN_DEBUG); i=0; @@ -256,118 +283,134 @@ jeb->last_node = NULL; } -void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) +static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - OFNI_BS_2SFFJ(c)->s_dirt = 1; -} - -void jffs2_mark_erased_blocks(struct jffs2_sb_info *c) -{ - static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)}; - struct jffs2_eraseblock *jeb; - struct jffs2_raw_node_ref *marker_ref; + struct jffs2_raw_node_ref *marker_ref = NULL; unsigned char *ebuf; - ssize_t retlen; + size_t retlen; int ret; - marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4); - - spin_lock_bh(&c->erase_completion_lock); - while (!list_empty(&c->erase_complete_list)) { - jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); - list_del(&jeb->list); - spin_unlock_bh(&c->erase_completion_lock); - + if (!jffs2_cleanmarker_oob(c)) { marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); - /* Come back later */ + /* Stick it back on the list from whence it came and come back later */ jffs2_erase_pending_trigger(c); + spin_lock(&c->erase_completion_lock); + list_add(&jeb->list, &c->erase_complete_list); + spin_unlock(&c->erase_completion_lock); return; } + } + ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!ebuf) { + printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset); + } else { + uint32_t ofs = jeb->offset; - ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!ebuf) { - printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset); - } else { - __u32 ofs = jeb->offset; - - D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset)); - while(ofs < jeb->offset + c->sector_size) { - __u32 readlen = min((__u32)PAGE_SIZE, jeb->offset + c->sector_size - ofs); - int i; - - ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); - if (ret < 0) { - printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); - goto bad; - } - if (retlen != readlen) { - printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen); - goto bad; - } - for (i=0; ioffset)); + while(ofs < jeb->offset + c->sector_size) { + uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs); + int i; + + ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); + if (ret) { + printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); + goto bad; + } + if (retlen != readlen) { + printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); + goto bad; + } + for (i=0; ierase_completion_lock); - c->erasing_size -= c->sector_size; - c->bad_size += c->sector_size; - - list_add_tail(&jeb->list, &c->bad_list); - c->nr_erasing_blocks--; - spin_unlock_bh(&c->erase_completion_lock); - wake_up(&c->erase_wait); - return; - } + else + jffs2_write_nand_badblock( c ,jeb ); + kfree(ebuf); + bad2: + spin_lock(&c->erase_completion_lock); + c->erasing_size -= c->sector_size; + c->bad_size += c->sector_size; + + list_add_tail(&jeb->list, &c->bad_list); + c->nr_erasing_blocks--; + spin_unlock(&c->erase_completion_lock); + wake_up(&c->erase_wait); + return; } - ofs += readlen; } - kfree(ebuf); + ofs += readlen; + cond_resched(); } + kfree(ebuf); + } - /* Write the erase complete marker */ - D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); - ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker); + /* Write the erase complete marker */ + D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); + if (jffs2_cleanmarker_oob(c)) { + + if (jffs2_write_nand_cleanmarker(c, jeb)) + goto bad2; + + jeb->first_node = jeb->last_node = NULL; + + jeb->free_size = c->sector_size; + jeb->used_size = 0; + jeb->dirty_size = 0; + jeb->wasted_size = 0; + } else { + struct jffs2_unknown_node marker = { + .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), + .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), + .totlen = cpu_to_je32(c->cleanmarker_size) + }; + + marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); + + /* We only write the header; the rest was noise or padding anyway */ + ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker); if (ret) { printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", jeb->offset, ret); goto bad2; } if (retlen != sizeof(marker)) { - printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n", + printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n", jeb->offset, sizeof(marker), retlen); goto bad2; } marker_ref->next_in_ino = NULL; marker_ref->next_phys = NULL; - marker_ref->flash_offset = jeb->offset; - marker_ref->totlen = PAD(sizeof(marker)); - + marker_ref->flash_offset = jeb->offset | REF_NORMAL; + marker_ref->__totlen = c->cleanmarker_size; + jeb->first_node = jeb->last_node = marker_ref; - - jeb->free_size = c->sector_size - marker_ref->totlen; - jeb->used_size = marker_ref->totlen; + + jeb->free_size = c->sector_size - c->cleanmarker_size; + jeb->used_size = c->cleanmarker_size; jeb->dirty_size = 0; + jeb->wasted_size = 0; + } - spin_lock_bh(&c->erase_completion_lock); - c->erasing_size -= c->sector_size; - c->free_size += jeb->free_size; - c->used_size += jeb->used_size; + spin_lock(&c->erase_completion_lock); + c->erasing_size -= c->sector_size; + c->free_size += jeb->free_size; + c->used_size += jeb->used_size; - ACCT_SANITY_CHECK(c,jeb); - ACCT_PARANOIA_CHECK(jeb); + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); - list_add_tail(&jeb->list, &c->free_list); - c->nr_erasing_blocks--; - c->nr_free_blocks++; - wake_up(&c->erase_wait); - } - spin_unlock_bh(&c->erase_completion_lock); + list_add_tail(&jeb->list, &c->free_list); + c->nr_erasing_blocks--; + c->nr_free_blocks++; + spin_unlock(&c->erase_completion_lock); + wake_up(&c->erase_wait); } + diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c --- a/fs/jffs2/file.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/file.c Thu Dec 4 16:24:25 2003 @@ -1,319 +1,106 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: file.c,v 1.58.2.6 2002/11/12 13:17:01 dwmw2 Exp $ + * $Id: file.c,v 1.97 2003/11/02 08:52:35 dwmw2 Exp $ * */ +#include #include -#include /* for min() */ #include #include +#include #include +#include +#include #include #include "nodelist.h" -#include "crc32.h" extern int generic_file_open(struct inode *, struct file *) __attribute__((weak)); extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak)); -int jffs2_null_fsync(struct file *filp, struct dentry *dentry, int datasync) +int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) { - /* Move along. Nothing to see here */ - return 0; + struct inode *inode = dentry->d_inode; + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + + /* Trigger GC to flush any pending writes for this inode */ + jffs2_flush_wbuf_gc(c, inode->i_ino); + + return 0; } struct file_operations jffs2_file_operations = { - llseek: generic_file_llseek, - open: generic_file_open, - read: generic_file_read, - write: generic_file_write, - ioctl: jffs2_ioctl, - mmap: generic_file_mmap, - fsync: jffs2_null_fsync + .llseek = generic_file_llseek, + .open = generic_file_open, + .read = generic_file_read, + .write = generic_file_write, + .ioctl = jffs2_ioctl, + .mmap = generic_file_readonly_mmap, + .fsync = jffs2_fsync, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29) + .sendfile = generic_file_sendfile +#endif }; /* jffs2_file_inode_operations */ struct inode_operations jffs2_file_inode_operations = { - setattr: jffs2_setattr + .setattr = jffs2_setattr }; struct address_space_operations jffs2_file_address_operations = { - readpage: jffs2_readpage, - prepare_write: jffs2_prepare_write, - commit_write: jffs2_commit_write + .readpage = jffs2_readpage, + .prepare_write =jffs2_prepare_write, + .commit_write = jffs2_commit_write }; -int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) -{ - struct jffs2_full_dnode *old_metadata, *new_metadata; - struct inode *inode = dentry->d_inode; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode *ri; - unsigned short dev; - unsigned char *mdata = NULL; - int mdatalen = 0; - unsigned int ivalid; - __u32 phys_ofs, alloclen; - int ret; - D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); - ret = inode_change_ok(inode, iattr); - if (ret) - return ret; - - /* Special cases - we don't want more than one data node - for these types on the medium at any time. So setattr - must read the original data associated with the node - (i.e. the device numbers or the target name) and write - it out again with the appropriate data attached */ - if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { - /* For these, we don't actually need to read the old node */ - dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) | - MINOR(to_kdev_t(dentry->d_inode->i_rdev)); - mdata = (char *)&dev; - mdatalen = sizeof(dev); - D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); - } else if (S_ISLNK(inode->i_mode)) { - mdatalen = f->metadata->size; - mdata = kmalloc(f->metadata->size, GFP_USER); - if (!mdata) - return -ENOMEM; - ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen); - if (ret) { - kfree(mdata); - return ret; - } - D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); - } - - ri = jffs2_alloc_raw_inode(); - if (!ri) { - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - return -ENOMEM; - } - - ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - jffs2_free_raw_inode(ri); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - return ret; - } - down(&f->sem); - ivalid = iattr->ia_valid; - - ri->magic = JFFS2_MAGIC_BITMASK; - ri->nodetype = JFFS2_NODETYPE_INODE; - ri->totlen = sizeof(*ri) + mdatalen; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); - - ri->ino = inode->i_ino; - ri->version = ++f->highest_version; - - ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode; - ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid; - ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid; - - if (ivalid & ATTR_MODE && ri->mode & S_ISGID && - !in_group_p(ri->gid) && !capable(CAP_FSETID)) - ri->mode &= ~S_ISGID; - - ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size; - ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime; - ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime; - ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime; - - ri->offset = 0; - ri->csize = ri->dsize = mdatalen; - ri->compr = JFFS2_COMPR_NONE; - if (inode->i_size < ri->isize) { - /* It's an extension. Make it a hole node */ - ri->compr = JFFS2_COMPR_ZERO; - ri->dsize = ri->isize - inode->i_size; - ri->offset = inode->i_size; - } - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - if (mdatalen) - ri->data_crc = crc32(0, mdata, mdatalen); - else - ri->data_crc = 0; - - new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - - jffs2_complete_reservation(c); - - if (IS_ERR(new_metadata)) { - jffs2_free_raw_inode(ri); - up(&f->sem); - return PTR_ERR(new_metadata); - } - /* It worked. Update the inode */ - inode->i_atime = ri->atime; - inode->i_ctime = ri->ctime; - inode->i_mtime = ri->mtime; - inode->i_mode = ri->mode; - inode->i_uid = ri->uid; - inode->i_gid = ri->gid; - - - old_metadata = f->metadata; - - if (inode->i_size > ri->isize) { - vmtruncate(inode, ri->isize); - jffs2_truncate_fraglist (c, &f->fraglist, ri->isize); - } - - if (inode->i_size < ri->isize) { - jffs2_add_full_dnode_to_inode(c, f, new_metadata); - inode->i_size = ri->isize; - f->metadata = NULL; - } else { - f->metadata = new_metadata; - } - if (old_metadata) { - jffs2_mark_node_obsolete(c, old_metadata->raw); - jffs2_free_full_dnode(old_metadata); - } - jffs2_free_raw_inode(ri); - up(&f->sem); - return 0; -} - int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_node_frag *frag = f->fraglist; - __u32 offset = pg->index << PAGE_CACHE_SHIFT; - __u32 end = offset + PAGE_CACHE_SIZE; unsigned char *pg_buf; int ret; - D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%x\n", inode->i_ino, offset)); + D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT)); if (!PageLocked(pg)) PAGE_BUG(pg); - while(frag && frag->ofs + frag->size <= offset) { - // D1(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size)); - frag = frag->next; - } - pg_buf = kmap(pg); + /* FIXME: Can kmap fail? */ - /* XXX FIXME: Where a single physical node actually shows up in two - frags, we read it twice. Don't do that. */ - /* Now we're pointing at the first frag which overlaps our page */ - while(offset < end) { - D2(printk(KERN_DEBUG "jffs2_readpage: offset %d, end %d\n", offset, end)); - if (!frag || frag->ofs > offset) { - __u32 holesize = end - offset; - if (frag) { - D1(printk(KERN_NOTICE "Eep. Hole in ino %ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", inode->i_ino, frag->ofs, offset)); - holesize = min(holesize, frag->ofs - offset); - D1(jffs2_print_frag_list(f)); - } - D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); - memset(pg_buf, 0, holesize); - pg_buf += holesize; - offset += holesize; - continue; - } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) { - D1(printk(KERN_NOTICE "Eep. Overlap in ino #%ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", - inode->i_ino, frag->ofs, offset)); - D1(jffs2_print_frag_list(f)); - memset(pg_buf, 0, end - offset); - ClearPageUptodate(pg); - SetPageError(pg); - kunmap(pg); - return -EIO; - } else if (!frag->node) { - __u32 holeend = min(end, frag->ofs + frag->size); - D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); - memset(pg_buf, 0, holeend - offset); - pg_buf += holeend - offset; - offset = holeend; - frag = frag->next; - continue; - } else { - __u32 readlen; - __u32 fragofs; /* offset within the frag to start reading */ - - fragofs = offset - frag->ofs; - readlen = min(frag->size - fragofs, end - offset); - D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, - fragofs+frag->ofs+readlen, frag->node->raw->flash_offset & ~3)); - ret = jffs2_read_dnode(c, frag->node, pg_buf, fragofs + frag->ofs - frag->node->ofs, readlen); - D2(printk(KERN_DEBUG "node read done\n")); - if (ret) { - D1(printk(KERN_DEBUG"jffs2_readpage error %d\n",ret)); - memset(pg_buf, 0, readlen); - ClearPageUptodate(pg); - SetPageError(pg); - kunmap(pg); - return ret; - } - - pg_buf += readlen; - offset += readlen; - frag = frag->next; - D2(printk(KERN_DEBUG "node read was OK. Looping\n")); - } + ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE); + + if (ret) { + ClearPageUptodate(pg); + SetPageError(pg); + } else { + SetPageUptodate(pg); + ClearPageError(pg); } - D2(printk(KERN_DEBUG "readpage finishing\n")); - SetPageUptodate(pg); - ClearPageError(pg); flush_dcache_page(pg); - kunmap(pg); - D1(printk(KERN_DEBUG "readpage finished\n")); + + D2(printk(KERN_DEBUG "readpage finished\n")); return 0; } int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) { int ret = jffs2_do_readpage_nolock(inode, pg); - UnlockPage(pg); + unlock_page(pg); return ret; } @@ -333,17 +120,17 @@ { struct inode *inode = pg->mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - __u32 pageofs = pg->index << PAGE_CACHE_SHIFT; + uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; int ret = 0; - D1(printk(KERN_DEBUG "jffs2_prepare_write() nrpages %ld\n", inode->i_mapping->nrpages)); + D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; - __u32 phys_ofs, alloc_len; + uint32_t phys_ofs, alloc_len; D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs)); @@ -355,29 +142,30 @@ down(&f->sem); memset(&ri, 0, sizeof(ri)); - ri.magic = JFFS2_MAGIC_BITMASK; - ri.nodetype = JFFS2_NODETYPE_INODE; - ri.totlen = sizeof(ri); - ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); - - ri.ino = f->inocache->ino; - ri.version = ++f->highest_version; - ri.mode = inode->i_mode; - ri.uid = inode->i_uid; - ri.gid = inode->i_gid; - ri.isize = max((__u32)inode->i_size, pageofs); - ri.atime = ri.ctime = ri.mtime = CURRENT_TIME; - ri.offset = inode->i_size; - ri.dsize = pageofs - inode->i_size; - ri.csize = 0; + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri)); + ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.version = cpu_to_je32(++f->highest_version); + ri.mode = cpu_to_jemode(inode->i_mode); + ri.uid = cpu_to_je16(inode->i_uid); + ri.gid = cpu_to_je16(inode->i_gid); + ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); + ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds()); + ri.offset = cpu_to_je32(inode->i_size); + ri.dsize = cpu_to_je32(pageofs - inode->i_size); + ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; - ri.node_crc = crc32(0, &ri, sizeof(ri)-8); - ri.data_crc = 0; + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); + ri.data_crc = cpu_to_je32(0); - fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); - jffs2_complete_reservation(c); + fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); + if (IS_ERR(fn)) { ret = PTR_ERR(fn); + jffs2_complete_reservation(c); up(&f->sem); return ret; } @@ -391,16 +179,17 @@ D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); + jffs2_complete_reservation(c); up(&f->sem); return ret; } + jffs2_complete_reservation(c); inode->i_size = pageofs; up(&f->sem); } - /* Read in the page if it wasn't already present, unless it's a whole page */ - if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { + if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { down(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); up(&f->sem); @@ -417,14 +206,12 @@ struct inode *inode = pg->mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - __u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end); - __u32 file_ofs = (pg->index << PAGE_CACHE_SHIFT); - __u32 writelen = min((__u32)PAGE_CACHE_SIZE, newsize - file_ofs); struct jffs2_raw_inode *ri; int ret = 0; - ssize_t writtenlen = 0; + uint32_t writtenlen = 0; - D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); + D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", + inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); if (!start && end == PAGE_CACHE_SIZE) { /* We need to avoid deadlock with page_cache_read() in @@ -435,109 +222,47 @@ } ri = jffs2_alloc_raw_inode(); - if (!ri) - return -ENOMEM; - - while(writelen) { - struct jffs2_full_dnode *fn; - unsigned char *comprbuf = NULL; - unsigned char comprtype = JFFS2_COMPR_NONE; - __u32 phys_ofs, alloclen; - __u32 datalen, cdatalen; - - D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, file_ofs)); - - ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - SetPageError(pg); - D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); - break; - } - down(&f->sem); - datalen = writelen; - cdatalen = min(alloclen - sizeof(*ri), writelen); - comprbuf = kmalloc(cdatalen, GFP_KERNEL); - if (comprbuf) { - comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen); - } - if (comprtype == JFFS2_COMPR_NONE) { - /* Either compression failed, or the allocation of comprbuf failed */ - if (comprbuf) - kfree(comprbuf); - comprbuf = page_address(pg) + (file_ofs & (PAGE_CACHE_SIZE -1)); - datalen = cdatalen; - } - /* Now comprbuf points to the data to be written, be it compressed or not. - comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means - that the comprbuf doesn't need to be kfree()d. - */ - - ri->magic = JFFS2_MAGIC_BITMASK; - ri->nodetype = JFFS2_NODETYPE_INODE; - ri->totlen = sizeof(*ri) + cdatalen; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); - - ri->ino = inode->i_ino; - ri->version = ++f->highest_version; - ri->mode = inode->i_mode; - ri->uid = inode->i_uid; - ri->gid = inode->i_gid; - ri->isize = max((__u32)inode->i_size, file_ofs + datalen); - ri->atime = ri->ctime = ri->mtime = CURRENT_TIME; - ri->offset = file_ofs; - ri->csize = cdatalen; - ri->dsize = datalen; - ri->compr = comprtype; - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - ri->data_crc = crc32(0, comprbuf, cdatalen); + if (!ri) { + D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n")); + return -ENOMEM; + } - fn = jffs2_write_dnode(inode, ri, comprbuf, cdatalen, phys_ofs, NULL); + /* Set the fields that the generic jffs2_write_inode_range() code can't find */ + ri->ino = cpu_to_je32(inode->i_ino); + ri->mode = cpu_to_jemode(inode->i_mode); + ri->uid = cpu_to_je16(inode->i_uid); + ri->gid = cpu_to_je16(inode->i_gid); + ri->isize = cpu_to_je32((uint32_t)inode->i_size); + ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds()); + + /* In 2.4, it was already kmapped by generic_file_write(). Doesn't + hurt to do it again. The alternative is ifdefs, which are ugly. */ + kmap(pg); + + ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start, + (pg->index << PAGE_CACHE_SHIFT) + start, + end - start, &writtenlen); - jffs2_complete_reservation(c); + kunmap(pg); - if (comprtype != JFFS2_COMPR_NONE) - kfree(comprbuf); + if (ret) { + /* There was an error writing. */ + SetPageError(pg); + } - if (IS_ERR(fn)) { - ret = PTR_ERR(fn); - up(&f->sem); - SetPageError(pg); - break; + if (writtenlen) { + if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { + inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; + inode->i_blocks = (inode->i_size + 511) >> 9; + + inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); } - ret = jffs2_add_full_dnode_to_inode(c, f, fn); - if (f->metadata) { - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - } - up(&f->sem); - if (ret) { - /* Eep */ - D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); - jffs2_mark_node_obsolete(c, fn->raw); - jffs2_free_full_dnode(fn); - SetPageError(pg); - break; - } - inode->i_size = ri->isize; - inode->i_blocks = (inode->i_size + 511) >> 9; - inode->i_ctime = inode->i_mtime = ri->ctime; - if (!datalen) { - printk(KERN_WARNING "Eep. We didn't actually write any bloody data\n"); - ret = -EIO; - SetPageError(pg); - break; - } - D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); - writtenlen += datalen; - file_ofs += datalen; - writelen -= datalen; } jffs2_free_raw_inode(ri); - if (writtenlen < end) { + if (start+writtenlen < end) { /* generic_file_write has written more to the page cache than we've actually written to the medium. Mark the page !Uptodate so that it gets reread */ @@ -545,13 +270,7 @@ SetPageError(pg); ClearPageUptodate(pg); } - if (writtenlen <= start) { - /* We didn't even get to the start of the affected part */ - ret = ret?ret:-ENOSPC; - D1(printk(KERN_DEBUG "jffs2_commit_write(): Only %x bytes written to page. start (%x) not reached, returning %d\n", writtenlen, start, ret)); - } - writtenlen = min(end-start, writtenlen-start); - D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d. nrpages is %ld\n",writtenlen?writtenlen:ret, inode->i_mapping->nrpages)); + D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret)); return writtenlen?writtenlen:ret; } diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c --- a/fs/jffs2/gc.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/gc.c Thu Dec 4 16:24:25 2003 @@ -1,76 +1,67 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: gc.c,v 1.52.2.5 2002/10/10 13:18:38 dwmw2 Exp $ + * $Id: gc.c,v 1.131 2003/11/24 12:07:28 dwmw2 Exp $ * */ #include #include #include -#include -#include -#include #include +#include +#include +#include #include "nodelist.h" -#include "crc32.h" +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw); static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dnode *fd); + struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dirent *fd); + struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dirent *fd); + struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *indeo, struct jffs2_full_dnode *fn, - __u32 start, __u32 end); + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, + uint32_t start, uint32_t end); static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dnode *fn, - __u32 start, __u32 end); + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, + uint32_t start, uint32_t end); +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f); /* Called with erase_completion_lock held */ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) { struct jffs2_eraseblock *ret; struct list_head *nextlist = NULL; + int n = jiffies % 128; /* Pick an eraseblock to garbage collect next. This is where we'll put the clever wear-levelling algorithms. Eventually. */ - if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) { + /* We possibly want to favour the dirtier blocks more when the + number of free blocks is low. */ + if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); nextlist = &c->bad_used_list; - } else if (jiffies % 100 && !list_empty(&c->dirty_list)) { - /* Most of the time, pick one off the dirty list */ + } else if (n < 50 && !list_empty(&c->erasable_list)) { + /* Note that most of them will have gone directly to be erased. + So don't favour the erasable_list _too_ much. */ + D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n")); + nextlist = &c->erasable_list; + } else if (n < 110 && !list_empty(&c->very_dirty_list)) { + /* Most of the time, pick one off the very_dirty list */ + D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n")); + nextlist = &c->very_dirty_list; + } else if (n < 126 && !list_empty(&c->dirty_list)) { D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n")); nextlist = &c->dirty_list; } else if (!list_empty(&c->clean_list)) { @@ -80,9 +71,16 @@ D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n")); nextlist = &c->dirty_list; + } else if (!list_empty(&c->very_dirty_list)) { + D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n")); + nextlist = &c->very_dirty_list; + } else if (!list_empty(&c->erasable_list)) { + D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); + + nextlist = &c->erasable_list; } else { - /* Eep. Both were empty */ - printk(KERN_NOTICE "jffs2: No clean _or_ dirty blocks to GC from! Where are they all?\n"); + /* Eep. All were empty */ + printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"); return NULL; } @@ -94,6 +92,17 @@ printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); BUG(); } + + /* Have we accidentally picked a clean block with wasted space ? */ + if (ret->wasted_size) { + D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size)); + ret->dirty_size += ret->wasted_size; + c->wasted_size -= ret->wasted_size; + c->dirty_size += ret->wasted_size; + ret->wasted_size = 0; + } + + D1(jffs2_dump_block_lists(c)); return ret; } @@ -103,21 +112,90 @@ */ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) { - struct jffs2_eraseblock *jeb; struct jffs2_inode_info *f; + struct jffs2_inode_cache *ic; + struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; - struct jffs2_node_frag *frag; - struct jffs2_full_dnode *fn = NULL; - struct jffs2_full_dirent *fd; - __u32 start = 0, end = 0, nrfrags = 0; - __u32 inum; - struct inode *inode; - int ret = 0; + int ret = 0, inum, nlink; if (down_interruptible(&c->alloc_sem)) return -EINTR; - spin_lock_bh(&c->erase_completion_lock); + for (;;) { + spin_lock(&c->erase_completion_lock); + if (!c->unchecked_size) + break; + + /* We can't start doing GC yet. We haven't finished checking + the node CRCs etc. Do it now. */ + + /* checked_ino is protected by the alloc_sem */ + if (c->checked_ino > c->highest_ino) { + printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", + c->unchecked_size); + D1(jffs2_dump_block_lists(c)); + spin_unlock(&c->erase_completion_lock); + BUG(); + } + + spin_unlock(&c->erase_completion_lock); + + spin_lock(&c->inocache_lock); + + ic = jffs2_get_ino_cache(c, c->checked_ino++); + + if (!ic) { + spin_unlock(&c->inocache_lock); + continue; + } + + if (!ic->nlink) { + D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", + ic->ino)); + spin_unlock(&c->inocache_lock); + continue; + } + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + case INO_STATE_PRESENT: + D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino)); + spin_unlock(&c->inocache_lock); + continue; + + case INO_STATE_GC: + case INO_STATE_CHECKING: + printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state); + spin_unlock(&c->inocache_lock); + BUG(); + + case INO_STATE_READING: + /* We need to wait for it to finish, lest we move on + and trigger the BUG() above while we haven't yet + finished checking all its nodes */ + D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); + up(&c->alloc_sem); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + return 0; + + default: + BUG(); + + case INO_STATE_UNCHECKED: + ; + } + ic->state = INO_STATE_CHECKING; + spin_unlock(&c->inocache_lock); + + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino)); + + ret = jffs2_do_crccheck_inode(c, ic); + if (ret) + printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); + + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); + up(&c->alloc_sem); + return ret; + } /* First, work out which block we're garbage-collecting */ jeb = c->gcblock; @@ -127,12 +205,14 @@ if (!jeb) { printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); return -EIO; } - D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset)); + D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size)); + D1(if (c->nextblock) + printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); if (!jeb->used_size) { up(&c->alloc_sem); @@ -141,61 +221,211 @@ raw = jeb->gc_node; - while(raw->flash_offset & 1) { - D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3)); - jeb->gc_node = raw = raw->next_phys; - if (!raw) { + while(ref_obsolete(raw)) { + D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); + raw = raw->next_phys; + if (unlikely(!raw)) { printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); - spin_unlock_bh(&c->erase_completion_lock); + jeb->gc_node = raw; + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); BUG(); } } - D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3)); + jeb->gc_node = raw; + + D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw))); + if (!raw->next_in_ino) { /* Inode-less node. Clean marker, snapshot or something like that */ - spin_unlock_bh(&c->erase_completion_lock); + /* FIXME: If it's something that needs to be copied, including something + we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ + spin_unlock(&c->erase_completion_lock); jffs2_mark_node_obsolete(c, raw); up(&c->alloc_sem); goto eraseit_lock; } - - inum = jffs2_raw_ref_to_inum(raw); - D1(printk(KERN_DEBUG "Inode number is #%u\n", inum)); - - spin_unlock_bh(&c->erase_completion_lock); - - D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, inum)); - - inode = iget(OFNI_BS_2SFFJ(c), inum); - if (is_bad_inode(inode)) { - printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum); - /* NB. This will happen again. We need to do something appropriate here. */ + + ic = jffs2_raw_ref_to_ic(raw); + + /* We need to hold the inocache. Either the erase_completion_lock or + the inocache_lock are sufficient; we trade down since the inocache_lock + causes less contention. */ + spin_lock(&c->inocache_lock); + + spin_unlock(&c->erase_completion_lock); + + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino)); + + /* Three possibilities: + 1. Inode is already in-core. We must iget it and do proper + updating to its fragtree, etc. + 2. Inode is not in-core, node is REF_PRISTINE. We lock the + inocache to prevent a read_inode(), copy the node intact. + 3. Inode is not in-core, node is not pristine. We must iget() + and take the slow path. + */ + + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + /* It's been checked, but it's not currently in-core. + We can just copy any pristine nodes, but have + to prevent anyone else from doing read_inode() while + we're at it, so we set the state accordingly */ + if (ref_flags(raw) == REF_PRISTINE) + ic->state = INO_STATE_GC; + else { + D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", + ic->ino)); + } + break; + + case INO_STATE_PRESENT: + /* It's in-core. GC must iget() it. */ + break; + + case INO_STATE_UNCHECKED: + case INO_STATE_CHECKING: + case INO_STATE_GC: + /* Should never happen. We should have finished checking + by the time we actually start doing any GC, and since + we're holding the alloc_sem, no other garbage collection + can happen. + */ + printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", + ic->ino, ic->state); up(&c->alloc_sem); - iput(inode); - return -EIO; + spin_unlock(&c->inocache_lock); + BUG(); + + case INO_STATE_READING: + /* Someone's currently trying to read it. We must wait for + them to finish and then go through the full iget() route + to do the GC. However, sometimes read_inode() needs to get + the alloc_sem() (for marking nodes invalid) so we must + drop the alloc_sem before sleeping. */ + + up(&c->alloc_sem); + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", + ic->ino, ic->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + /* And because we dropped the alloc_sem we must start again from the + beginning. Ponder chance of livelock here -- we're returning success + without actually making any progress. + + Q: What are the chances that the inode is back in INO_STATE_READING + again by the time we next enter this function? And that this happens + enough times to cause a real delay? + + A: Small enough that I don't care :) + */ + return 0; + } + + /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the + node intact, and we don't have to muck about with the fragtree etc. + because we know it's not in-core. If it _was_ in-core, we go through + all the iget() crap anyway */ + + if (ic->state == INO_STATE_GC) { + spin_unlock(&c->inocache_lock); + + ret = jffs2_garbage_collect_pristine(c, ic, raw); + + spin_lock(&c->inocache_lock); + ic->state = INO_STATE_CHECKEDABSENT; + wake_up(&c->inocache_wq); + + if (ret != -EBADFD) { + spin_unlock(&c->inocache_lock); + goto release_sem; + } + + /* Fall through if it wanted us to, with inocache_lock held */ } - f = JFFS2_INODE_INFO(inode); + /* Prevent the fairly unlikely race where the gcblock is + entirely obsoleted by the final close of a file which had + the only valid nodes in the block, followed by erasure, + followed by freeing of the ic because the erased block(s) + held _all_ the nodes of that inode.... never been seen but + it's vaguely possible. */ + + inum = ic->ino; + nlink = ic->nlink; + spin_unlock(&c->inocache_lock); + + f = jffs2_gc_fetch_inode(c, inum, nlink); + if (IS_ERR(f)) + return PTR_ERR(f); + if (!f) + return 0; + + ret = jffs2_garbage_collect_live(c, jeb, raw, f); + + jffs2_gc_release_inode(c, f); + + release_sem: + up(&c->alloc_sem); + + eraseit_lock: + /* If we've finished this block, start it erasing */ + spin_lock(&c->erase_completion_lock); + + eraseit: + if (c->gcblock && !c->gcblock->used_size) { + D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); + /* We're GC'ing an empty block? */ + list_add_tail(&c->gcblock->list, &c->erase_pending_list); + c->gcblock = NULL; + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + } + spin_unlock(&c->erase_completion_lock); + + return ret; +} + +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f) +{ + struct jffs2_node_frag *frag; + struct jffs2_full_dnode *fn = NULL; + struct jffs2_full_dirent *fd; + uint32_t start = 0, end = 0, nrfrags = 0; + int ret = 0; + down(&f->sem); + /* Now we have the lock for this inode. Check that it's still the one at the head of the list. */ - if (raw->flash_offset & 1) { + spin_lock(&c->erase_completion_lock); + + if (c->gcblock != jeb) { + spin_unlock(&c->erase_completion_lock); + D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n")); + goto upnout; + } + if (ref_obsolete(raw)) { + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n")); /* They'll call again */ goto upnout; } + spin_unlock(&c->erase_completion_lock); + /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */ if (f->metadata && f->metadata->raw == raw) { fn = f->metadata; - ret = jffs2_garbage_collect_metadata(c, jeb, inode, fn); + ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); goto upnout; } - - for (frag = f->fraglist; frag; frag = frag->next) { + + /* FIXME. Read node and do lookup? */ + for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { if (frag->node && frag->node->raw == raw) { fn = frag->node; end = frag->ofs + frag->size; @@ -206,13 +436,22 @@ } } if (fn) { + if (ref_flags(raw) == REF_PRISTINE) { + ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); + if (!ret) { + /* Urgh. Return it sensibly. */ + frag->node->raw = f->inocache->nodes; + } + if (ret != -EBADFD) + goto upnout; + } /* We found a datanode. Do the GC */ if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { /* It crosses a page boundary. Therefore, it must be a hole. */ - ret = jffs2_garbage_collect_hole(c, jeb, inode, fn, start, end); + ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); } else { /* It could still be a hole. But we GC the page this way anyway */ - ret = jffs2_garbage_collect_dnode(c, jeb, inode, fn, start, end); + ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end); } goto upnout; } @@ -224,12 +463,13 @@ } if (fd && fd->ino) { - ret = jffs2_garbage_collect_dirent(c, jeb, inode, fd); + ret = jffs2_garbage_collect_dirent(c, jeb, f, fd); } else if (fd) { - ret = jffs2_garbage_collect_deletion_dirent(c, jeb, inode, fd); + ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); } else { - printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%lu\n", raw->flash_offset&~3, inode->i_ino); - if (raw->flash_offset & 1) { + printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n", + ref_offset(raw), f->inocache->ino); + if (ref_obsolete(raw)) { printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); } else { ret = -EIO; @@ -237,46 +477,197 @@ } upnout: up(&f->sem); - up(&c->alloc_sem); - iput(inode); - eraseit_lock: - /* If we've finished this block, start it erasing */ - spin_lock_bh(&c->erase_completion_lock); + return ret; +} - eraseit: - if (c->gcblock && !c->gcblock->used_size) { - D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); - /* We're GC'ing an empty block? */ - list_add_tail(&c->gcblock->list, &c->erase_pending_list); - c->gcblock = NULL; - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw) +{ + union jffs2_node_union *node; + struct jffs2_raw_node_ref *nraw; + size_t retlen; + int ret; + uint32_t phys_ofs, alloclen; + uint32_t crc, rawlen; + int retried = 0; + + D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); + + rawlen = ref_totlen(c, c->gcblock, raw); + + /* Ask for a small amount of space (or the totlen if smaller) because we + don't want to force wastage of the end of a block if splitting would + work. */ + ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, + rawlen), &phys_ofs, &alloclen); + if (ret) + return ret; + + if (alloclen < rawlen) { + /* Doesn't fit untouched. We'll go the old route and split it */ + return -EBADFD; + } + + node = kmalloc(rawlen, GFP_KERNEL); + if (!node) + return -ENOMEM; + + ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); + if (!ret && retlen != rawlen) + ret = -EIO; + if (ret) + goto out_node; + + crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); + if (je32_to_cpu(node->u.hdr_crc) != crc) { + printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); + goto bail; + } + + switch(je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + crc = crc32(0, node, sizeof(node->i)-8); + if (je32_to_cpu(node->i.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); + goto bail; + } + + if (je32_to_cpu(node->i.dsize)) { + crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); + if (je32_to_cpu(node->i.data_crc) != crc) { + printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); + goto bail; + } + } + break; + + case JFFS2_NODETYPE_DIRENT: + crc = crc32(0, node, sizeof(node->d)-8); + if (je32_to_cpu(node->d.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); + goto bail; + } + + if (node->d.nsize) { + crc = crc32(0, node->d.name, node->d.nsize); + if (je32_to_cpu(node->d.name_crc) != crc) { + printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); + goto bail; + } + } + break; + default: + printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + goto bail; + } + + nraw = jffs2_alloc_raw_node_ref(); + if (!nraw) { + ret = -ENOMEM; + goto out_node; + } + + /* OK, all the CRCs are good; this node can just be copied as-is. */ + retry: + nraw->flash_offset = phys_ofs; + nraw->__totlen = rawlen; + nraw->next_phys = NULL; + + ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); + + if (ret || (retlen != rawlen)) { + printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", + rawlen, phys_ofs, ret, retlen); + if (retlen) { + /* Doesn't belong to any inode */ + nraw->next_in_ino = NULL; + + nraw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, nraw); + jffs2_mark_node_obsolete(c, nraw); + } else { + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); + jffs2_free_raw_node_ref(nraw); + } + if (!retried && (nraw == jffs2_alloc_raw_node_ref())) { + /* Try to reallocate space and retry */ + uint32_t dummy; + struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; + + retried = 1; + + D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n")); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); + + if (!ret) { + D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + goto retry; + } + D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(nraw); + } + + if (!ret) + ret = -EIO; + goto out_node; } - spin_unlock_bh(&c->erase_completion_lock); + nraw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, nraw); + /* Link into per-inode list. This is safe because of the ic + state being INO_STATE_GC. Note that if we're doing this + for an inode which is in-code, the 'nraw' pointer is then + going to be fetched from ic->nodes by our caller. */ + nraw->next_in_ino = ic->nodes; + ic->nodes = nraw; + + jffs2_mark_node_obsolete(c, raw); + D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); + + out_node: + kfree(node); return ret; + bail: + ret = -EBADFD; + goto out_node; } static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dnode *fn) + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - unsigned short dev; + jint16_t dev; char *mdata = NULL, mdatalen = 0; - __u32 alloclen, phys_ofs; + uint32_t alloclen, phys_ofs; int ret; - if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { + if (S_ISBLK(JFFS2_F_I_MODE(f)) || + S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ - dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) | - MINOR(to_kdev_t(inode->i_rdev)); + /* FIXME: for minor or major > 255. */ + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | + JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); - } else if (S_ISLNK(inode->i_mode)) { + } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { mdatalen = fn->size; mdata = kmalloc(fn->size, GFP_KERNEL); if (!mdata) { @@ -295,34 +686,34 @@ ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", sizeof(ri)+ mdatalen, ret); goto out; } memset(&ri, 0, sizeof(ri)); - ri.magic = JFFS2_MAGIC_BITMASK; - ri.nodetype = JFFS2_NODETYPE_INODE; - ri.totlen = sizeof(ri) + mdatalen; - ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); - - ri.ino = inode->i_ino; - ri.version = ++f->highest_version; - ri.mode = inode->i_mode; - ri.uid = inode->i_uid; - ri.gid = inode->i_gid; - ri.isize = inode->i_size; - ri.atime = inode->i_atime; - ri.ctime = inode->i_ctime; - ri.mtime = inode->i_mtime; - ri.offset = 0; - ri.csize = mdatalen; - ri.dsize = mdatalen; + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen); + ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.version = cpu_to_je32(++f->highest_version); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); + ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); + ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); + ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); + ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); + ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); + ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); + ri.offset = cpu_to_je32(0); + ri.csize = cpu_to_je32(mdatalen); + ri.dsize = cpu_to_je32(mdatalen); ri.compr = JFFS2_COMPR_NONE; - ri.node_crc = crc32(0, &ri, sizeof(ri)-8); - ri.data_crc = crc32(0, mdata, mdatalen); + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); + ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); - new_fn = jffs2_write_dnode(inode, &ri, mdata, mdatalen, phys_ofs, NULL); + new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC); if (IS_ERR(new_fn)) { printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn)); @@ -333,41 +724,40 @@ jffs2_free_full_dnode(fn); f->metadata = new_fn; out: - if (S_ISLNK(inode->i_mode)) + if (S_ISLNK(JFFS2_F_I_MODE(f))) kfree(mdata); return ret; } static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dirent *fd) + struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dirent *new_fd; struct jffs2_raw_dirent rd; - __u32 alloclen, phys_ofs; + uint32_t alloclen, phys_ofs; int ret; - rd.magic = JFFS2_MAGIC_BITMASK; - rd.nodetype = JFFS2_NODETYPE_DIRENT; + rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd.nsize = strlen(fd->name); - rd.totlen = sizeof(rd) + rd.nsize; - rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4); + rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); + rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); - rd.pino = inode->i_ino; - rd.version = ++f->highest_version; - rd.ino = fd->ino; - rd.mctime = max(inode->i_mtime, inode->i_ctime); + rd.pino = cpu_to_je32(f->inocache->ino); + rd.version = cpu_to_je32(++f->highest_version); + rd.ino = cpu_to_je32(fd->ino); + rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f))); rd.type = fd->type; - rd.node_crc = crc32(0, &rd, sizeof(rd)-8); - rd.name_crc = crc32(0, fd->name, rd.nsize); + rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); + rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", sizeof(rd)+rd.nsize, ret); return ret; } - new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL); + new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC); if (IS_ERR(new_fd)) { printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd)); @@ -378,19 +768,98 @@ } static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dirent *fd) + struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dirent **fdp = &f->dents; int found = 0; - /* FIXME: When we run on NAND flash, we need to work out whether - this deletion dirent is still needed to actively delete a - 'real' dirent with the same name that's still somewhere else - on the flash. For now, we know that we've actually obliterated - all the older dirents when they became obsolete, so we didn't - really need to write the deletion to flash in the first place. - */ + /* On a medium where we can't actually mark nodes obsolete + pernamently, such as NAND flash, we need to work out + whether this deletion dirent is still needed to actively + delete a 'real' dirent with the same name that's still + somewhere else on the flash. */ + if (!jffs2_can_mark_obsolete(c)) { + struct jffs2_raw_dirent *rd; + struct jffs2_raw_node_ref *raw; + int ret; + size_t retlen; + int name_len = strlen(fd->name); + uint32_t name_crc = crc32(0, fd->name, name_len); + uint32_t rawlen = ref_totlen(c, jeb, fd->raw); + + rd = kmalloc(rawlen, GFP_KERNEL); + if (!rd) + return -ENOMEM; + + /* Prevent the erase code from nicking the obsolete node refs while + we're looking at them. I really don't like this extra lock but + can't see any alternative. Suggestions on a postcard to... */ + down(&c->erase_free_sem); + + for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { + + /* We only care about obsolete ones */ + if (!(ref_obsolete(raw))) + continue; + + /* Any dirent with the same name is going to have the same length... */ + if (ref_totlen(c, NULL, raw) != rawlen) + continue; + + /* Doesn't matter if there's one in the same erase block. We're going to + delete it too at the same time. */ + if ((raw->flash_offset & ~(c->sector_size-1)) == + (fd->raw->flash_offset & ~(c->sector_size-1))) + continue; + + D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); + + /* This is an obsolete node belonging to the same directory, and it's of the right + length. We need to take a closer look...*/ + ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd); + if (ret) { + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw)); + /* If we can't read it, we don't need to continue to obsolete it. Continue */ + continue; + } + if (retlen != rawlen) { + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n", + retlen, rawlen, ref_offset(raw)); + continue; + } + + if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) + continue; + + /* If the name CRC doesn't match, skip */ + if (je32_to_cpu(rd->name_crc) != name_crc) + continue; + + /* If the name length doesn't match, or it's another deletion dirent, skip */ + if (rd->nsize != name_len || !je32_to_cpu(rd->ino)) + continue; + + /* OK, check the actual name now */ + if (memcmp(rd->name, fd->name, name_len)) + continue; + + /* OK. The name really does match. There really is still an older node on + the flash which our deletion dirent obsoletes. So we have to write out + a new deletion dirent to replace it */ + up(&c->erase_free_sem); + + D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", + ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); + kfree(rd); + + return jffs2_garbage_collect_dirent(c, jeb, f, fd); + } + + up(&c->erase_free_sem); + kfree(rd); + } + + /* No need for it any more. Just mark it obsolete and remove it from the list */ while (*fdp) { if ((*fdp) == fd) { found = 1; @@ -400,7 +869,7 @@ fdp = &(*fdp)->next; } if (!found) { - printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino); + printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino); } jffs2_mark_node_obsolete(c, fd->raw); jffs2_free_full_dirent(fd); @@ -408,93 +877,95 @@ } static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dnode *fn, - __u32 start, __u32 end) + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, + uint32_t start, uint32_t end) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_raw_inode ri; struct jffs2_node_frag *frag; struct jffs2_full_dnode *new_fn; - __u32 alloclen, phys_ofs; + uint32_t alloclen, phys_ofs; int ret; - D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n", - inode->i_ino, start, end)); + D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", + f->inocache->ino, start, end)); memset(&ri, 0, sizeof(ri)); if(fn->frags > 1) { size_t readlen; - __u32 crc; + uint32_t crc; /* It's partially obsoleted by a later write. So we have to write it out again with the _same_ version as before */ - ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri); + ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { - printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen); + printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen); goto fill; } - if (ri.nodetype != JFFS2_NODETYPE_INODE) { + if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", - fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE); + ref_offset(fn->raw), + je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE); return -EIO; } - if (ri.totlen != sizeof(ri)) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", - fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri)); + if (je32_to_cpu(ri.totlen) != sizeof(ri)) { + printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", + ref_offset(fn->raw), + je32_to_cpu(ri.totlen), sizeof(ri)); return -EIO; } crc = crc32(0, &ri, sizeof(ri)-8); - if (crc != ri.node_crc) { + if (crc != je32_to_cpu(ri.node_crc)) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", - fn->raw->flash_offset & ~3, ri.node_crc, crc); + ref_offset(fn->raw), + je32_to_cpu(ri.node_crc), crc); /* FIXME: We could possibly deal with this by writing new holes for each frag */ - printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", - start, end, inode->i_ino); + printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", + start, end, f->inocache->ino); goto fill; } if (ri.compr != JFFS2_COMPR_ZERO) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3); - printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", - start, end, inode->i_ino); + printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw)); + printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", + start, end, f->inocache->ino); goto fill; } } else { fill: - ri.magic = JFFS2_MAGIC_BITMASK; - ri.nodetype = JFFS2_NODETYPE_INODE; - ri.totlen = sizeof(ri); - ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); - - ri.ino = inode->i_ino; - ri.version = ++f->highest_version; - ri.offset = start; - ri.dsize = end - start; - ri.csize = 0; + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri)); + ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.version = cpu_to_je32(++f->highest_version); + ri.offset = cpu_to_je32(start); + ri.dsize = cpu_to_je32(end - start); + ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } - ri.mode = inode->i_mode; - ri.uid = inode->i_uid; - ri.gid = inode->i_gid; - ri.isize = inode->i_size; - ri.atime = inode->i_atime; - ri.ctime = inode->i_ctime; - ri.mtime = inode->i_mtime; - ri.data_crc = 0; - ri.node_crc = crc32(0, &ri, sizeof(ri)-8); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); + ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); + ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); + ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); + ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); + ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); + ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); + ri.data_crc = cpu_to_je32(0); + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", sizeof(ri), ret); return ret; } - new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); + new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC); if (IS_ERR(new_fn)) { printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn)); return PTR_ERR(new_fn); } - if (ri.version == f->highest_version) { + if (je32_to_cpu(ri.version) == f->highest_version) { jffs2_add_full_dnode_to_inode(c, f, new_fn); if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); @@ -510,12 +981,17 @@ * number as before. (Except in case of error -- see 'goto fill;' * above.) */ - D1(if(fn->frags <= 1) { + D1(if(unlikely(fn->frags <= 1)) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", - fn->frags, ri.version, f->highest_version, ri.ino); + fn->frags, je32_to_cpu(ri.version), f->highest_version, + je32_to_cpu(ri.ino)); }); - for (frag = f->fraglist; frag; frag = frag->next) { + /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ + mark_ref_normal(new_fn->raw); + + for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); + frag; frag = frag_next(frag)) { if (frag->ofs > fn->size + fn->ofs) break; if (frag->node == fn) { @@ -540,49 +1016,146 @@ } static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct inode *inode, struct jffs2_full_dnode *fn, - __u32 start, __u32 end) + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, + uint32_t start, uint32_t end) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - __u32 alloclen, phys_ofs, offset, orig_end; + uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; int ret = 0; unsigned char *comprbuf = NULL, *writebuf; - struct page *pg; + unsigned long pg; unsigned char *pg_ptr; - - + memset(&ri, 0, sizeof(ri)); - D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n", - inode->i_ino, start, end)); + D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", + f->inocache->ino, start, end)); orig_end = end; + orig_start = start; + if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { + /* Attempt to do some merging. But only expand to cover logically + adjacent frags if the block containing them is already considered + to be dirty. Otherwise we end up with GC just going round in + circles dirtying the nodes it already wrote out, especially + on NAND where we have small eraseblocks and hence a much higher + chance of nodes having to be split to cross boundaries. */ - /* If we're looking at the last node in the block we're - garbage-collecting, we allow ourselves to merge as if the - block was already erasing. We're likely to be GC'ing a - partial page, and the next block we GC is likely to have - the other half of this page right at the beginning, which - means we'd expand it _then_, as nr_erasing_blocks would have - increased since we checked, and in doing so would obsolete - the partial node which we'd have written here. Meaning that - the GC would churn and churn, and just leave dirty blocks in - it's wake. - */ - if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) { - /* Shitloads of space */ - /* FIXME: Integrate this properly with GC calculations */ - start &= ~(PAGE_CACHE_SIZE-1); - end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size); - D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n", - start, end)); - if (end < orig_end) { - printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end); - end = orig_end; + struct jffs2_node_frag *frag; + uint32_t min, max; + + min = start & ~(PAGE_CACHE_SIZE-1); + max = min + PAGE_CACHE_SIZE; + + frag = jffs2_lookup_node_frag(&f->fragtree, start); + + /* BUG_ON(!frag) but that'll happen anyway... */ + + BUG_ON(frag->ofs != start); + + /* First grow down... */ + while((frag = frag_prev(frag)) && frag->ofs >= min) { + + /* If the previous frag doesn't even reach the beginning, there's + excessive fragmentation. Just merge. */ + if (frag->ofs > min) { + D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n", + frag->ofs, frag->ofs+frag->size)); + start = frag->ofs; + continue; + } + /* OK. This frag holds the first byte of the page. */ + if (!frag->node || !frag->node->raw) { + D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n", + frag->ofs, frag->ofs+frag->size)); + break; + } else { + + /* OK, it's a frag which extends to the beginning of the page. Does it live + in a block which is still considered clean? If so, don't obsolete it. + If not, cover it anyway. */ + + struct jffs2_raw_node_ref *raw = frag->node->raw; + struct jffs2_eraseblock *jeb; + + jeb = &c->blocks[raw->flash_offset / c->sector_size]; + + if (jeb == c->gcblock) { + D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n", + frag->ofs, frag->ofs+frag->size, ref_offset(raw))); + start = frag->ofs; + break; + } + if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { + D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n", + frag->ofs, frag->ofs+frag->size, jeb->offset)); + break; + } + + D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n", + frag->ofs, frag->ofs+frag->size, jeb->offset)); + start = frag->ofs; + break; + } + } + + /* ... then up */ + + /* Find last frag which is actually part of the node we're to GC. */ + frag = jffs2_lookup_node_frag(&f->fragtree, end-1); + + while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { + + /* If the previous frag doesn't even reach the beginning, there's lots + of fragmentation. Just merge. */ + if (frag->ofs+frag->size < max) { + D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n", + frag->ofs, frag->ofs+frag->size)); + end = frag->ofs + frag->size; + continue; + } + + if (!frag->node || !frag->node->raw) { + D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n", + frag->ofs, frag->ofs+frag->size)); + break; + } else { + + /* OK, it's a frag which extends to the beginning of the page. Does it live + in a block which is still considered clean? If so, don't obsolete it. + If not, cover it anyway. */ + + struct jffs2_raw_node_ref *raw = frag->node->raw; + struct jffs2_eraseblock *jeb; + + jeb = &c->blocks[raw->flash_offset / c->sector_size]; + + if (jeb == c->gcblock) { + D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n", + frag->ofs, frag->ofs+frag->size, ref_offset(raw))); + end = frag->ofs + frag->size; + break; + } + if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { + D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n", + frag->ofs, frag->ofs+frag->size, jeb->offset)); + break; + } + + D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n", + frag->ofs, frag->ofs+frag->size, jeb->offset)); + end = frag->ofs + frag->size; + break; + } } + D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", + orig_start, orig_end, start, end)); + + BUG_ON(end > JFFS2_F_I_SIZE(f)); + BUG_ON(end < orig_end); + BUG_ON(start > orig_start); } /* First, use readpage() to read the appropriate page into the page cache */ @@ -592,63 +1165,57 @@ * page OK. We'll actually write it out again in commit_write, which is a little * suboptimal, but at least we're correct. */ - pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); + pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); - if (IS_ERR(pg)) { - printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg)); - return PTR_ERR(pg); + if (IS_ERR(pg_ptr)) { + printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr)); + return PTR_ERR(pg_ptr); } - pg_ptr = (char *)kmap(pg); - comprbuf = kmalloc(end - start, GFP_KERNEL); offset = start; while(offset < orig_end) { - __u32 datalen; - __u32 cdatalen; + uint32_t datalen; + uint32_t cdatalen; char comprtype = JFFS2_COMPR_NONE; ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret); break; } - cdatalen = min(alloclen - sizeof(ri), end - offset); + cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); datalen = end - offset; writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); - if (comprbuf) { - comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen); - } - if (comprtype) { - writebuf = comprbuf; - } else { - datalen = cdatalen; - } - ri.magic = JFFS2_MAGIC_BITMASK; - ri.nodetype = JFFS2_NODETYPE_INODE; - ri.totlen = sizeof(ri) + cdatalen; - ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); - - ri.ino = inode->i_ino; - ri.version = ++f->highest_version; - ri.mode = inode->i_mode; - ri.uid = inode->i_uid; - ri.gid = inode->i_gid; - ri.isize = inode->i_size; - ri.atime = inode->i_atime; - ri.ctime = inode->i_ctime; - ri.mtime = inode->i_mtime; - ri.offset = offset; - ri.csize = cdatalen; - ri.dsize = datalen; + comprtype = jffs2_compress(writebuf, &comprbuf, &datalen, &cdatalen); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen); + ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.version = cpu_to_je32(++f->highest_version); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); + ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); + ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); + ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); + ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); + ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); + ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); + ri.offset = cpu_to_je32(offset); + ri.csize = cpu_to_je32(cdatalen); + ri.dsize = cpu_to_je32(datalen); ri.compr = comprtype; - ri.node_crc = crc32(0, &ri, sizeof(ri)-8); - ri.data_crc = crc32(0, writebuf, cdatalen); + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); + ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen)); - new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL); + new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC); + + jffs2_free_comprbuf(comprbuf, writebuf); if (IS_ERR(new_fn)) { printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn)); @@ -663,12 +1230,8 @@ f->metadata = NULL; } } - if (comprbuf) kfree(comprbuf); - kunmap(pg); - /* XXX: Does the page get freed automatically? */ - /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */ - page_cache_release(pg); + jffs2_gc_release_page(c, pg_ptr, &pg); return ret; } diff -Nru a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c --- a/fs/jffs2/ioctl.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/ioctl.c Thu Dec 4 16:24:25 2003 @@ -1,37 +1,13 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: ioctl.c,v 1.5 2001/03/15 15:38:24 dwmw2 Exp $ + * $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $ * */ @@ -42,6 +18,6 @@ { /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which will include compression support etc. */ - return -EINVAL; + return -ENOTTY; } diff -Nru a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c --- a/fs/jffs2/malloc.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/malloc.c Thu Dec 4 16:24:25 2003 @@ -1,37 +1,13 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: malloc.c,v 1.16 2001/03/15 15:38:24 dwmw2 Exp $ + * $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $ * */ @@ -47,6 +23,9 @@ #define JFFS2_SLAB_POISON 0 #endif +// replace this by #define D3 (x) x for cache debugging +#define D3(x) + /* These are initialised to NULL in the kernel startup code. If you're porting to other operating systems, beware */ static kmem_cache_t *full_dnode_slab; @@ -57,57 +36,47 @@ static kmem_cache_t *node_frag_slab; static kmem_cache_t *inode_cache_slab; -void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) -{ - struct jffs2_tmp_dnode_info *next; - - while (tn) { - next = tn; - tn = tn->next; - jffs2_free_full_dnode(next->fn); - jffs2_free_tmp_dnode_info(next); - } -} - -void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) -{ - struct jffs2_full_dirent *next; - - while (fd) { - next = fd->next; - jffs2_free_full_dirent(fd); - fd = next; - } -} - int __init jffs2_create_slab_caches(void) { - full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL); + full_dnode_slab = kmem_cache_create("jffs2_full_dnode", + sizeof(struct jffs2_full_dnode), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!full_dnode_slab) goto err; - raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), 0, JFFS2_SLAB_POISON, NULL, NULL); + raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", + sizeof(struct jffs2_raw_dirent), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!raw_dirent_slab) goto err; - raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), 0, JFFS2_SLAB_POISON, NULL, NULL); + raw_inode_slab = kmem_cache_create("jffs2_raw_inode", + sizeof(struct jffs2_raw_inode), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!raw_inode_slab) goto err; - tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), 0, JFFS2_SLAB_POISON, NULL, NULL); + tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", + sizeof(struct jffs2_tmp_dnode_info), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!tmp_dnode_info_slab) goto err; - raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), 0, JFFS2_SLAB_POISON, NULL, NULL); + raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", + sizeof(struct jffs2_raw_node_ref), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!raw_node_ref_slab) goto err; - node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), 0, JFFS2_SLAB_POISON, NULL, NULL); + node_frag_slab = kmem_cache_create("jffs2_node_frag", + sizeof(struct jffs2_node_frag), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (!node_frag_slab) goto err; - inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL); - + inode_cache_slab = kmem_cache_create("jffs2_inode_cache", + sizeof(struct jffs2_inode_cache), + 0, JFFS2_SLAB_POISON, NULL, NULL); if (inode_cache_slab) return 0; err: @@ -131,7 +100,6 @@ kmem_cache_destroy(node_frag_slab); if(inode_cache_slab) kmem_cache_destroy(inode_cache_slab); - } struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) @@ -146,75 +114,92 @@ struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { - void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); return ret; } void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { + D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); kmem_cache_free(full_dnode_slab, x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { - return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); + return ret; } void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { + D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); kmem_cache_free(raw_dirent_slab, x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { - return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); + return ret; } void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { + D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); kmem_cache_free(raw_inode_slab, x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { - return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); + return ret; } void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { + D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); kmem_cache_free(tmp_dnode_info_slab, x); } struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) { - return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); + return ret; } void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { + D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); kmem_cache_free(raw_node_ref_slab, x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { - return kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); + return ret; } void jffs2_free_node_frag(struct jffs2_node_frag *x) { + D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); kmem_cache_free(node_frag_slab, x); } struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); - D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); + D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); return ret; } void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { - D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x)); + D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); kmem_cache_free(inode_cache_slab, x); } diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c --- a/fs/jffs2/nodelist.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/nodelist.c Thu Dec 4 16:24:25 2003 @@ -1,44 +1,24 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001, 2002 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: nodelist.c,v 1.30.2.6 2003/02/24 21:49:33 dwmw2 Exp $ + * $Id: nodelist.c,v 1.86 2003/10/31 15:37:51 dwmw2 Exp $ * */ #include -#include +#include #include #include +#include +#include +#include +#include #include "nodelist.h" void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) @@ -78,7 +58,7 @@ /* Put a new tmp_dnode_info into the list, keeping the list in order of increasing version */ -void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) +static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) { struct jffs2_tmp_dnode_info **prev = list; @@ -89,13 +69,37 @@ *prev = tn; } +static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) +{ + struct jffs2_tmp_dnode_info *next; + + while (tn) { + next = tn; + tn = tn->next; + jffs2_free_full_dnode(next->fn); + jffs2_free_tmp_dnode_info(next); + } +} + +static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) +{ + struct jffs2_full_dirent *next; + + while (fd) { + next = fd->next; + jffs2_free_full_dirent(fd); + fd = next; + } +} + + /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated with this ino, returning the former in order of version */ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, - __u32 *highest_version, __u32 *latest_mctime, - __u32 *mctime_ver) + uint32_t *highest_version, uint32_t *latest_mctime, + uint32_t *mctime_ver) { struct jffs2_raw_node_ref *ref = f->inocache->nodes; struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; @@ -109,43 +113,71 @@ D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino)); if (!f->inocache->nodes) { - printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino); + printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino); } + + spin_lock(&c->erase_completion_lock); + for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) { /* Work out whether it's a data node or a dirent node */ - if (ref->flash_offset & 1) { + if (ref_obsolete(ref)) { /* FIXME: On NAND flash we may need to read these */ - D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3)); + D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); continue; } - err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node); + /* We can hold a pointer to a non-obsolete node without the spinlock, + but _obsolete_ nodes may disappear at any time, if the block + they're in gets erased */ + spin_unlock(&c->erase_completion_lock); + + cond_resched(); + + /* FIXME: point() */ + err = jffs2_flash_read(c, (ref_offset(ref)), + min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), + &retlen, (void *)&node); if (err) { - printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3); + printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); goto free_out; } /* Check we've managed to read at least the common node header */ - if (retlen < min(ref->totlen, sizeof(node.u))) { + if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) { printk(KERN_WARNING "short read in get_inode_nodes()\n"); err = -EIO; goto free_out; } - switch (node.u.nodetype) { + switch (je16_to_cpu(node.u.nodetype)) { case JFFS2_NODETYPE_DIRENT: - D1(printk(KERN_DEBUG "Node at %08x is a dirent node\n", ref->flash_offset &~3)); + D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); + if (ref_flags(ref) == REF_UNCHECKED) { + printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref)); + BUG(); + } if (retlen < sizeof(node.d)) { printk(KERN_WARNING "short read in get_inode_nodes()\n"); err = -EIO; goto free_out; } - if (node.d.version > *highest_version) - *highest_version = node.d.version; - if (ref->flash_offset & 1) { - /* Obsoleted */ + /* sanity check */ + if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", + ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); continue; } + if (je32_to_cpu(node.d.version) > *highest_version) + *highest_version = je32_to_cpu(node.d.version); + if (ref_obsolete(ref)) { + /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ + printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n", + ref_offset(ref)); + BUG(); + } + fd = jffs2_alloc_full_dirent(node.d.nsize+1); if (!fd) { err = -ENOMEM; @@ -153,29 +185,30 @@ } memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1); fd->raw = ref; - fd->version = node.d.version; - fd->ino = node.d.ino; + fd->version = je32_to_cpu(node.d.version); + fd->ino = je32_to_cpu(node.d.ino); fd->type = node.d.type; /* Pick out the mctime of the latest dirent */ if(fd->version > *mctime_ver) { *mctime_ver = fd->version; - *latest_mctime = node.d.mctime; + *latest_mctime = je32_to_cpu(node.d.mctime); } /* memcpy as much of the name as possible from the raw dirent we've already read from the flash */ if (retlen > sizeof(struct jffs2_raw_dirent)) - memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); + memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); /* Do we need to copy any more of the name directly from the flash? */ if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { + /* FIXME: point() */ int already = retlen - sizeof(struct jffs2_raw_dirent); - err = c->mtd->read(c->mtd, (ref->flash_offset & ~3) + retlen, + err = jffs2_flash_read(c, (ref_offset(ref)) + retlen, node.d.nsize - already, &retlen, &fd->name[already]); if (!err && retlen != node.d.nsize - already) err = -EIO; @@ -196,21 +229,126 @@ break; case JFFS2_NODETYPE_INODE: - D1(printk(KERN_DEBUG "Node at %08x is a data node\n", ref->flash_offset &~3)); + D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); if (retlen < sizeof(node.i)) { printk(KERN_WARNING "read too short for dnode\n"); err = -EIO; goto free_out; } - if (node.i.version > *highest_version) - *highest_version = node.i.version; - D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.i.version, *highest_version)); - - if (ref->flash_offset & 1) { - D1(printk(KERN_DEBUG "obsoleted\n")); - /* Obsoleted */ - continue; + if (je32_to_cpu(node.i.version) > *highest_version) + *highest_version = je32_to_cpu(node.i.version); + D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version)); + + if (ref_obsolete(ref)) { + /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ + printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n", + ref_offset(ref)); + BUG(); + } + + /* If we've never checked the CRCs on this node, check them now. */ + if (ref_flags(ref) == REF_UNCHECKED) { + uint32_t crc, len; + struct jffs2_eraseblock *jeb; + + crc = crc32(0, &node, sizeof(node.i)-8); + if (crc != je32_to_cpu(node.i.node_crc)) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } + + /* sanity checks */ + if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || + PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", + ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), + je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), + je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } + + if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { + unsigned char *buf=NULL; + uint32_t pointed = 0; +#ifndef __ECOS + if (c->mtd->point) { + err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, &buf); + if (!err && retlen < je32_to_cpu(node.i.csize)) { + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); + } else if (err){ + D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); + } else + pointed = 1; /* succefully pointed to device */ + } +#endif + if(!pointed){ + buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, buf); + if (!err && retlen != je32_to_cpu(node.i.csize)) + err = -EIO; + if (err) { + kfree(buf); + return err; + } + } + crc = crc32(0, buf, je32_to_cpu(node.i.csize)); + if(!pointed) + kfree(buf); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); +#endif + + if (crc != je32_to_cpu(node.i.data_crc)) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } + + } + + /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + + If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) + when the overlapping node(s) get added to the tree anyway. + */ + if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_PRISTINE; + } else { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_NORMAL; + } + spin_unlock(&c->erase_completion_lock); } + tn = jffs2_alloc_tmp_dnode_info(); if (!tn) { D1(printk(KERN_DEBUG "alloc tn failed\n")); @@ -225,36 +363,76 @@ jffs2_free_tmp_dnode_info(tn); goto free_out; } - tn->version = node.i.version; - tn->fn->ofs = node.i.offset; + tn->version = je32_to_cpu(node.i.version); + tn->fn->ofs = je32_to_cpu(node.i.offset); /* There was a bug where we wrote hole nodes out with csize/dsize swapped. Deal with it */ - if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize) - tn->fn->size = node.i.csize; + if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize)) + tn->fn->size = je32_to_cpu(node.i.csize); else // normal case... - tn->fn->size = node.i.dsize; + tn->fn->size = je32_to_cpu(node.i.dsize); tn->fn->raw = ref; - D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize)); + D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", + ref_offset(ref), je32_to_cpu(node.i.version), + je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize))); jffs2_add_tn_to_list(tn, &ret_tn); break; default: - switch(node.u.nodetype & JFFS2_COMPAT_MASK) { + if (ref_flags(ref) == REF_UNCHECKED) { + struct jffs2_eraseblock *jeb; + uint32_t len; + + printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n", + je16_to_cpu(node.u.nodetype), ref_offset(ref)); + + /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + + mark_ref_normal(ref); + spin_unlock(&c->erase_completion_lock); + } + node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); + if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { + /* Hmmm. This should have been caught at scan time. */ + printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n", + ref_offset(ref)); + printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n", + je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen), + je32_to_cpu(node.u.hdr_crc)); + jffs2_mark_node_obsolete(c, ref); + } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) { case JFFS2_FEATURE_INCOMPAT: - printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); + printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); + /* EEP */ + BUG(); break; case JFFS2_FEATURE_ROCOMPAT: - printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); + printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); + if (!(c->flags & JFFS2_SB_FLAG_RO)) + BUG(); break; case JFFS2_FEATURE_RWCOMPAT_COPY: - printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); + printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); break; case JFFS2_FEATURE_RWCOMPAT_DELETE: - printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); + printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); + jffs2_mark_node_obsolete(c, ref); break; } + } + spin_lock(&c->erase_completion_lock); + } + spin_unlock(&c->erase_completion_lock); *tnp = ret_tn; *fdp = ret_fd; @@ -266,19 +444,30 @@ return err; } +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) +{ + spin_lock(&c->inocache_lock); + ic->state = state; + wake_up(&c->inocache_wq); + spin_unlock(&c->inocache_lock); +} + +/* During mount, this needs no locking. During normal operation, its + callers want to do other stuff while still holding the inocache_lock. + Rather than introducing special case get_ino_cache functions or + callbacks, we just let the caller do the locking itself. */ + struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ret; D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); - spin_lock (&c->inocache_lock); + ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; while (ret && ret->ino < ino) { ret = ret->next; } - - spin_unlock(&c->inocache_lock); - + if (ret && ret->ino != ino) ret = NULL; @@ -299,6 +488,7 @@ } new->next = *prev; *prev = new; + spin_unlock(&c->inocache_lock); } @@ -316,6 +506,7 @@ if ((*prev) == old) { *prev = old->next; } + spin_unlock(&c->inocache_lock); } @@ -352,3 +543,128 @@ } } +struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) +{ + /* The common case in lookup is that there will be a node + which precisely matches. So we go looking for that first */ + struct rb_node *next; + struct jffs2_node_frag *prev = NULL; + struct jffs2_node_frag *frag = NULL; + + D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset)); + + next = fragtree->rb_node; + + while(next) { + frag = rb_entry(next, struct jffs2_node_frag, rb); + + D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n", + frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right)); + if (frag->ofs + frag->size <= offset) { + D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n", + frag->ofs, frag->ofs+frag->size)); + /* Remember the closest smaller match on the way down */ + if (!prev || frag->ofs > prev->ofs) + prev = frag; + next = frag->rb.rb_right; + } else if (frag->ofs > offset) { + D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n", + frag->ofs, frag->ofs+frag->size)); + next = frag->rb.rb_left; + } else { + D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n", + frag->ofs, frag->ofs+frag->size)); + return frag; + } + } + + /* Exact match not found. Go back up looking at each parent, + and return the closest smaller one */ + + if (prev) + D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n", + prev->ofs, prev->ofs+prev->size)); + else + D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n")); + + return prev; +} + +/* Pass 'c' argument to indicate that nodes should be marked obsolete as + they're killed. */ +void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) +{ + struct jffs2_node_frag *frag; + struct jffs2_node_frag *parent; + + if (!root->rb_node) + return; + + frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); + + while(frag) { + if (frag->rb.rb_left) { + D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", + frag, frag->ofs, frag->ofs+frag->size)); + frag = frag_left(frag); + continue; + } + if (frag->rb.rb_right) { + D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", + frag, frag->ofs, frag->ofs+frag->size)); + frag = frag_right(frag); + continue; + } + + D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n", + frag->ofs, frag->ofs+frag->size, frag->node, + frag->node?frag->node->frags:0)); + + if (frag->node && !(--frag->node->frags)) { + /* Not a hole, and it's the final remaining frag + of this node. Free the node */ + if (c) + jffs2_mark_node_obsolete(c, frag->node->raw); + + jffs2_free_full_dnode(frag->node); + } + parent = frag_parent(frag); + if (parent) { + if (frag_left(parent) == frag) + parent->rb.rb_left = NULL; + else + parent->rb.rb_right = NULL; + } + + jffs2_free_node_frag(frag); + frag = parent; + + cond_resched(); + } +} + +void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) +{ + struct rb_node *parent = &base->rb; + struct rb_node **link = &parent; + + D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, + newfrag->ofs, newfrag->ofs+newfrag->size, base)); + + while (*link) { + parent = *link; + base = rb_entry(parent, struct jffs2_node_frag, rb); + + D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); + if (newfrag->ofs > base->ofs) + link = &base->rb.rb_right; + else if (newfrag->ofs < base->ofs) + link = &base->rb.rb_left; + else { + printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); + BUG(); + } + } + + rb_link_node(&newfrag->rb, &base->rb, link); +} diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h --- a/fs/jffs2/nodelist.h Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/nodelist.h Thu Dec 4 16:24:25 2003 @@ -1,48 +1,35 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: nodelist.h,v 1.46.2.4 2003/02/24 21:49:33 dwmw2 Exp $ + * $Id: nodelist.h,v 1.115 2003/11/26 15:30:58 dwmw2 Exp $ * */ +#ifndef __JFFS2_NODELIST_H__ +#define __JFFS2_NODELIST_H__ + #include #include - +#include +#include #include #include +#ifdef __ECOS +#include "os-ecos.h" +#else +#include /* For min/max in older kernels */ +#include "os-linux.h" +#endif + #ifndef CONFIG_JFFS2_FS_DEBUG -#define CONFIG_JFFS2_FS_DEBUG 2 +#define CONFIG_JFFS2_FS_DEBUG 1 #endif #if CONFIG_JFFS2_FS_DEBUG > 0 @@ -71,17 +58,21 @@ for this inode instead. The inode_cache will have NULL in the first word so you know when you've got there :) */ struct jffs2_raw_node_ref *next_phys; - // __u32 ino; - __u32 flash_offset; - __u32 totlen; -// __u16 nodetype; - + uint32_t flash_offset; + uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ +}; + /* flash_offset & 3 always has to be zero, because nodes are always aligned at 4 bytes. So we have a couple of extra bits - to play with. So we set the least significant bit to 1 to - signify that the node is obsoleted by later nodes. - */ -}; + to play with, which indicate the node's status; see below: */ +#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ +#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */ +#define REF_PRISTINE 2 /* Completely clean. GC without looking */ +#define REF_NORMAL 3 /* Possibly overlapped. Read the page and write again on GC */ +#define ref_flags(ref) ((ref)->flash_offset & 3) +#define ref_offset(ref) ((ref)->flash_offset & ~3) +#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) +#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) /* Used for keeping track of deletion nodes &c, which can only be marked @@ -101,19 +92,35 @@ a pointer to the first physical node which is part of this inode, too. */ struct jffs2_inode_cache { - struct jffs2_scan_info *scan; /* Used during scan to hold - temporary lists of nodes, and later must be set to + struct jffs2_full_dirent *scan_dents; /* Used during scan to hold + temporary lists of dirents, and later must be set to NULL to mark the end of the raw_node_ref->next_in_ino chain. */ struct jffs2_inode_cache *next; struct jffs2_raw_node_ref *nodes; - __u32 ino; + uint32_t ino; int nlink; + int state; }; +/* Inode states for 'state' above. We need the 'GC' state to prevent + someone from doing a read_inode() while we're moving a 'REF_PRISTINE' + node without going through all the iget() nonsense */ +#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */ +#define INO_STATE_CHECKING 1 /* CRC checks in progress */ +#define INO_STATE_PRESENT 2 /* In core */ +#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ +#define INO_STATE_GC 4 /* GCing a 'pristine' node */ +#define INO_STATE_READING 5 /* In read_inode() */ + +#define INOCACHE_HASHSIZE 128 + struct jffs2_scan_info { struct jffs2_full_dirent *dents; struct jffs2_tmp_dnode_info *tmpnodes; + /* Latest i_size info */ + uint32_t version; + uint32_t isize; }; /* Larger representation of a raw node, kept in-core only when the @@ -123,9 +130,9 @@ struct jffs2_full_dnode { struct jffs2_raw_node_ref *raw; - __u32 ofs; /* Don't really need this, but optimisation */ - __u32 size; - __u32 frags; /* Number of fragments which currently refer + uint32_t ofs; /* Don't really need this, but optimisation */ + uint32_t size; + uint32_t frags; /* Number of fragments which currently refer to this node. When this reaches zero, the node is obsolete. */ @@ -140,15 +147,15 @@ { struct jffs2_tmp_dnode_info *next; struct jffs2_full_dnode *fn; - __u32 version; + uint32_t version; }; struct jffs2_full_dirent { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *next; - __u32 version; - __u32 ino; /* == zero for unlink */ + uint32_t version; + uint32_t ino; /* == zero for unlink */ unsigned int nhash; unsigned char type; unsigned char name[0]; @@ -159,21 +166,23 @@ */ struct jffs2_node_frag { - struct jffs2_node_frag *next; + struct rb_node rb; struct jffs2_full_dnode *node; /* NULL for holes */ - __u32 size; - __u32 ofs; /* Don't really need this, but optimisation */ + uint32_t size; + uint32_t ofs; /* Don't really need this, but optimisation */ }; struct jffs2_eraseblock { struct list_head list; int bad_count; - __u32 offset; /* of this block in the MTD */ + uint32_t offset; /* of this block in the MTD */ - __u32 used_size; - __u32 dirty_size; - __u32 free_size; /* Note that sector_size - free_size + uint32_t unchecked_size; + uint32_t used_size; + uint32_t dirty_size; + uint32_t wasted_size; + uint32_t free_size; /* Note that sector_size - free_size is the address of the first free space */ struct jffs2_raw_node_ref *first_node; struct jffs2_raw_node_ref *last_node; @@ -190,94 +199,215 @@ }; #define ACCT_SANITY_CHECK(c, jeb) do { \ - if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \ - printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \ - printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \ - jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \ + struct jffs2_eraseblock *___j = jeb; \ + if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \ + printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \ + printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \ + ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \ BUG(); \ } \ - if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \ + if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \ printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \ - printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \ - c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \ + printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \ + c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \ BUG(); \ } \ } while(0) +static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb) +{ + struct jffs2_raw_node_ref *ref; + int i=0; + + printk(KERN_NOTICE); + for (ref = jeb->first_node; ref; ref = ref->next_phys) { + printk("%08x->", ref_offset(ref)); + if (++i == 8) { + i = 0; + printk("\n" KERN_NOTICE); + } + } + printk("\n"); +} + + #define ACCT_PARANOIA_CHECK(jeb) do { \ - __u32 my_used_size = 0; \ + uint32_t my_used_size = 0; \ + uint32_t my_unchecked_size = 0; \ struct jffs2_raw_node_ref *ref2 = jeb->first_node; \ while (ref2) { \ - if (!(ref2->flash_offset & 1)) \ - my_used_size += ref2->totlen; \ + if (unlikely(ref2->flash_offset < jeb->offset || \ + ref2->flash_offset > jeb->offset + c->sector_size)) { \ + printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \ + ref_offset(ref2), jeb->offset); \ + paranoia_failed_dump(jeb); \ + BUG(); \ + } \ + if (ref_flags(ref2) == REF_UNCHECKED) \ + my_unchecked_size += ref_totlen(c, jeb, ref2); \ + else if (!ref_obsolete(ref2)) \ + my_used_size += ref_totlen(c, jeb, ref2); \ + if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ + printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ + ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ + jeb->last_node, ref_offset(jeb->last_node)); \ + paranoia_failed_dump(jeb); \ + BUG(); \ + } \ ref2 = ref2->next_phys; \ } \ if (my_used_size != jeb->used_size) { \ printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \ BUG(); \ } \ + if (my_unchecked_size != jeb->unchecked_size) { \ + printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \ + BUG(); \ + } \ } while(0) +/* Calculate totlen from surrounding nodes or eraseblock */ +static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref) +{ + uint32_t ref_end; + + if (ref->next_phys) + ref_end = ref_offset(ref->next_phys); + else { + if (!jeb) + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + + /* Last node in block. Use free_space */ + BUG_ON(ref != jeb->last_node); + ref_end = jeb->offset + c->sector_size - jeb->free_size; + } + return ref_end - ref_offset(ref); +} + +static inline uint32_t ref_totlen(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref) +{ + uint32_t ret; + + D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { + printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", + jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); + BUG(); + }) + +#if 1 + ret = ref->__totlen; +#else + /* This doesn't actually work yet */ + ret = __ref_totlen(c, jeb, ref); + if (ret != ref->__totlen) { + printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", + ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, + ret, ref->__totlen); + if (!jeb) + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + paranoia_failed_dump(jeb); + BUG(); + } +#endif + return ret; +} + + #define ALLOC_NORMAL 0 /* Normal allocation */ #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ +#define ALLOC_NORETRY 3 /* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */ -#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */ -#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */ -#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */ -#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */ -#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */ -#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */ +/* How much dirty space before it goes on the very_dirty_list */ +#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) +/* check if dirty space is more than 255 Byte */ +#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) #define PAD(x) (((x)+3)&~3) -static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw) +static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) { while(raw->next_in_ino) { raw = raw->next_in_ino; } - return ((struct jffs2_inode_cache *)raw)->ino; + return ((struct jffs2_inode_cache *)raw); } +static inline struct jffs2_node_frag *frag_first(struct rb_root *root) +{ + struct rb_node *node = root->rb_node; + + if (!node) + return NULL; + while(node->rb_left) + node = node->rb_left; + return rb_entry(node, struct jffs2_node_frag, rb); +} +#define rb_parent(rb) ((rb)->rb_parent) +#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) +#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) +#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb) +#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb) +#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) +#define frag_erase(frag, list) rb_erase(&frag->rb, list); + /* nodelist.c */ D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)); void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); -void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list); int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, - __u32 *highest_version, __u32 *latest_mctime, - __u32 *mctime_ver); + uint32_t *highest_version, uint32_t *latest_mctime, + uint32_t *mctime_ver); +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_free_ino_caches(struct jffs2_sb_info *c); void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); +struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset); +void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete); +void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base); +struct rb_node *rb_next(struct rb_node *); +struct rb_node *rb_prev(struct rb_node *); +void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); /* nodemgmt.c */ -int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio); -int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len); -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty); +int jffs2_thread_should_wake(struct jffs2_sb_info *c); +int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); +int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); void jffs2_complete_reservation(struct jffs2_sb_info *c); void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); +void jffs2_dump_block_lists(struct jffs2_sb_info *c); /* write.c */ -struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri); -struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen); -struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen); +int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri); + +struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode); +struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode); +int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct jffs2_raw_inode *ri, unsigned char *buf, + uint32_t offset, uint32_t writelen, uint32_t *retlen); +int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen); +int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f); +int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen); + /* readinode.c */ -void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size); -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn); +void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); -void jffs2_read_inode (struct inode *); -void jffs2_clear_inode (struct inode *); +int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + uint32_t ino, struct jffs2_raw_inode *latest_node); +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); +void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* malloc.c */ -void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn); -void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd); - int jffs2_create_slab_caches(void); void jffs2_destroy_slab_caches(void); @@ -301,54 +431,41 @@ /* gc.c */ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c); -/* background.c */ -int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); -void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); -void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); - -/* dir.c */ -extern struct file_operations jffs2_dir_operations; -extern struct inode_operations jffs2_dir_inode_operations; - -/* file.c */ -extern struct file_operations jffs2_file_operations; -extern struct inode_operations jffs2_file_inode_operations; -extern struct address_space_operations jffs2_file_address_operations; -int jffs2_null_fsync(struct file *, struct dentry *, int); -int jffs2_setattr (struct dentry *dentry, struct iattr *iattr); -int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg); -int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); -int jffs2_readpage (struct file *, struct page *); -int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned); -int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned); - -/* ioctl.c */ -int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); - /* read.c */ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len); +int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + unsigned char *buf, uint32_t offset, uint32_t len); +char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* compr.c */ -unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, - __u32 *datalen, __u32 *cdatalen); +unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, + uint32_t *datalen, uint32_t *cdatalen); +void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, - unsigned char *data_out, __u32 cdatalen, __u32 datalen); + unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); /* scan.c */ int jffs2_scan_medium(struct jffs2_sb_info *c); +void jffs2_rotate_lists(struct jffs2_sb_info *c); /* build.c */ -int jffs2_build_filesystem(struct jffs2_sb_info *c); - -/* symlink.c */ -extern struct inode_operations jffs2_symlink_inode_operations; +int jffs2_do_mount_fs(struct jffs2_sb_info *c); /* erase.c */ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -void jffs2_erase_pending_blocks(struct jffs2_sb_info *c); -void jffs2_mark_erased_blocks(struct jffs2_sb_info *c); -void jffs2_erase_pending_trigger(struct jffs2_sb_info *c); +void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); + +#ifdef CONFIG_JFFS2_FS_NAND +/* wbuf.c */ +int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); +int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); +int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +#endif /* compr_zlib.c */ int jffs2_zlib_init(void); void jffs2_zlib_exit(void); + +#endif /* __JFFS2_NODELIST_H__ */ diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c --- a/fs/jffs2/nodemgmt.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/nodemgmt.c Thu Dec 4 16:24:25 2003 @@ -1,45 +1,21 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: nodemgmt.c,v 1.45.2.1 2002/02/23 14:13:34 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $ * */ #include #include -#include #include -#include +#include +#include /* For cond_resched() */ #include "nodelist.h" /** @@ -62,53 +38,95 @@ * for the requested allocation. */ -static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len); +static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); -int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio) +int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) { int ret = -EAGAIN; - int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE; + int blocksneeded = c->resv_blocks_write; /* align it */ minsize = PAD(minsize); - if (prio == ALLOC_DELETION) - blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION; - D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); down(&c->alloc_sem); D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); - /* this needs a little more thought */ + /* this needs a little more thought (true :)) */ while(ret == -EAGAIN) { while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { int ret; + uint32_t dirty, avail; - up(&c->alloc_sem); - if (c->dirty_size < c->sector_size) { - D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size)); - spin_unlock_bh(&c->erase_completion_lock); + /* calculate real dirty size + * dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + * We add unchecked_size here, as we hopefully will find some space to use. + * This will affect the sum only once, as gc first finishes checking + * of nodes. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; + if (dirty < c->nospc_dirty_size) { + if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { + printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"); + break; + } + D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", + dirty, c->unchecked_size, c->sector_size)); + + spin_unlock(&c->erase_completion_lock); + up(&c->alloc_sem); + return -ENOSPC; + } + + /* Calc possibly available space. Possibly available means that we + * don't know, if unchecked size contains obsoleted nodes, which could give us some + * more usable space. This will affect the sum only once, as gc first finishes checking + * of nodes. + + Return -ENOSPC, if the maximum possibly available space is less or equal than + * blocksneeded * sector_size. + * This blocks endless gc looping on a filesystem, which is nearly full, even if + * the check above passes. + */ + avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; + if ( (avail / c->sector_size) <= blocksneeded) { + if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { + printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"); + break; + } + + D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", + avail, blocksneeded * c->sector_size)); + spin_unlock(&c->erase_completion_lock); + up(&c->alloc_sem); return -ENOSPC; } - D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", - c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, - c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); - spin_unlock_bh(&c->erase_completion_lock); + + up(&c->alloc_sem); + + D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", + c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, + c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); + spin_unlock(&c->erase_completion_lock); ret = jffs2_garbage_collect_pass(c); if (ret) return ret; - if (current->need_resched) - schedule(); + cond_resched(); if (signal_pending(current)) return -EINTR; down(&c->alloc_sem); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } ret = jffs2_do_reserve_space(c, minsize, ofs, len); @@ -116,45 +134,72 @@ D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); if (ret) up(&c->alloc_sem); return ret; } -int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len) +int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) { int ret = -EAGAIN; minsize = PAD(minsize); D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); while(ret == -EAGAIN) { ret = jffs2_do_reserve_space(c, minsize, ofs, len); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return ret; } /* Called with alloc sem _and_ erase_completion_lock */ -static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len) +static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) { struct jffs2_eraseblock *jeb = c->nextblock; restart: if (jeb && minsize > jeb->free_size) { /* Skip the end of this block and file it as having some dirty space */ - c->dirty_size += jeb->free_size; + /* If there's a pending write to it, flush now */ + if (jffs2_wbuf_dirty(c)) { + spin_unlock(&c->erase_completion_lock); + D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); + jffs2_flush_wbuf_pad(c); + spin_lock(&c->erase_completion_lock); + jeb = c->nextblock; + goto restart; + } + c->wasted_size += jeb->free_size; c->free_size -= jeb->free_size; - jeb->dirty_size += jeb->free_size; + jeb->wasted_size += jeb->free_size; jeb->free_size = 0; - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + + /* Check, if we have a dirty block now, or if it was dirty already */ + if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { + c->dirty_size += jeb->wasted_size; + c->wasted_size -= jeb->wasted_size; + jeb->dirty_size += jeb->wasted_size; + jeb->wasted_size = 0; + if (VERYDIRTY(c, jeb->dirty_size)) { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + list_add_tail(&jeb->list, &c->very_dirty_list); + } else { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + list_add_tail(&jeb->list, &c->dirty_list); + } + } else { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - list_add_tail(&jeb->list, &c->dirty_list); + list_add_tail(&jeb->list, &c->clean_list); + } c->nextblock = jeb = NULL; } @@ -164,33 +209,44 @@ if (list_empty(&c->free_list)) { - DECLARE_WAITQUEUE(wait, current); - + if (!c->nr_erasing_blocks && + !list_empty(&c->erasable_list)) { + struct jffs2_eraseblock *ejeb; + + ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); + list_del(&ejeb->list); + list_add_tail(&ejeb->list, &c->erase_pending_list); + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", + ejeb->offset)); + } + + if (!c->nr_erasing_blocks && + !list_empty(&c->erasable_pending_wbuf_list)) { + D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); + /* c->nextblock is NULL, no update to c->nextblock allowed */ + spin_unlock(&c->erase_completion_lock); + jffs2_flush_wbuf_pad(c); + spin_lock(&c->erase_completion_lock); + /* Have another go. It'll be on the erasable_list now */ + return -EAGAIN; + } + if (!c->nr_erasing_blocks) { -// if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) { /* Ouch. We're in GC, or we wouldn't have got here. And there's no space left. At all. */ - printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", - c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); + printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", + c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", + list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); return -ENOSPC; } - /* Make sure this can't deadlock. Someone has to start the erases - of erase_pending blocks */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&c->erase_wait, &wait); - D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", - c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no")); - if (!list_empty(&c->erase_pending_list)) { - D1(printk(KERN_DEBUG "Triggering pending erases\n")); - jffs2_erase_pending_trigger(c); - } - spin_unlock_bh(&c->erase_completion_lock); - schedule(); - remove_wait_queue(&c->erase_wait, &wait); - spin_lock_bh(&c->erase_completion_lock); - if (signal_pending(current)) { - return -EINTR; - } + + spin_unlock(&c->erase_completion_lock); + /* Don't wait for it; just erase one right now */ + jffs2_erase_pending_blocks(c, 1); + spin_lock(&c->erase_completion_lock); + /* An erase may have failed, decreasing the amount of free space available. So we must restart from the beginning */ @@ -201,7 +257,8 @@ list_del(next); c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list); c->nr_free_blocks--; - if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) { + + if (jeb->free_size != c->sector_size - c->cleanmarker_size) { printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); goto restart; } @@ -210,6 +267,20 @@ enough space */ *ofs = jeb->offset + (c->sector_size - jeb->free_size); *len = jeb->free_size; + + if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && + !jeb->first_node->next_in_ino) { + /* Only node in it beforehand was a CLEANMARKER node (we think). + So mark it obsolete now that there's going to be another node + in the block. This will reduce used_size to zero but We've + already set c->nextblock so that jffs2_mark_node_obsolete() + won't try to refile it to the dirty_list. + */ + spin_unlock(&c->erase_completion_lock); + jffs2_mark_node_obsolete(c, jeb->first_node); + spin_lock(&c->erase_completion_lock); + } + D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs)); return 0; } @@ -217,9 +288,9 @@ /** * jffs2_add_physical_node_ref - add a physical node reference to the list * @c: superblock info - * @ofs: physical location of this physical node + * @new: new node reference to add * @len: length of this physical node - * @ino: inode number with which this physical node is associated + * @dirty: dirty flag for new node * * Should only be used to report nodes for which space has been allocated * by jffs2_reserve_space. @@ -227,47 +298,58 @@ * Must be called with the alloc_sem held. */ -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty) +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) { struct jffs2_eraseblock *jeb; + uint32_t len; + + jeb = &c->blocks[new->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, new); - len = PAD(len); - jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size]; - D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len)); + D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 - if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) { + if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { printk(KERN_WARNING "argh. node added in wrong place\n"); jffs2_free_raw_node_ref(new); return -EINVAL; } #endif + spin_lock(&c->erase_completion_lock); + if (!jeb->first_node) jeb->first_node = new; if (jeb->last_node) jeb->last_node->next_phys = new; jeb->last_node = new; - spin_lock_bh(&c->erase_completion_lock); jeb->free_size -= len; c->free_size -= len; - if (dirty) { - new->flash_offset |= 1; + if (ref_obsolete(new)) { jeb->dirty_size += len; c->dirty_size += len; } else { jeb->used_size += len; c->used_size += len; } - spin_unlock_bh(&c->erase_completion_lock); + if (!jeb->free_size && !jeb->dirty_size) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + if (jffs2_wbuf_dirty(c)) { + /* Flush the last write in the block if it's outstanding */ + spin_unlock(&c->erase_completion_lock); + jffs2_flush_wbuf_pad(c); + spin_lock(&c->erase_completion_lock); + } + list_add_tail(&jeb->list, &c->clean_list); c->nextblock = NULL; } ACCT_SANITY_CHECK(c,jeb); - ACCT_PARANOIA_CHECK(jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + spin_unlock(&c->erase_completion_lock); return 0; } @@ -280,20 +362,34 @@ up(&c->alloc_sem); } +static inline int on_list(struct list_head *obj, struct list_head *head) +{ + struct list_head *this; + + list_for_each(this, head) { + if (this == obj) { + D1(printk("%p is on list at %p\n", obj, head)); + return 1; + + } + } + return 0; +} + void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) { struct jffs2_eraseblock *jeb; int blocknr; struct jffs2_unknown_node n; - int ret; - ssize_t retlen; + int ret, addedsize; + size_t retlen; if(!ref) { printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); return; } - if (ref->flash_offset & 1) { - D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3)); + if (ref_obsolete(ref)) { + D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref))); return; } blocknr = ref->flash_offset / c->sector_size; @@ -302,22 +398,63 @@ BUG(); } jeb = &c->blocks[blocknr]; - if (jeb->used_size < ref->totlen) { - printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", - ref->totlen, blocknr, ref->flash_offset, jeb->used_size); - BUG(); - } - spin_lock_bh(&c->erase_completion_lock); - jeb->used_size -= ref->totlen; - jeb->dirty_size += ref->totlen; - c->used_size -= ref->totlen; - c->dirty_size += ref->totlen; - ref->flash_offset |= 1; + spin_lock(&c->erase_completion_lock); + + if (ref_flags(ref) == REF_UNCHECKED) { + D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) { + printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", + ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); + BUG(); + }) + D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); + jeb->unchecked_size -= ref_totlen(c, jeb, ref); + c->unchecked_size -= ref_totlen(c, jeb, ref); + } else { + D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) { + printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", + ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); + BUG(); + }) + D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); + jeb->used_size -= ref_totlen(c, jeb, ref); + c->used_size -= ref_totlen(c, jeb, ref); + } + + // Take care, that wasted size is taken into concern + if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { + D1(printk("Dirtying\n")); + addedsize = ref_totlen(c, jeb, ref); + jeb->dirty_size += ref_totlen(c, jeb, ref); + c->dirty_size += ref_totlen(c, jeb, ref); + + /* Convert wasted space to dirty, if not a bad block */ + if (jeb->wasted_size) { + if (on_list(&jeb->list, &c->bad_used_list)) { + D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n", + jeb->offset)); + addedsize = 0; /* To fool the refiling code later */ + } else { + D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n", + jeb->wasted_size, jeb->offset)); + addedsize += jeb->wasted_size; + jeb->dirty_size += jeb->wasted_size; + c->dirty_size += jeb->wasted_size; + c->wasted_size -= jeb->wasted_size; + jeb->wasted_size = 0; + } + } + } else { + D1(printk("Wasting\n")); + addedsize = 0; + jeb->wasted_size += ref_totlen(c, jeb, ref); + c->wasted_size += ref_totlen(c, jeb, ref); + } + ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; ACCT_SANITY_CHECK(c, jeb); - ACCT_PARANOIA_CHECK(jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); if (c->flags & JFFS2_SB_FLAG_MOUNTING) { /* Mount in progress. Don't muck about with the block @@ -325,68 +462,280 @@ obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ obsolete, there was probably a reason for that. */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return; } + if (jeb == c->nextblock) { D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); - } else if (jeb == c->gcblock) { - D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); -#if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static - data and a few blocks free, and you just create new files and keep deleting/overwriting - them, then you'd keep erasing and reusing those blocks without ever moving stuff around. - So we leave completely obsoleted blocks on the dirty_list and let the GC delete them - when it finds them there. That way, we still get the 'once in a while, take a clean block' - to spread out the flash usage */ - } else if (!jeb->used_size) { - D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset)); - list_del(&jeb->list); - D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n")); - list_add_tail(&jeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); - // OFNI_BS_2SFFJ(c)->s_dirt = 1; + } else if (!jeb->used_size && !jeb->unchecked_size) { + if (jeb == c->gcblock) { + D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset)); + c->gcblock = NULL; + } else { + D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset)); + list_del(&jeb->list); + } + if (jffs2_wbuf_dirty(c)) { + D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); + list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); + } else { + if (jiffies & 127) { + /* Most of the time, we just erase it immediately. Otherwise we + spend ages scanning it on mount, etc. */ + D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n")); + list_add_tail(&jeb->list, &c->erase_pending_list); + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + } else { + /* Sometimes, however, we leave it elsewhere so it doesn't get + immediately reused, and we spread the load a bit. */ + D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); + list_add_tail(&jeb->list, &c->erasable_list); + } + } D1(printk(KERN_DEBUG "Done OK\n")); -#endif - } else if (jeb->dirty_size == ref->totlen) { + } else if (jeb == c->gcblock) { + D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); + } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); list_del(&jeb->list); D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); list_add_tail(&jeb->list, &c->dirty_list); - } - spin_unlock_bh(&c->erase_completion_lock); + } else if (VERYDIRTY(c, jeb->dirty_size) && + !VERYDIRTY(c, jeb->dirty_size - addedsize)) { + D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset)); + list_del(&jeb->list); + D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n")); + list_add_tail(&jeb->list, &c->very_dirty_list); + } else { + D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + } - if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM) + spin_unlock(&c->erase_completion_lock); + + if (!jffs2_can_mark_obsolete(c)) return; - if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) + if (jffs2_is_readonly(c)) return; - D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3)); - ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n); + D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); + ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); if (ret) { - printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); + printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); + printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } - if (PAD(n.totlen) != PAD(ref->totlen)) { - printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen); + if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) { + printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref)); return; } - if (!(n.nodetype & JFFS2_NODE_ACCURATE)) { - D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype)); + if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { + D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype))); return; } - n.nodetype &= ~JFFS2_NODE_ACCURATE; - ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n); + /* XXX FIXME: This is ugly now */ + n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); + ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); if (ret) { - printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); + printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); + printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } +} + +#if CONFIG_JFFS2_FS_DEBUG > 0 +void jffs2_dump_block_lists(struct jffs2_sb_info *c) +{ + + + printk(KERN_DEBUG "jffs2_dump_block_lists:\n"); + printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); + printk(KERN_DEBUG "used_size: %08x\n", c->used_size); + printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); + printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size); + printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size); + printk(KERN_DEBUG "free_size: %08x\n", c->free_size); + printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); + printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); + printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); + printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write); + + if (c->nextblock) { + printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size); + } else { + printk(KERN_DEBUG "nextblock: NULL\n"); + } + if (c->gcblock) { + printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); + } else { + printk(KERN_DEBUG "gcblock: NULL\n"); + } + if (list_empty(&c->clean_list)) { + printk(KERN_DEBUG "clean_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->clean_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + numblocks ++; + dirty += jeb->wasted_size; + printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks); + } + if (list_empty(&c->very_dirty_list)) { + printk(KERN_DEBUG "very_dirty_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->very_dirty_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + numblocks ++; + dirty += jeb->dirty_size; + printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", + numblocks, dirty, dirty / numblocks); + } + if (list_empty(&c->dirty_list)) { + printk(KERN_DEBUG "dirty_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->dirty_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + numblocks ++; + dirty += jeb->dirty_size; + printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", + numblocks, dirty, dirty / numblocks); + } + if (list_empty(&c->erasable_list)) { + printk(KERN_DEBUG "erasable_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasable_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->erasing_list)) { + printk(KERN_DEBUG "erasing_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasing_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->erase_pending_list)) { + printk(KERN_DEBUG "erase_pending_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erase_pending_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->erasable_pending_wbuf_list)) { + printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasable_pending_wbuf_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->free_list)) { + printk(KERN_DEBUG "free_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->free_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->bad_list)) { + printk(KERN_DEBUG "bad_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->bad_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } + if (list_empty(&c->bad_used_list)) { + printk(KERN_DEBUG "bad_used_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->bad_used_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); + } + } +} +#endif /* CONFIG_JFFS2_FS_DEBUG */ + +int jffs2_thread_should_wake(struct jffs2_sb_info *c) +{ + int ret = 0; + uint32_t dirty; + + if (c->unchecked_size) { + D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", + c->unchecked_size, c->checked_ino)); + return 1; + } + + /* dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; + + if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && + (dirty > c->nospc_dirty_size)) + ret = 1; + + D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", + c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); + + return ret; } diff -Nru a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h --- a/fs/jffs2/pushpull.h Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/pushpull.h Thu Dec 4 16:24:25 2003 @@ -1,42 +1,21 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001, 2002 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: pushpull.h,v 1.5 2001/09/23 10:04:15 rmk Exp $ + * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $ * */ #ifndef __PUSHPULL_H__ #define __PUSHPULL_H__ + +#include + struct pushpull { unsigned char *buf; unsigned int buflen; @@ -44,9 +23,36 @@ unsigned int reserve; }; -void init_pushpull(struct pushpull *, char *, unsigned, unsigned, unsigned); -int pushbit(struct pushpull *pp, int bit, int use_reserved); -int pushedbits(struct pushpull *pp); + +static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) +{ + pp->buf = buf; + pp->buflen = buflen; + pp->ofs = ofs; + pp->reserve = reserve; +} + +static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) +{ + if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { + return -ENOSPC; + } + + if (bit) { + pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); + } + else { + pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); + } + pp->ofs++; + + return 0; +} + +static inline int pushedbits(struct pushpull *pp) +{ + return pp->ofs; +} static inline int pullbit(struct pushpull *pp) { diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c --- a/fs/jffs2/read.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/read.c Thu Dec 4 16:24:25 2003 @@ -1,52 +1,29 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: read.c,v 1.13.2.1 2002/02/01 23:32:33 dwmw2 Exp $ + * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $ * */ #include #include -#include +#include +#include #include +#include #include "nodelist.h" -#include "crc32.h" int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len) { struct jffs2_raw_inode *ri; size_t readlen; - __u32 crc; + uint32_t crc; unsigned char *decomprbuf = NULL; unsigned char *readbuf = NULL; int ret = 0; @@ -55,35 +32,41 @@ if (!ri) return -ENOMEM; - ret = c->mtd->read(c->mtd, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri); + ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri); if (ret) { jffs2_free_raw_inode(ri); - printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret); + printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret); return ret; } if (readlen != sizeof(*ri)) { jffs2_free_raw_inode(ri); - printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", - fd->raw->flash_offset & ~3, sizeof(*ri), readlen); + printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", + ref_offset(fd->raw), sizeof(*ri), readlen); return -EIO; } crc = crc32(0, ri, sizeof(*ri)-8); - D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", fd->raw->flash_offset & ~3, ri->node_crc, crc, ri->dsize, ri->csize, ri->offset, buf)); - if (crc != ri->node_crc) { - printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", ri->node_crc, crc, fd->raw->flash_offset & ~3); + D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", + ref_offset(fd->raw), je32_to_cpu(ri->node_crc), + crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), + je32_to_cpu(ri->offset), buf)); + if (crc != je32_to_cpu(ri->node_crc)) { + printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", + je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); ret = -EIO; goto out_ri; } /* There was a bug where we wrote hole nodes out with csize/dsize swapped. Deal with it */ - if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) { + if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && + je32_to_cpu(ri->csize)) { ri->dsize = ri->csize; - ri->csize = 0; + ri->csize = cpu_to_je32(0); } - D1(if(ofs + len > ri->dsize) { - printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize); + D1(if(ofs + len > je32_to_cpu(ri->dsize)) { + printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", + len, ofs, je32_to_cpu(ri->dsize)); ret = -EINVAL; goto out_ri; }); @@ -100,18 +83,18 @@ Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy */ - if (ri->compr == JFFS2_COMPR_NONE && len == ri->dsize) { + if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { readbuf = buf; } else { - readbuf = kmalloc(ri->csize, GFP_KERNEL); + readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); if (!readbuf) { ret = -ENOMEM; goto out_ri; } } if (ri->compr != JFFS2_COMPR_NONE) { - if (len < ri->dsize) { - decomprbuf = kmalloc(ri->dsize, GFP_KERNEL); + if (len < je32_to_cpu(ri->dsize)) { + decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); if (!decomprbuf) { ret = -ENOMEM; goto out_readbuf; @@ -123,31 +106,35 @@ decomprbuf = readbuf; } - D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf)); - ret = c->mtd->read(c->mtd, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf); + D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize), + readbuf)); + ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), + je32_to_cpu(ri->csize), &readlen, readbuf); - if (!ret && readlen != ri->csize) + if (!ret && readlen != je32_to_cpu(ri->csize)) ret = -EIO; if (ret) goto out_decomprbuf; - crc = crc32(0, readbuf, ri->csize); - if (crc != ri->data_crc) { - printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", ri->data_crc, crc, fd->raw->flash_offset & ~3); + crc = crc32(0, readbuf, je32_to_cpu(ri->csize)); + if (crc != je32_to_cpu(ri->data_crc)) { + printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", + je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); ret = -EIO; goto out_decomprbuf; } D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); if (ri->compr != JFFS2_COMPR_NONE) { - D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf)); - ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize); + D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", + je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); + ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); if (ret) { printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); goto out_decomprbuf; } } - if (len < ri->dsize) { + if (len < je32_to_cpu(ri->dsize)) { memcpy(buf, decomprbuf+ofs, len); } out_decomprbuf: @@ -160,4 +147,97 @@ jffs2_free_raw_inode(ri); return ret; +} + +int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + unsigned char *buf, uint32_t offset, uint32_t len) +{ + uint32_t end = offset + len; + struct jffs2_node_frag *frag; + int ret; + + D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n", + f->inocache->ino, offset, offset+len)); + + frag = jffs2_lookup_node_frag(&f->fragtree, offset); + + /* XXX FIXME: Where a single physical node actually shows up in two + frags, we read it twice. Don't do that. */ + /* Now we're pointing at the first frag which overlaps our page */ + while(offset < end) { + D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); + if (unlikely(!frag || frag->ofs > offset)) { + uint32_t holesize = end - offset; + if (frag) { + D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); + holesize = min(holesize, frag->ofs - offset); + D1(jffs2_print_frag_list(f)); + } + D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); + memset(buf, 0, holesize); + buf += holesize; + offset += holesize; + continue; + } else if (unlikely(!frag->node)) { + uint32_t holeend = min(end, frag->ofs + frag->size); + D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); + memset(buf, 0, holeend - offset); + buf += holeend - offset; + offset = holeend; + frag = frag_next(frag); + continue; + } else { + uint32_t readlen; + uint32_t fragofs; /* offset within the frag to start reading */ + + fragofs = offset - frag->ofs; + readlen = min(frag->size - fragofs, end - offset); + D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", + frag->ofs+fragofs, frag->ofs+fragofs+readlen, + ref_offset(frag->node->raw), ref_flags(frag->node->raw))); + ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); + D2(printk(KERN_DEBUG "node read done\n")); + if (ret) { + D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret)); + memset(buf, 0, readlen); + return ret; + } + buf += readlen; + offset += readlen; + frag = frag_next(frag); + D2(printk(KERN_DEBUG "node read was OK. Looping\n")); + } + } + return 0; +} + +/* Core function to read symlink target. */ +char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) +{ + char *buf; + int ret; + + down(&f->sem); + + if (!f->metadata) { + printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); + up(&f->sem); + return ERR_PTR(-EINVAL); + } + buf = kmalloc(f->metadata->size+1, GFP_USER); + if (!buf) { + up(&f->sem); + return ERR_PTR(-ENOMEM); + } + buf[f->metadata->size]=0; + + ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size); + + up(&f->sem); + + if (ret) { + kfree(buf); + return ERR_PTR(ret); + } + return buf; } diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c --- a/fs/jffs2/readinode.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/readinode.c Thu Dec 4 16:24:25 2003 @@ -1,79 +1,122 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: readinode.c,v 1.58.2.6 2002/10/10 13:18:38 dwmw2 Exp $ + * $Id: readinode.c,v 1.113 2003/11/03 13:20:33 dwmw2 Exp $ * */ -/* Given an inode, probably with existing list of fragments, add the new node - * to the fragment list. - */ #include #include #include +#include +#include #include -#include +#include #include "nodelist.h" -#include "crc32.h" +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); -D1(void jffs2_print_frag_list(struct jffs2_inode_info *f) +#if CONFIG_JFFS2_FS_DEBUG >= 1 +static void jffs2_print_fragtree(struct rb_root *list, int permitbug) { - struct jffs2_node_frag *this = f->fraglist; + struct jffs2_node_frag *this = frag_first(list); + uint32_t lastofs = 0; + int buggy = 0; while(this) { if (this->node) - printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next); + printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n", + this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw), + this, frag_left(this), frag_right(this), frag_parent(this)); else - printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next); - this = this->next; + printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, + this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this)); + if (this->ofs != lastofs) + buggy = 1; + lastofs = this->ofs+this->size; + this = frag_next(this); + } + if (buggy && !permitbug) { + printk(KERN_CRIT "Frag tree got a hole in it\n"); + BUG(); } +} + +void jffs2_print_frag_list(struct jffs2_inode_info *f) +{ + jffs2_print_fragtree(&f->fragtree, 0); + if (f->metadata) { - printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3); + printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); } -}) - +} -int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) +static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) { - int ret; - D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); + struct jffs2_node_frag *frag; + int bitched = 0; - ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn); + for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { - D2(jffs2_print_frag_list(f)); - return ret; + struct jffs2_full_dnode *fn = frag->node; + if (!fn || !fn->raw) + continue; + + if (ref_flags(fn->raw) == REF_PRISTINE) { + + if (fn->frags > 1) { + printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags); + bitched = 1; + } + /* A hole node which isn't multi-page should be garbage-collected + and merged anyway, so we just check for the frag size here, + rather than mucking around with actually reading the node + and checking the compression type, which is the real way + to tell a hole node. */ + if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { + printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", + ref_offset(fn->raw)); + bitched = 1; + } + + if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { + printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", + ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); + bitched = 1; + } + } + } + + if (bitched) { + struct jffs2_node_frag *thisfrag; + + printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino); + thisfrag = frag_first(&f->fragtree); + while (thisfrag) { + if (!thisfrag->node) { + printk("Frag @0x%x-0x%x; node-less hole\n", + thisfrag->ofs, thisfrag->size + thisfrag->ofs); + } else if (!thisfrag->node->raw) { + printk("Frag @0x%x-0x%x; raw-less hole\n", + thisfrag->ofs, thisfrag->size + thisfrag->ofs); + } else { + printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n", + thisfrag->ofs, thisfrag->size + thisfrag->ofs, + ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw), + thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size); + } + thisfrag = frag_next(thisfrag); + } + } + return bitched; } +#endif /* D1 */ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) { @@ -82,42 +125,38 @@ if (!this->node->frags) { /* The node has no valid frags left. It's totally obsoleted */ D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", - this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size)); + ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); jffs2_mark_node_obsolete(c, this->node->raw); jffs2_free_full_dnode(this->node); } else { - D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n", - this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size, + D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", + ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags)); + mark_ref_normal(this->node->raw); } } jffs2_free_node_frag(this); } -/* Doesn't set inode->i_size */ -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn) +/* Given an inode, probably with existing list of fragments, add the new node + * to the fragment list. + */ +int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { - - struct jffs2_node_frag *this, **prev, *old; - struct jffs2_node_frag *newfrag, *newfrag2; - __u32 lastend = 0; + int ret; + struct jffs2_node_frag *newfrag; + D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); newfrag = jffs2_alloc_node_frag(); - if (!newfrag) { + if (unlikely(!newfrag)) return -ENOMEM; - } - D2(if (fn->raw) - printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag); - else - printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag)); + D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", + fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); - prev = list; - this = *list; - - if (!fn->size) { + if (unlikely(!fn->size)) { jffs2_free_node_frag(newfrag); return 0; } @@ -126,176 +165,358 @@ newfrag->size = fn->size; newfrag->node = fn; newfrag->node->frags = 1; - newfrag->next = (void *)0xdeadbeef; - /* Skip all the nodes which are completed before this one starts */ - while(this && fn->ofs >= this->ofs+this->size) { - lastend = this->ofs + this->size; + ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); + if (ret) + return ret; + + /* If we now share a page with other nodes, mark either previous + or next node REF_NORMAL, as appropriate. */ + if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *prev = frag_prev(newfrag); + + mark_ref_normal(fn->raw); + /* If we don't start at zero there's _always_ a previous */ + if (prev->node) + mark_ref_normal(prev->node->raw); + } - D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", - this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); - prev = &this->next; - this = this->next; + if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *next = frag_next(newfrag); + + if (next) { + mark_ref_normal(fn->raw); + if (next->node) + mark_ref_normal(next->node->raw); + } } + D2(if (jffs2_sanitycheck_fragtree(f)) { + printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n", + fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); + return 0; + }) + D2(jffs2_print_frag_list(f)); + return 0; +} +/* Doesn't set inode->i_size */ +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) +{ + struct jffs2_node_frag *this; + uint32_t lastend; + + /* Skip all the nodes which are completed before this one starts */ + this = jffs2_lookup_node_frag(list, newfrag->node->ofs); + + if (this) { + D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", + this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); + lastend = this->ofs + this->size; + } else { + D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); + lastend = 0; + } + /* See if we ran off the end of the list */ - if (!this) { + if (lastend <= newfrag->ofs) { /* We did */ - if (lastend < fn->ofs) { + + /* Check if 'this' node was on the same page as the new node. + If so, both 'this' and the new node get marked REF_NORMAL so + the GC can take a look. + */ + if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { + if (this->node) + mark_ref_normal(this->node->raw); + mark_ref_normal(newfrag->node->raw); + } + + if (lastend < newfrag->node->ofs) { /* ... and we need to put a hole in before the new node */ struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); - if (!holefrag) + if (!holefrag) { + jffs2_free_node_frag(newfrag); return -ENOMEM; + } holefrag->ofs = lastend; - holefrag->size = fn->ofs - lastend; - holefrag->next = NULL; + holefrag->size = newfrag->node->ofs - lastend; holefrag->node = NULL; - *prev = holefrag; - prev = &holefrag->next; + if (this) { + /* By definition, the 'this' node has no right-hand child, + because there are no frags with offset greater than it. + So that's where we want to put the hole */ + D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); + rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); + } else { + D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); + rb_link_node(&holefrag->rb, NULL, &list->rb_node); + } + rb_insert_color(&holefrag->rb, list); + this = holefrag; + } + if (this) { + /* By definition, the 'this' node has no right-hand child, + because there are no frags with offset greater than it. + So that's where we want to put the hole */ + D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); + rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); + } else { + D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); + rb_link_node(&newfrag->rb, NULL, &list->rb_node); } - newfrag->next = NULL; - *prev = newfrag; + rb_insert_color(&newfrag->rb, list); return 0; } - D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", - this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); + D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", + this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); - /* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes, - * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs + /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, + * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs */ - if (fn->ofs > this->ofs) { + if (newfrag->ofs > this->ofs) { /* This node isn't completely obsoleted. The start of it remains valid */ - if (this->ofs + this->size > fn->ofs + fn->size) { + + /* Mark the new node and the partially covered node REF_NORMAL -- let + the GC take a look at them */ + mark_ref_normal(newfrag->node->raw); + if (this->node) + mark_ref_normal(this->node->raw); + + if (this->ofs + this->size > newfrag->ofs + newfrag->size) { /* The new node splits 'this' frag into two */ - newfrag2 = jffs2_alloc_node_frag(); + struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); if (!newfrag2) { jffs2_free_node_frag(newfrag); return -ENOMEM; } - D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); + D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); if (this->node) - printk("phys 0x%08x\n", this->node->raw->flash_offset &~3); + printk("phys 0x%08x\n", ref_offset(this->node->raw)); else printk("hole\n"); ) - newfrag2->ofs = fn->ofs + fn->size; + + /* New second frag pointing to this's node */ + newfrag2->ofs = newfrag->ofs + newfrag->size; newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; - newfrag2->next = this->next; newfrag2->node = this->node; if (this->node) this->node->frags++; - newfrag->next = newfrag2; - this->next = newfrag; + + /* Adjust size of original 'this' */ this->size = newfrag->ofs - this->ofs; + + /* Now, we know there's no node with offset + greater than this->ofs but smaller than + newfrag2->ofs or newfrag->ofs, for obvious + reasons. So we can do a tree insert from + 'this' to insert newfrag, and a tree insert + from newfrag to insert newfrag2. */ + jffs2_fragtree_insert(newfrag, this); + rb_insert_color(&newfrag->rb, list); + + jffs2_fragtree_insert(newfrag2, newfrag); + rb_insert_color(&newfrag2->rb, list); + return 0; } /* New node just reduces 'this' frag in size, doesn't split it */ - this->size = fn->ofs - this->ofs; - newfrag->next = this->next; - this->next = newfrag; - this = newfrag->next; + this->size = newfrag->ofs - this->ofs; + + /* Again, we know it lives down here in the tree */ + jffs2_fragtree_insert(newfrag, this); + rb_insert_color(&newfrag->rb, list); } else { - D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this)); - *prev = newfrag; - newfrag->next = this; + /* New frag starts at the same point as 'this' used to. Replace + it in the tree without doing a delete and insertion */ + D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", + newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, + this, this->ofs, this->ofs+this->size)); + + rb_replace_node(&this->rb, &newfrag->rb, list); + + if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { + D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); + jffs2_obsolete_node_frag(c, this); + } else { + this->ofs += newfrag->size; + this->size -= newfrag->size; + + jffs2_fragtree_insert(this, newfrag); + rb_insert_color(&this->rb, list); + return 0; + } } - /* OK, now we have newfrag added in the correct place in the list, but - newfrag->next points to a fragment which may be overlapping it + /* OK, now we have newfrag added in the correct place in the tree, but + frag_next(newfrag) may be a fragment which is overlapped by it */ - while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) { - /* 'this' frag is obsoleted. */ - old = this; - this = old->next; - jffs2_obsolete_node_frag(c, old); + while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { + /* 'this' frag is obsoleted completely. */ + D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); + rb_erase(&this->rb, list); + jffs2_obsolete_node_frag(c, this); } /* Now we're pointing at the first frag which isn't totally obsoleted by the new frag */ - newfrag->next = this; if (!this || newfrag->ofs + newfrag->size == this->ofs) { return 0; } - /* Still some overlap */ + /* Still some overlap but we don't need to move it in the tree */ this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); this->ofs = newfrag->ofs + newfrag->size; + + /* And mark them REF_NORMAL so the GC takes a look at them */ + if (this->node) + mark_ref_normal(this->node->raw); + mark_ref_normal(newfrag->node->raw); + return 0; } -void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size) +void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) { + struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); + D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); - while (*list) { - if ((*list)->ofs >= size) { - struct jffs2_node_frag *this = *list; - *list = this->next; - D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size)); - jffs2_obsolete_node_frag(c, this); - continue; - } else if ((*list)->ofs + (*list)->size > size) { - D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size)); - (*list)->size = size - (*list)->ofs; - } - list = &(*list)->next; + /* We know frag->ofs <= size. That's what lookup does for us */ + if (frag && frag->ofs != size) { + if (frag->ofs+frag->size >= size) { + D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); + frag->size = size - frag->ofs; + } + frag = frag_next(frag); + } + while (frag && frag->ofs >= size) { + struct jffs2_node_frag *next = frag_next(frag); + + D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); + frag_erase(frag, list); + jffs2_obsolete_node_frag(c, frag); + frag = next; } } /* Scan the list of all nodes present for this ino, build map of versions, etc. */ -void jffs2_read_inode (struct inode *inode) -{ - struct jffs2_tmp_dnode_info *tn_list, *tn; - struct jffs2_full_dirent *fd_list; - struct jffs2_inode_info *f; - struct jffs2_full_dnode *fn = NULL; - struct jffs2_sb_info *c; - struct jffs2_raw_inode latest_node; - __u32 latest_mctime, mctime_ver; - __u32 mdata_ver = 0; - int ret; - ssize_t retlen; +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node); - D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); +int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + uint32_t ino, struct jffs2_raw_inode *latest_node) +{ + D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); - f = JFFS2_INODE_INFO(inode); - c = JFFS2_SB_INFO(inode->i_sb); + retry_inocache: + spin_lock(&c->inocache_lock); + f->inocache = jffs2_get_ino_cache(c, ino); + + D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); + + if (f->inocache) { + /* Check its state. We may need to wait before we can use it */ + switch(f->inocache->state) { + case INO_STATE_UNCHECKED: + case INO_STATE_CHECKEDABSENT: + f->inocache->state = INO_STATE_READING; + break; + + case INO_STATE_CHECKING: + case INO_STATE_GC: + /* If it's in either of these states, we need + to wait for whoever's got it to finish and + put it back. */ + D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", + ino, f->inocache->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + goto retry_inocache; + + case INO_STATE_READING: + case INO_STATE_PRESENT: + /* Eep. This should never happen. It can + happen if Linux calls read_inode() again + before clear_inode() has finished though. */ + printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); + /* Fail. That's probably better than allowing it to succeed */ + f->inocache = NULL; + break; - memset(f, 0, sizeof(*f)); - D2(printk(KERN_DEBUG "getting inocache\n")); - init_MUTEX(&f->sem); - f->inocache = jffs2_get_ino_cache(c, inode->i_ino); - D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache)); + default: + BUG(); + } + } + spin_unlock(&c->inocache_lock); - if (!f->inocache && inode->i_ino == 1) { + if (!f->inocache && ino == 1) { /* Special case - no root inode on medium */ f->inocache = jffs2_alloc_inode_cache(); if (!f->inocache) { - printk(KERN_CRIT "jffs2_read_inode(): Cannot allocate inocache for root inode\n"); - make_bad_inode(inode); - return; + printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n"); + return -ENOMEM; } - D1(printk(KERN_DEBUG "jffs2_read_inode(): Creating inocache for root inode\n")); + D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n")); memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; + f->inocache->state = INO_STATE_READING; jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { - printk(KERN_WARNING "jffs2_read_inode() on nonexistent ino %lu\n", (unsigned long)inode->i_ino); - make_bad_inode(inode); - return; + printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); + return -ENOENT; + } + + return jffs2_do_read_inode_internal(c, f, latest_node); +} + +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_raw_inode n; + struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); + int ret; + + if (!f) + return -ENOMEM; + + memset(f, 0, sizeof(*f)); + init_MUTEX_LOCKED(&f->sem); + f->inocache = ic; + + ret = jffs2_do_read_inode_internal(c, f, &n); + if (!ret) { + up(&f->sem); + jffs2_do_clear_inode(c, f); } - D1(printk(KERN_DEBUG "jffs2_read_inode(): ino #%lu nlink is %d\n", (unsigned long)inode->i_ino, f->inocache->nlink)); - inode->i_nlink = f->inocache->nlink; + kfree (f); + return ret; +} + +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node) +{ + struct jffs2_tmp_dnode_info *tn_list, *tn; + struct jffs2_full_dirent *fd_list; + struct jffs2_full_dnode *fn = NULL; + uint32_t crc; + uint32_t latest_mctime, mctime_ver; + uint32_t mdata_ver = 0; + size_t retlen; + int ret; + + D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); /* Grab all nodes relevant to this ino */ - ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); + ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); if (ret) { - printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret); - make_bad_inode(inode); - return; + printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + return ret; } f->dents = fd_list; @@ -304,219 +525,169 @@ fn = tn->fn; - if (f->metadata && tn->version > mdata_ver) { - D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3)); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; + if (f->metadata) { + if (likely(tn->version >= mdata_ver)) { + D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + + mdata_ver = 0; + } else { + /* This should never happen. */ + printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n", + ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + /* Fill in latest_node from the metadata, not this one we're about to free... */ + fn = f->metadata; + goto next_tn; + } } if (fn->size) { jffs2_add_full_dnode_to_inode(c, f, fn); } else { /* Zero-sized node at end of version list. Just a metadata update */ - D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version)); + D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version)); f->metadata = fn; mdata_ver = tn->version; } + next_tn: tn_list = tn->next; jffs2_free_tmp_dnode_info(tn); } + D1(jffs2_sanitycheck_fragtree(f)); + if (!fn) { /* No data nodes for this inode. */ - if (inode->i_ino != 1) { - printk(KERN_WARNING "jffs2_read_inode(): No data nodes found for ino #%lu\n", inode->i_ino); + if (f->inocache->ino != 1) { + printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { - make_bad_inode(inode); - return; + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + return -EIO; } - printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n"); + printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); } - inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO; - latest_node.version = 0; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; - inode->i_nlink = f->inocache->nlink; - inode->i_size = 0; - } else { - __u32 crc; + latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); + latest_node->version = cpu_to_je32(0); + latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); + latest_node->isize = cpu_to_je32(0); + latest_node->gid = cpu_to_je16(0); + latest_node->uid = cpu_to_je16(0); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); + return 0; + } - ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(latest_node), &retlen, (void *)&latest_node); - if (ret || retlen != sizeof(latest_node)) { - printk(KERN_NOTICE "MTD read in jffs2_read_inode() failed: Returned %d, %ld of %d bytes read\n", - ret, (long)retlen, sizeof(latest_node)); - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - - crc = crc32(0, &latest_node, sizeof(latest_node)-8); - if (crc != latest_node.node_crc) { - printk(KERN_NOTICE "CRC failed for read_inode of inode %ld at physical location 0x%x\n", inode->i_ino, fn->raw->flash_offset & ~3); - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - - inode->i_mode = latest_node.mode; - inode->i_uid = latest_node.uid; - inode->i_gid = latest_node.gid; - inode->i_size = latest_node.isize; - if (S_ISREG(inode->i_mode)) - jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize); - inode->i_atime = latest_node.atime; - inode->i_mtime = latest_node.mtime; - inode->i_ctime = latest_node.ctime; - } - - /* OK, now the special cases. Certain inode types should - have only one data node, and it's kept as the metadata - node */ - if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) || - S_ISLNK(inode->i_mode)) { - if (f->metadata) { - printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode); - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - if (!f->fraglist) { - printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o has no fragments\n", inode->i_ino, inode->i_mode); - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - /* ASSERT: f->fraglist != NULL */ - if (f->fraglist->next) { - printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode); - /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - /* OK. We're happy */ - f->metadata = f->fraglist->node; - jffs2_free_node_frag(f->fraglist); - f->fraglist = NULL; - } - - inode->i_blksize = PAGE_SIZE; - inode->i_blocks = (inode->i_size + 511) >> 9; - - switch (inode->i_mode & S_IFMT) { - unsigned short rdev; + ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); + if (ret || retlen != sizeof(*latest_node)) { + printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", + ret, retlen, sizeof(*latest_node)); + /* FIXME: If this fails, there seems to be a memory leak. Find it. */ + up(&f->sem); + jffs2_do_clear_inode(c, f); + return ret?ret:-EIO; + } + + crc = crc32(0, latest_node, sizeof(*latest_node)-8); + if (crc != je32_to_cpu(latest_node->node_crc)) { + printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -EIO; + } - case S_IFLNK: - inode->i_op = &jffs2_symlink_inode_operations; - /* Hack to work around broken isize in old symlink code. - Remove this when dwmw2 comes to his senses and stops - symlinks from being an entirely gratuitous special - case. */ - if (!inode->i_size) - inode->i_size = latest_node.dsize; - break; - + switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: - if (mctime_ver > latest_node.version) { + if (mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than mctime in the latest dirent. Cheat. */ - inode->i_mtime = inode->i_ctime = inode->i_atime = - latest_mctime; + latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); } - inode->i_op = &jffs2_dir_inode_operations; - inode->i_fop = &jffs2_dir_operations; break; + case S_IFREG: - inode->i_op = &jffs2_file_inode_operations; - inode->i_fop = &jffs2_file_operations; - inode->i_mapping->a_ops = &jffs2_file_address_operations; - inode->i_mapping->nrpages = 0; + /* If it was a regular file, truncate it to the latest node's isize */ + jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize)); break; + case S_IFLNK: + /* Hack to work around broken isize in old symlink code. + Remove this when dwmw2 comes to his senses and stops + symlinks from being an entirely gratuitous special + case. */ + if (!je32_to_cpu(latest_node->isize)) + latest_node->isize = latest_node->dsize; + /* fall through... */ + case S_IFBLK: case S_IFCHR: - /* Read the device numbers from the media */ - D1(printk(KERN_DEBUG "Reading device numbers from flash\n")); - if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { - /* Eep */ - printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); - jffs2_clear_inode(inode); - make_bad_inode(inode); - return; - } - - case S_IFSOCK: - case S_IFIFO: - inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff))); + /* Certain inode types should have only one data node, and it's + kept as the metadata node */ + if (f->metadata) { + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -EIO; + } + if (!frag_first(&f->fragtree)) { + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -EIO; + } + /* ASSERT: f->fraglist != NULL */ + if (frag_next(frag_first(&f->fragtree))) { + printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); + /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -EIO; + } + /* OK. We're happy */ + f->metadata = frag_first(&f->fragtree)->node; + jffs2_free_node_frag(frag_first(&f->fragtree)); + f->fragtree = RB_ROOT; break; - - default: - printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu", inode->i_mode, (unsigned long)inode->i_ino); } - D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); + + return 0; } -void jffs2_clear_inode (struct inode *inode) +void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) { - /* We can forget about this inode for now - drop all - * the nodelists associated with it, etc. - */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_node_frag *frag, *frags; struct jffs2_full_dirent *fd, *fds; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - /* I don't think we care about the potential race due to reading this - without f->sem. It can never get undeleted. */ - int deleted = f->inocache && !f->inocache->nlink; - - D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); - - /* If it's a deleted inode, grab the alloc_sem. This prevents - jffs2_garbage_collect_pass() from deciding that it wants to - garbage collect one of the nodes we're just about to mark - obsolete -- by the time we drop alloc_sem and return, all - the nodes are marked obsolete, and jffs2_g_c_pass() won't - call iget() for the inode in question. - */ - if (deleted) - down(&c->alloc_sem); + int deleted; down(&f->sem); + deleted = f->inocache && !f->inocache->nlink; - frags = f->fraglist; - fds = f->dents; if (f->metadata) { if (deleted) jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); } - while (frags) { - frag = frags; - frags = frag->next; - D2(printk(KERN_DEBUG "jffs2_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0)); - - if (frag->node && !(--frag->node->frags)) { - /* Not a hole, and it's the final remaining frag of this node. Free the node */ - if (deleted) - jffs2_mark_node_obsolete(c, frag->node->raw); + jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); + + fds = f->dents; - jffs2_free_full_dnode(frag->node); - } - jffs2_free_node_frag(frag); - } while(fds) { fd = fds; fds = fd->next; jffs2_free_full_dirent(fd); } - up(&f->sem); - - if(deleted) - up(&c->alloc_sem); -}; + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + up(&f->sem); +} diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c --- a/fs/jffs2/scan.c Thu Dec 4 16:24:26 2003 +++ b/fs/jffs2/scan.c Thu Dec 4 16:24:26 2003 @@ -1,47 +1,25 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: scan.c,v 1.51.2.3 2002/07/25 20:49:06 dwmw2 Exp $ + * $Id: scan.c,v 1.106 2003/10/28 17:01:13 dwmw2 Exp $ * */ #include +#include #include -#include #include #include +#include +#include #include "nodelist.h" -#include "crc32.h" +#define EMPTY_SCAN_SIZE 1024 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ c->free_size -= _x; c->dirty_size += _x; \ @@ -51,6 +29,10 @@ c->free_size -= _x; c->used_size += _x; \ jeb->free_size -= _x ; jeb->used_size += _x; \ }while(0) +#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->unchecked_size += _x; \ + jeb->free_size -= _x ; jeb->unchecked_size += _x; \ + }while(0) #define noisy_printk(noise, args...) do { \ if (*(noise)) { \ @@ -63,39 +45,84 @@ } while(0) static uint32_t pseudo_random; -static void jffs2_rotate_lists(struct jffs2_sb_info *c); -static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + unsigned char *buf, uint32_t buf_size); /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. * Returning an error will abort the mount - bad checksums etc. should just mark the space * as dirty. */ -static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs, int *noise); -static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs); -static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs); +static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_inode *ri, uint32_t ofs); +static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_dirent *rd, uint32_t ofs); + +#define BLK_STATE_ALLFF 0 +#define BLK_STATE_CLEAN 1 +#define BLK_STATE_PARTDIRTY 2 +#define BLK_STATE_CLEANMARKER 3 +#define BLK_STATE_ALLDIRTY 4 +#define BLK_STATE_BADBLOCK 5 +static inline int min_free(struct jffs2_sb_info *c) +{ + uint32_t min = 2 * sizeof(struct jffs2_raw_inode); +#ifdef CONFIG_JFFS2_FS_NAND + if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) + return c->wbuf_pagesize; +#endif + return min; +} int jffs2_scan_medium(struct jffs2_sb_info *c) { int i, ret; - __u32 empty_blocks = 0; - - if (!c->blocks) { - printk(KERN_WARNING "EEEK! c->blocks is NULL!\n"); - return -EINVAL; + uint32_t empty_blocks = 0, bad_blocks = 0; + unsigned char *flashbuf = NULL; + uint32_t buf_size = 0; +#ifndef __ECOS + size_t pointlen; + + if (c->mtd->point) { + ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); + if (!ret && pointlen < c->mtd->size) { + /* Don't muck about if it won't let us point to the whole flash */ + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); + flashbuf = NULL; + } + if (ret) + D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); + } +#endif + if (!flashbuf) { + /* For NAND it's quicker to read a whole eraseblock at a time, + apparently */ + if (jffs2_cleanmarker_oob(c)) + buf_size = c->sector_size; + else + buf_size = PAGE_SIZE; + + D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size)); + flashbuf = kmalloc(buf_size, GFP_KERNEL); + if (!flashbuf) + return -ENOMEM; } + for (i=0; inr_blocks; i++) { struct jffs2_eraseblock *jeb = &c->blocks[i]; - ret = jffs2_scan_eraseblock(c, jeb); + ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); + if (ret < 0) - return ret; + goto out; ACCT_PARANOIA_CHECK(jeb); /* Now decide which list to put it on */ - if (ret == 1) { + switch(ret) { + case BLK_STATE_ALLFF: /* * Empty block. Since we can't be sure it * was entirely erased, we just queue it for erase @@ -103,10 +130,12 @@ * is complete. Meanwhile we still count it as empty * for later checks. */ - list_add(&jeb->list, &c->erase_pending_list); empty_blocks++; + list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; - } else if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && !jeb->first_node->next_in_ino) { + break; + + case BLK_STATE_CLEANMARKER: /* Only a CLEANMARKER node is valid */ if (!jeb->dirty_size) { /* It's actually free */ @@ -118,74 +147,227 @@ list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; } - } else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode))) { + break; + + case BLK_STATE_CLEAN: /* Full (or almost full) of clean data. Clean list */ list_add(&jeb->list, &c->clean_list); - } else if (jeb->used_size) { + break; + + case BLK_STATE_PARTDIRTY: /* Some data, but not full. Dirty list. */ /* Except that we want to remember the block with most free space, and stick it in the 'nextblock' position to start writing to it. Later when we do snapshots, this must be the most recent block, not the one with most free space. */ - if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) && - (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { + if (jeb->free_size > min_free(c) && + (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { /* Better candidate for the next writes to go to */ - if (c->nextblock) - list_add(&c->nextblock->list, &c->dirty_list); + if (c->nextblock) { + c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; + c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; + c->free_size -= c->nextblock->free_size; + c->wasted_size -= c->nextblock->wasted_size; + c->nextblock->free_size = c->nextblock->wasted_size = 0; + if (VERYDIRTY(c, c->nextblock->dirty_size)) { + list_add(&c->nextblock->list, &c->very_dirty_list); + } else { + list_add(&c->nextblock->list, &c->dirty_list); + } + } c->nextblock = jeb; } else { - list_add(&jeb->list, &c->dirty_list); + jeb->dirty_size += jeb->free_size + jeb->wasted_size; + c->dirty_size += jeb->free_size + jeb->wasted_size; + c->free_size -= jeb->free_size; + c->wasted_size -= jeb->wasted_size; + jeb->free_size = jeb->wasted_size = 0; + if (VERYDIRTY(c, jeb->dirty_size)) { + list_add(&jeb->list, &c->very_dirty_list); + } else { + list_add(&jeb->list, &c->dirty_list); + } } - } else { + break; + + case BLK_STATE_ALLDIRTY: /* Nothing valid - not even a clean marker. Needs erasing. */ /* For now we just put it on the erasing list. We'll start the erases later */ - printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset); + D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; + break; + + case BLK_STATE_BADBLOCK: + D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); + list_add(&jeb->list, &c->bad_list); + c->bad_size += c->sector_size; + c->free_size -= c->sector_size; + bad_blocks++; + break; + default: + printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); + BUG(); } } - /* Rotate the lists by some number to ensure wear levelling */ - jffs2_rotate_lists(c); + + /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ + if (c->nextblock && (c->nextblock->dirty_size)) { + c->nextblock->wasted_size += c->nextblock->dirty_size; + c->wasted_size += c->nextblock->dirty_size; + c->dirty_size -= c->nextblock->dirty_size; + c->nextblock->dirty_size = 0; + } +#ifdef CONFIG_JFFS2_FS_NAND + if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { + /* If we're going to start writing into a block which already + contains data, and the end of the data isn't page-aligned, + skip a little and align it. */ + + uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1); + + D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", + skip)); + c->nextblock->wasted_size += skip; + c->wasted_size += skip; + c->nextblock->free_size -= skip; + c->free_size -= skip; + } +#endif if (c->nr_erasing_blocks) { - if (!c->used_size && empty_blocks != c->nr_blocks) { + if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); - return -EIO; + printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); + ret = -EIO; + goto out; } jffs2_erase_pending_trigger(c); } + ret = 0; + out: + if (buf_size) + kfree(flashbuf); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); +#endif + return ret; +} + +static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, + uint32_t ofs, uint32_t len) +{ + int ret; + size_t retlen; + + ret = jffs2_flash_read(c, ofs, len, &retlen, buf); + if (ret) { + D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret)); + return ret; + } + if (retlen < len) { + D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); + return -EIO; + } + D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs)); + D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15])); return 0; } -static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct jffs2_unknown_node node; - __u32 ofs, prevofs; - __u32 hdr_crc, nodetype; +static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + unsigned char *buf, uint32_t buf_size) { + struct jffs2_unknown_node *node; + struct jffs2_unknown_node crcnode; + uint32_t ofs, prevofs; + uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; + int wasempty = 0; + uint32_t empty_start = 0; +#ifdef CONFIG_JFFS2_FS_NAND + int cleanmarkerfound = 0; +#endif ofs = jeb->offset; prevofs = jeb->offset - 1; D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); - err = jffs2_scan_empty(c, jeb, &ofs, &noise); - if (err) return err; - if (ofs == jeb->offset + c->sector_size) { - D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); - return 1; /* special return code */ +#ifdef CONFIG_JFFS2_FS_NAND + if (jffs2_cleanmarker_oob(c)) { + int ret = jffs2_check_nand_cleanmarker(c, jeb); + D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); + /* Even if it's not found, we still scan to see + if the block is empty. We use this information + to decide whether to erase it or not. */ + switch (ret) { + case 0: cleanmarkerfound = 1; break; + case 1: break; + case 2: return BLK_STATE_BADBLOCK; + case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */ + default: return ret; + } + } +#endif + buf_ofs = jeb->offset; + + if (!buf_size) { + buf_len = c->sector_size; + } else { + buf_len = EMPTY_SCAN_SIZE; + err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); + if (err) + return err; } + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + + /* Scan only 4KiB of 0xFF before declaring it's empty */ + while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) + ofs += 4; + + if (ofs == EMPTY_SCAN_SIZE) { +#ifdef CONFIG_JFFS2_FS_NAND + if (jffs2_cleanmarker_oob(c)) { + /* scan oob, take care of cleanmarker */ + int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); + D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret)); + switch (ret) { + case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF; + case 1: return BLK_STATE_ALLDIRTY; + case 2: return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */ + case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */ + default: return ret; + } + } +#endif + D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); + return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ + } + if (ofs) { + D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, + jeb->offset + ofs)); + DIRTY_SPACE(ofs); + } + + /* Now ofs is a complete physical flash offset as it always was... */ + ofs += jeb->offset; + noise = 10; while(ofs < jeb->offset + c->sector_size) { - ssize_t retlen; - ACCT_PARANOIA_CHECK(jeb); - + + D1(ACCT_PARANOIA_CHECK(jeb)); + + cond_resched(); + if (ofs & 3) { printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs); - ofs = (ofs+3)&~3; + ofs = PAD(ofs); continue; } if (ofs == prevofs) { @@ -195,103 +377,174 @@ continue; } prevofs = ofs; - - if (jeb->offset + c->sector_size < ofs + sizeof(node)) { - D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node))); + + if (jeb->offset + c->sector_size < ofs + sizeof(*node)) { + D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node), + jeb->offset, c->sector_size, ofs, sizeof(*node))); DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); break; } - err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, (char *)&node); - - if (err) { - D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err)); - return err; - } - if (retlen < sizeof(node)) { - D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen)); - DIRTY_SPACE(retlen); - ofs += retlen; - continue; - } + if (buf_ofs + buf_len < ofs + sizeof(*node)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", + sizeof(struct jffs2_unknown_node), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + } + + node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs]; + + if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { + uint32_t inbuf_ofs = ofs - buf_ofs + 4; + uint32_t scanend; - if (node.magic == JFFS2_EMPTY_BITMASK && node.nodetype == JFFS2_EMPTY_BITMASK) { - D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs)); - err = jffs2_scan_empty(c, jeb, &ofs, &noise); - if (err) return err; + empty_start = ofs; + ofs += 4; + + /* If scanning empty space after only a cleanmarker, don't + bother scanning the whole block */ + if (unlikely(empty_start == jeb->offset + c->cleanmarker_size && + jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len)) + scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs; + else + scanend = buf_len; + + D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs)); + while (inbuf_ofs < scanend) { + if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) + goto emptyends; + + inbuf_ofs+=4; + ofs += 4; + } + /* Ran off end. */ + D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs)); + + if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && + c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size) + return BLK_STATE_CLEANMARKER; + wasempty = 1; + continue; + } else if (wasempty) { + emptyends: + printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs); + DIRTY_SPACE(ofs-empty_start); + wasempty = 0; continue; } - if (ofs == jeb->offset && node.magic == KSAMTIB_CIGAM_2SFFJ) { + if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) { printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs); DIRTY_SPACE(4); ofs += 4; continue; } - if (node.magic == JFFS2_DIRTY_BITMASK) { - D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); + if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { + D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); DIRTY_SPACE(4); ofs += 4; continue; } - if (node.magic == JFFS2_OLD_MAGIC_BITMASK) { + if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) { printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs); printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n"); DIRTY_SPACE(4); ofs += 4; continue; } - if (node.magic != JFFS2_MAGIC_BITMASK) { + if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) { /* OK. We're out of possibilities. Whinge and move on */ - noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, node.magic); + noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", + JFFS2_MAGIC_BITMASK, ofs, + je16_to_cpu(node->magic)); DIRTY_SPACE(4); ofs += 4; continue; } /* We seem to have a node of sorts. Check the CRC */ - nodetype = node.nodetype; - node.nodetype |= JFFS2_NODE_ACCURATE; - hdr_crc = crc32(0, &node, sizeof(node)-4); - node.nodetype = nodetype; - if (hdr_crc != node.hdr_crc) { + crcnode.magic = node->magic; + crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE); + crcnode.totlen = node->totlen; + hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4); + + if (hdr_crc != je32_to_cpu(node->hdr_crc)) { noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n", - ofs, node.magic, node.nodetype, node.totlen, node.hdr_crc, hdr_crc); + ofs, je16_to_cpu(node->magic), + je16_to_cpu(node->nodetype), + je32_to_cpu(node->totlen), + je32_to_cpu(node->hdr_crc), + hdr_crc); DIRTY_SPACE(4); ofs += 4; continue; } - if (ofs + node.totlen > jeb->offset + c->sector_size) { + if (ofs + je32_to_cpu(node->totlen) > + jeb->offset + c->sector_size) { /* Eep. Node goes over the end of the erase block. */ printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", - ofs, node.totlen); + ofs, je32_to_cpu(node->totlen)); printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n"); DIRTY_SPACE(4); ofs += 4; continue; } - switch(node.nodetype | JFFS2_NODE_ACCURATE) { + if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) { + /* Wheee. This is an obsoleted node */ + D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs)); + DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + ofs += PAD(je32_to_cpu(node->totlen)); + continue; + } + + switch(je16_to_cpu(node->nodetype)) { case JFFS2_NODETYPE_INODE: - err = jffs2_scan_inode_node(c, jeb, &ofs); + if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", + sizeof(struct jffs2_raw_inode), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); if (err) return err; + ofs += PAD(je32_to_cpu(node->totlen)); break; case JFFS2_NODETYPE_DIRENT: - err = jffs2_scan_dirent_node(c, jeb, &ofs); + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); if (err) return err; + ofs += PAD(je32_to_cpu(node->totlen)); break; case JFFS2_NODETYPE_CLEANMARKER: - if (node.totlen != sizeof(struct jffs2_unknown_node)) { + D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); + if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", - ofs, node.totlen, sizeof(struct jffs2_unknown_node)); + ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); + ofs += PAD(sizeof(struct jffs2_unknown_node)); } else if (jeb->first_node) { printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset); DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); ofs += PAD(sizeof(struct jffs2_unknown_node)); - continue; } else { struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { @@ -300,98 +553,80 @@ } marker_ref->next_in_ino = NULL; marker_ref->next_phys = NULL; - marker_ref->flash_offset = ofs; - marker_ref->totlen = sizeof(struct jffs2_unknown_node); + marker_ref->flash_offset = ofs | REF_NORMAL; + marker_ref->__totlen = c->cleanmarker_size; jeb->first_node = jeb->last_node = marker_ref; - USED_SPACE(PAD(sizeof(struct jffs2_unknown_node))); + USED_SPACE(PAD(c->cleanmarker_size)); + ofs += PAD(c->cleanmarker_size); } - ofs += PAD(sizeof(struct jffs2_unknown_node)); + break; + + case JFFS2_NODETYPE_PADDING: + DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + ofs += PAD(je32_to_cpu(node->totlen)); break; default: - switch (node.nodetype & JFFS2_COMPAT_MASK) { + switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { case JFFS2_FEATURE_ROCOMPAT: - printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); + printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); c->flags |= JFFS2_SB_FLAG_RO; - if (!(OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)) + if (!(jffs2_is_readonly(c))) return -EROFS; - DIRTY_SPACE(PAD(node.totlen)); - ofs += PAD(node.totlen); - continue; + DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + ofs += PAD(je32_to_cpu(node->totlen)); + break; case JFFS2_FEATURE_INCOMPAT: - printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); + printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); return -EINVAL; case JFFS2_FEATURE_RWCOMPAT_DELETE: - printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); - DIRTY_SPACE(PAD(node.totlen)); - ofs += PAD(node.totlen); + D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); + DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + ofs += PAD(je32_to_cpu(node->totlen)); break; case JFFS2_FEATURE_RWCOMPAT_COPY: - printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); - USED_SPACE(PAD(node.totlen)); - ofs += PAD(node.totlen); + D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); + USED_SPACE(PAD(je32_to_cpu(node->totlen))); + ofs += PAD(je32_to_cpu(node->totlen)); break; } } } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, - jeb->free_size, jeb->dirty_size, jeb->used_size)); - return 0; -} -/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */ -static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *startofs, int *noise) -{ - __u32 *buf; - __u32 scanlen = (jeb->offset + c->sector_size) - *startofs; - __u32 curofs = *startofs; - - buf = kmalloc(min((__u32)PAGE_SIZE, scanlen), GFP_KERNEL); - if (!buf) { - printk(KERN_WARNING "Scan buffer allocation failed\n"); - return -ENOMEM; - } - while(scanlen) { - ssize_t retlen; - int ret, i; - - ret = c->mtd->read(c->mtd, curofs, min((__u32)PAGE_SIZE, scanlen), &retlen, (char *)buf); - if(ret) { - D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((__u32)PAGE_SIZE, scanlen), curofs, ret)); - kfree(buf); - return ret; - } - if (retlen < 4) { - D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n")); - kfree(buf); - return -EIO; - } - for (i=0; i<(retlen / 4); i++) { - if (buf[i] != 0xffffffff) { - curofs += i*4; - - noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]); - DIRTY_SPACE(curofs - (*startofs)); - *startofs = curofs; - kfree(buf); - return 0; - } - } - scanlen -= retlen&~3; - curofs += retlen&~3; + + D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, + jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); + + /* mark_node_obsolete can add to wasted !! */ + if (jeb->wasted_size) { + jeb->dirty_size += jeb->wasted_size; + c->dirty_size += jeb->wasted_size; + c->wasted_size -= jeb->wasted_size; + jeb->wasted_size = 0; } - D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs)); - kfree(buf); - *startofs = curofs; - return 0; + if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size + && (!jeb->first_node || jeb->first_node->next_in_ino) ) + return BLK_STATE_CLEANMARKER; + + /* move blocks with max 4 byte dirty space to cleanlist */ + else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { + c->dirty_size -= jeb->dirty_size; + c->wasted_size += jeb->dirty_size; + jeb->wasted_size += jeb->dirty_size; + jeb->dirty_size = 0; + return BLK_STATE_CLEAN; + } else if (jeb->used_size || jeb->unchecked_size) + return BLK_STATE_PARTDIRTY; + else + return BLK_STATE_ALLDIRTY; } -static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, __u32 ino) +static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ic; @@ -399,137 +634,77 @@ if (ic) return ic; + if (ino > c->highest_ino) + c->highest_ino = ino; + ic = jffs2_alloc_inode_cache(); if (!ic) { printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n"); return NULL; } memset(ic, 0, sizeof(*ic)); - ic->scan = kmalloc(sizeof(struct jffs2_scan_info), GFP_KERNEL); - if (!ic->scan) { - printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed\n"); - jffs2_free_inode_cache(ic); - return NULL; - } - memset(ic->scan, 0, sizeof(*ic->scan)); + ic->ino = ino; ic->nodes = (void *)ic; jffs2_add_ino_cache(c, ic); if (ino == 1) - ic->nlink=1; + ic->nlink = 1; return ic; } -static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs) +static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_inode *ri, uint32_t ofs) { struct jffs2_raw_node_ref *raw; - struct jffs2_full_dnode *fn; - struct jffs2_tmp_dnode_info *tn, **tn_list; struct jffs2_inode_cache *ic; - struct jffs2_raw_inode ri; - __u32 crc; - __u16 oldnodetype; - int ret; - ssize_t retlen; + uint32_t ino = je32_to_cpu(ri->ino); - D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs)); + D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); - ret = c->mtd->read(c->mtd, *ofs, sizeof(ri), &retlen, (char *)&ri); - if (ret) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret); - return ret; - } - if (retlen != sizeof(ri)) { - printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", - retlen, *ofs, sizeof(ri)); - return -EIO; - } - - /* We sort of assume that the node was accurate when it was - first written to the medium :) */ - oldnodetype = ri.nodetype; - ri.nodetype |= JFFS2_NODE_ACCURATE; - crc = crc32(0, &ri, sizeof(ri)-8); - ri.nodetype = oldnodetype; - - if(crc != ri.node_crc) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - *ofs, ri.node_crc, crc); - /* FIXME: Why do we believe totlen? */ - DIRTY_SPACE(4); - *ofs += 4; - return 0; - } - /* There was a bug where we wrote hole nodes out with csize/dsize - swapped. Deal with it */ - if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) { - ri.dsize = ri.csize; - ri.csize = 0; - } - - if (ri.csize) { - /* Check data CRC too */ - unsigned char *dbuf; - __u32 crc; - - dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); - if (!dbuf) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n"); - return -ENOMEM; - } - ret = c->mtd->read(c->mtd, *ofs+sizeof(ri), ri.csize, &retlen, dbuf); - if (ret) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret); - kfree(dbuf); - return ret; - } - if (retlen != ri.csize) { - printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", - retlen, *ofs+ sizeof(ri), ri.csize); - kfree(dbuf); - return -EIO; - } - crc = crc32(0, dbuf, ri.csize); - kfree(dbuf); - if (crc != ri.data_crc) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - *ofs, ri.data_crc, crc); - DIRTY_SPACE(PAD(ri.totlen)); - *ofs += PAD(ri.totlen); - return 0; - } - } + /* We do very little here now. Just check the ino# to which we should attribute + this node; we can do all the CRC checking etc. later. There's a tradeoff here -- + we used to scan the flash once only, reading everything we want from it into + memory, then building all our in-core data structures and freeing the extra + information. Now we allow the first part of the mount to complete a lot quicker, + but we have to go _back_ to the flash in order to finish the CRC checking, etc. + Which means that the _full_ amount of time to get to proper write mode with GC + operational may actually be _longer_ than before. Sucks to be me. */ - /* Wheee. It worked */ raw = jffs2_alloc_raw_node_ref(); if (!raw) { printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n"); return -ENOMEM; } - tn = jffs2_alloc_tmp_dnode_info(); - if (!tn) { - jffs2_free_raw_node_ref(raw); - return -ENOMEM; - } - fn = jffs2_alloc_full_dnode(); - if (!fn) { - jffs2_free_tmp_dnode_info(tn); - jffs2_free_raw_node_ref(raw); - return -ENOMEM; - } - ic = jffs2_scan_make_ino_cache(c, ri.ino); + + ic = jffs2_get_ino_cache(c, ino); if (!ic) { - jffs2_free_full_dnode(fn); - jffs2_free_tmp_dnode_info(tn); - jffs2_free_raw_node_ref(raw); - return -ENOMEM; + /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the + first node we found for this inode. Do a CRC check to protect against the former + case */ + uint32_t crc = crc32(0, ri, sizeof(*ri)-8); + + if (crc != je32_to_cpu(ri->node_crc)) { + printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ofs, je32_to_cpu(ri->node_crc), crc); + /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ + DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen))); + jffs2_free_raw_node_ref(raw); + return 0; + } + ic = jffs2_scan_make_ino_cache(c, ino); + if (!ic) { + jffs2_free_raw_node_ref(raw); + return -ENOMEM; + } } - /* Build the data structures and file them for later */ - raw->flash_offset = *ofs; - raw->totlen = PAD(ri.totlen); + /* Wheee. It worked */ + + raw->flash_offset = ofs | REF_UNCHECKED; + raw->__totlen = PAD(je32_to_cpu(ri->totlen)); raw->next_phys = NULL; raw->next_in_ino = ic->nodes; + ic->nodes = raw; if (!jeb->first_node) jeb->first_node = raw; @@ -538,134 +713,56 @@ jeb->last_node = raw; D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", - ri.ino, ri.version, ri.offset, ri.offset+ri.dsize)); + je32_to_cpu(ri->ino), je32_to_cpu(ri->version), + je32_to_cpu(ri->offset), + je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize))); - pseudo_random += ri.version; + pseudo_random += je32_to_cpu(ri->version); - for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) { - if ((*tn_list)->version < ri.version) - continue; - if ((*tn_list)->version > ri.version) - break; - /* Wheee. We've found another instance of the same version number. - We should obsolete one of them. - */ - D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3)); - if (!jeb->used_size) { - D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n", - jeb->offset, raw->flash_offset & ~3)); - ri.nodetype &= ~JFFS2_NODE_ACCURATE; - /* Perhaps we could also mark it as such on the medium. Maybe later */ - } - break; - } - - if (ri.nodetype & JFFS2_NODE_ACCURATE) { - memset(fn,0,sizeof(*fn)); - - fn->ofs = ri.offset; - fn->size = ri.dsize; - fn->frags = 0; - fn->raw = raw; - - tn->next = NULL; - tn->fn = fn; - tn->version = ri.version; - - USED_SPACE(PAD(ri.totlen)); - jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes); - /* Make sure the one we just added is the _last_ in the list - with this version number, so the older ones get obsoleted */ - while (tn->next && tn->next->version == tn->version) { - - D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n", - fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version)); - - if(tn->fn != fn) - BUG(); - tn->fn = tn->next->fn; - tn->next->fn = fn; - tn = tn->next; - } - } else { - jffs2_free_full_dnode(fn); - jffs2_free_tmp_dnode_info(tn); - raw->flash_offset |= 1; - DIRTY_SPACE(PAD(ri.totlen)); - } - *ofs += PAD(ri.totlen); + UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); return 0; } -static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs) +static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_dirent *rd, uint32_t ofs) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; - struct jffs2_raw_dirent rd; - __u16 oldnodetype; - int ret; - __u32 crc; - ssize_t retlen; + uint32_t crc; - D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs)); + D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs)); - ret = c->mtd->read(c->mtd, *ofs, sizeof(rd), &retlen, (char *)&rd); - if (ret) { - printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret); - return ret; - } - if (retlen != sizeof(rd)) { - printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", - retlen, *ofs, sizeof(rd)); - return -EIO; - } - - /* We sort of assume that the node was accurate when it was - first written to the medium :) */ - oldnodetype = rd.nodetype; - rd.nodetype |= JFFS2_NODE_ACCURATE; - crc = crc32(0, &rd, sizeof(rd)-8); - rd.nodetype = oldnodetype; + /* We don't get here unless the node is still valid, so we don't have to + mask in the ACCURATE bit any more. */ + crc = crc32(0, rd, sizeof(*rd)-8); - if (crc != rd.node_crc) { + if (crc != je32_to_cpu(rd->node_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - *ofs, rd.node_crc, crc); - /* FIXME: Why do we believe totlen? */ - DIRTY_SPACE(4); - *ofs += 4; + ofs, je32_to_cpu(rd->node_crc), crc); + /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ + DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); return 0; } - pseudo_random += rd.version; + pseudo_random += je32_to_cpu(rd->version); - fd = jffs2_alloc_full_dirent(rd.nsize+1); + fd = jffs2_alloc_full_dirent(rd->nsize+1); if (!fd) { return -ENOMEM; -} - ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]); - if (ret) { - jffs2_free_full_dirent(fd); - printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", - *ofs + sizeof(rd), ret); - return ret; } - if (retlen != rd.nsize) { - jffs2_free_full_dirent(fd); - printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", - retlen, *ofs + sizeof(rd), rd.nsize); - return -EIO; - } - crc = crc32(0, fd->name, rd.nsize); - if (crc != rd.name_crc) { + memcpy(&fd->name, rd->name, rd->nsize); + fd->name[rd->nsize] = 0; + + crc = crc32(0, fd->name, rd->nsize); + if (crc != je32_to_cpu(rd->name_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - *ofs, rd.name_crc, crc); - fd->name[rd.nsize]=0; - D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino)); + ofs, je32_to_cpu(rd->name_crc), crc); + D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ - DIRTY_SPACE(PAD(rd.totlen)); - *ofs += PAD(rd.totlen); + /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */ + DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); return 0; } raw = jffs2_alloc_raw_node_ref(); @@ -674,15 +771,15 @@ printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); return -ENOMEM; } - ic = jffs2_scan_make_ino_cache(c, rd.pino); + ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); jffs2_free_raw_node_ref(raw); return -ENOMEM; } - raw->totlen = PAD(rd.totlen); - raw->flash_offset = *ofs; + raw->__totlen = PAD(je32_to_cpu(rd->totlen)); + raw->flash_offset = ofs | REF_PRISTINE; raw->next_phys = NULL; raw->next_in_ino = ic->nodes; ic->nodes = raw; @@ -692,24 +789,15 @@ jeb->last_node->next_phys = raw; jeb->last_node = raw; - if (rd.nodetype & JFFS2_NODE_ACCURATE) { - fd->raw = raw; - fd->next = NULL; - fd->version = rd.version; - fd->ino = rd.ino; - fd->name[rd.nsize]=0; - fd->nhash = full_name_hash(fd->name, rd.nsize); - fd->type = rd.type; - - USED_SPACE(PAD(rd.totlen)); - jffs2_add_fd_to_list(c, fd, &ic->scan->dents); - } else { - raw->flash_offset |= 1; - jffs2_free_full_dirent(fd); + fd->raw = raw; + fd->next = NULL; + fd->version = je32_to_cpu(rd->version); + fd->ino = je32_to_cpu(rd->ino); + fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->type = rd->type; + USED_SPACE(PAD(je32_to_cpu(rd->totlen))); + jffs2_add_fd_to_list(c, fd, &ic->scan_dents); - DIRTY_SPACE(PAD(rd.totlen)); - } - *ofs += PAD(rd.totlen); return 0; } @@ -731,26 +819,90 @@ struct list_head *n = head->next; list_del(head); - while(count--) + while(count--) { n = n->next; + } list_add(head, n); } -static void jffs2_rotate_lists(struct jffs2_sb_info *c) +void jffs2_rotate_lists(struct jffs2_sb_info *c) { uint32_t x; + uint32_t rotateby; x = count_list(&c->clean_list); - if (x) - rotate_list((&c->clean_list), pseudo_random % x); + if (x) { + rotateby = pseudo_random % x; + D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby)); + + rotate_list((&c->clean_list), rotateby); + + D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n", + list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty clean_list\n")); + } + + x = count_list(&c->very_dirty_list); + if (x) { + rotateby = pseudo_random % x; + D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby)); + + rotate_list((&c->very_dirty_list), rotateby); + + D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n", + list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n")); + } x = count_list(&c->dirty_list); - if (x) - rotate_list((&c->dirty_list), pseudo_random % x); + if (x) { + rotateby = pseudo_random % x; + D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby)); + + rotate_list((&c->dirty_list), rotateby); - if (c->nr_erasing_blocks) - rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks); + D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n", + list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n")); + } + + x = count_list(&c->erasable_list); + if (x) { + rotateby = pseudo_random % x; + D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby)); - if (c->nr_free_blocks) /* Not that it should ever be zero */ - rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks); + rotate_list((&c->erasable_list), rotateby); + + D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n", + list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n")); + } + + if (c->nr_erasing_blocks) { + rotateby = pseudo_random % c->nr_erasing_blocks; + D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby)); + + rotate_list((&c->erase_pending_list), rotateby); + + D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n", + list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n")); + } + + if (c->nr_free_blocks) { + rotateby = pseudo_random % c->nr_free_blocks; + D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby)); + + rotate_list((&c->free_list), rotateby); + + D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n", + list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset)); + } else { + D1(printk(KERN_DEBUG "Not rotating empty free_list\n")); + } } diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c --- a/fs/jffs2/super.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/super.c Thu Dec 4 16:24:25 2003 @@ -1,291 +1,257 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: super.c,v 1.48.2.3 2002/10/11 09:04:44 dwmw2 Exp $ + * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $ * */ #include #include #include -#include #include #include #include #include +#include #include #include #include -#include +#include +#include #include "nodelist.h" -#ifndef MTD_BLOCK_MAJOR -#define MTD_BLOCK_MAJOR 31 -#endif +static void jffs2_put_super(struct super_block *); + +static kmem_cache_t *jffs2_inode_cachep; + +static struct inode *jffs2_alloc_inode(struct super_block *sb) +{ + struct jffs2_inode_info *ei; + ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL); + if (!ei) + return NULL; + return &ei->vfs_inode; +} + +static void jffs2_destroy_inode(struct inode *inode) +{ + kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); +} + +static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +{ + struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; -extern void jffs2_read_inode (struct inode *); -void jffs2_put_super (struct super_block *); -void jffs2_write_super (struct super_block *); -static int jffs2_statfs (struct super_block *, struct statfs *); -int jffs2_remount_fs (struct super_block *, int *, char *); -extern void jffs2_clear_inode (struct inode *); + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + init_MUTEX_LOCKED(&ei->sem); + inode_init_once(&ei->vfs_inode); + } +} static struct super_operations jffs2_super_operations = { - read_inode: jffs2_read_inode, -// delete_inode: jffs2_delete_inode, - put_super: jffs2_put_super, - write_super: jffs2_write_super, - statfs: jffs2_statfs, - remount_fs: jffs2_remount_fs, - clear_inode: jffs2_clear_inode + .alloc_inode = jffs2_alloc_inode, + .destroy_inode =jffs2_destroy_inode, + .read_inode = jffs2_read_inode, + .put_super = jffs2_put_super, + .write_super = jffs2_write_super, + .statfs = jffs2_statfs, + .remount_fs = jffs2_remount_fs, + .clear_inode = jffs2_clear_inode, + .dirty_inode = jffs2_dirty_inode, }; -static int jffs2_statfs(struct super_block *sb, struct statfs *buf) +static int jffs2_sb_compare(struct super_block *sb, void *data) { + struct jffs2_sb_info *p = data; struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - unsigned long avail; - - buf->f_type = JFFS2_SUPER_MAGIC; - buf->f_bsize = 1 << PAGE_SHIFT; - buf->f_blocks = c->flash_size >> PAGE_SHIFT; - buf->f_files = 0; - buf->f_ffree = 0; - buf->f_namelen = JFFS2_MAX_NAME_LEN; - - spin_lock_bh(&c->erase_completion_lock); - - avail = c->dirty_size + c->free_size; - if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE) - avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE; - else - avail = 0; - - buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; - -#if CONFIG_JFFS2_FS_DEBUG > 0 - printk(KERN_DEBUG "STATFS:\n"); - printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); - printk(KERN_DEBUG "used_size: %08x\n", c->used_size); - printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); - printk(KERN_DEBUG "free_size: %08x\n", c->free_size); - printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); - printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); - printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); - if (c->nextblock) { - printk(KERN_DEBUG "nextblock: 0x%08x\n", c->nextblock->offset); + /* The superblocks are considered to be equivalent if the underlying MTD + device is the same one */ + if (c->mtd == p->mtd) { + D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name)); + return 1; } else { - printk(KERN_DEBUG "nextblock: NULL\n"); + D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n", + c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name)); + return 0; } - if (c->gcblock) { - printk(KERN_DEBUG "gcblock: 0x%08x\n", c->gcblock->offset); - } else { - printk(KERN_DEBUG "gcblock: NULL\n"); - } - if (list_empty(&c->clean_list)) { - printk(KERN_DEBUG "clean_list: empty\n"); - } else { - struct list_head *this; +} - list_for_each(this, &c->clean_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "clean_list: %08x\n", jeb->offset); - } - } - if (list_empty(&c->dirty_list)) { - printk(KERN_DEBUG "dirty_list: empty\n"); - } else { - struct list_head *this; +static int jffs2_sb_set(struct super_block *sb, void *data) +{ + struct jffs2_sb_info *p = data; - list_for_each(this, &c->dirty_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "dirty_list: %08x\n", jeb->offset); - } - } - if (list_empty(&c->erasing_list)) { - printk(KERN_DEBUG "erasing_list: empty\n"); - } else { - struct list_head *this; + /* For persistence of NFS exports etc. we use the same s_dev + each time we mount the device, don't just use an anonymous + device */ + sb->s_fs_info = p; + p->os_priv = sb; + sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index); - list_for_each(this, &c->erasing_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erasing_list: %08x\n", jeb->offset); - } - } - if (list_empty(&c->erase_pending_list)) { - printk(KERN_DEBUG "erase_pending_list: empty\n"); - } else { - struct list_head *this; + return 0; +} - list_for_each(this, &c->erase_pending_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erase_pending_list: %08x\n", jeb->offset); - } - } - if (list_empty(&c->free_list)) { - printk(KERN_DEBUG "free_list: empty\n"); - } else { - struct list_head *this; +static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct mtd_info *mtd) +{ + struct super_block *sb; + struct jffs2_sb_info *c; + int ret; - list_for_each(this, &c->free_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "free_list: %08x\n", jeb->offset); - } - } - if (list_empty(&c->bad_list)) { - printk(KERN_DEBUG "bad_list: empty\n"); - } else { - struct list_head *this; + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + memset(c, 0, sizeof(*c)); + c->mtd = mtd; - list_for_each(this, &c->bad_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "bad_list: %08x\n", jeb->offset); - } + sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); + + if (IS_ERR(sb)) + goto out_put; + + if (sb->s_root) { + /* New mountpoint for JFFS2 which is already mounted */ + D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", + mtd->index, mtd->name)); + goto out_put; } - if (list_empty(&c->bad_used_list)) { - printk(KERN_DEBUG "bad_used_list: empty\n"); - } else { - struct list_head *this; - list_for_each(this, &c->bad_used_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "bad_used_list: %08x\n", jeb->offset); - } + D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n", + mtd->index, mtd->name)); + + sb->s_op = &jffs2_super_operations; + + ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0); + + if (ret) { + /* Failure case... */ + up_write(&sb->s_umount); + deactivate_super(sb); + return ERR_PTR(ret); } -#endif /* CONFIG_JFFS2_FS_DEBUG */ - spin_unlock_bh(&c->erase_completion_lock); + sb->s_flags |= MS_ACTIVE; + return sb; + out_put: + kfree(c); + put_mtd_device(mtd); - return 0; + return sb; } -static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent) +static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, int mtdnr) { - struct jffs2_sb_info *c; - struct inode *root_i; - int i; - - D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev))); + struct mtd_info *mtd; - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { - if (!silent) - printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev)); - return NULL; + mtd = get_mtd_device(NULL, mtdnr); + if (!mtd) { + D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); + return ERR_PTR(-EINVAL); } - c = JFFS2_SB_INFO(sb); - memset(c, 0, sizeof(*c)); - - c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); - if (!c->mtd) { - D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev))); - return NULL; - } - c->sector_size = c->mtd->erasesize; - c->free_size = c->flash_size = c->mtd->size; - c->nr_blocks = c->mtd->size / c->mtd->erasesize; - c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); - if (!c->blocks) - goto out_mtd; - for (i=0; inr_blocks; i++) { - INIT_LIST_HEAD(&c->blocks[i].list); - c->blocks[i].offset = i * c->sector_size; - c->blocks[i].free_size = c->sector_size; - c->blocks[i].dirty_size = 0; - c->blocks[i].used_size = 0; - c->blocks[i].first_node = NULL; - c->blocks[i].last_node = NULL; - } - - spin_lock_init(&c->nodelist_lock); - init_MUTEX(&c->alloc_sem); - init_waitqueue_head(&c->erase_wait); - spin_lock_init(&c->erase_completion_lock); - spin_lock_init(&c->inocache_lock); - - INIT_LIST_HEAD(&c->clean_list); - INIT_LIST_HEAD(&c->dirty_list); - INIT_LIST_HEAD(&c->erasing_list); - INIT_LIST_HEAD(&c->erase_pending_list); - INIT_LIST_HEAD(&c->erase_complete_list); - INIT_LIST_HEAD(&c->free_list); - INIT_LIST_HEAD(&c->bad_list); - INIT_LIST_HEAD(&c->bad_used_list); - c->highest_ino = 1; - - if (jffs2_build_filesystem(c)) { - D1(printk(KERN_DEBUG "build_fs failed\n")); - goto out_nodes; + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); +} + +static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + int err; + struct nameidata nd; + int mtdnr; + + if (!dev_name) + return ERR_PTR(-EINVAL); + + D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); + + /* The preferred way of mounting in future; especially when + CONFIG_BLK_DEV is implemented - we specify the underlying + MTD device by number or by name, so that we don't require + block device support to be present in the kernel. */ + + /* FIXME: How to do the root fs this way? */ + + if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { + /* Probably mounting without the blkdev crap */ + if (dev_name[3] == ':') { + struct mtd_info *mtd; + + /* Mount by MTD device name */ + D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); + for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { + mtd = get_mtd_device(NULL, mtdnr); + if (mtd) { + if (!strcmp(mtd->name, dev_name+4)) + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); + put_mtd_device(mtd); + } + } + printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4); + } else if (isdigit(dev_name[3])) { + /* Mount by MTD device number name */ + char *endptr; + + mtdnr = simple_strtoul(dev_name+3, &endptr, 0); + if (!*endptr) { + /* It was a valid number */ + D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + } + } } - sb->s_op = &jffs2_super_operations; + /* Try the old way - the hack where we allowed users to mount + /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ + + err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); - D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); - root_i = iget(sb, 1); - if (is_bad_inode(root_i)) { - D1(printk(KERN_WARNING "get root inode failed\n")); - goto out_nodes; + D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n", + err, nd.dentry->d_inode)); + + if (err) + return ERR_PTR(err); + + err = -EINVAL; + + if (!S_ISBLK(nd.dentry->d_inode->i_mode)) + goto out; + + if (nd.mnt->mnt_flags & MNT_NODEV) { + err = -EACCES; + goto out; } - D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n")); - sb->s_root = d_alloc_root(root_i); - if (!sb->s_root) - goto out_root_i; + if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { + if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */ + printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", + dev_name); + goto out; + } -#if LINUX_VERSION_CODE >= 0x20403 - sb->s_maxbytes = 0xFFFFFFFF; -#endif - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = JFFS2_SUPER_MAGIC; - if (!(sb->s_flags & MS_RDONLY)) - jffs2_start_garbage_collect_thread(c); - return sb; + mtdnr = iminor(nd.dentry->d_inode); + path_release(&nd); - out_root_i: - iput(root_i); - out_nodes: - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - kfree(c->blocks); - out_mtd: - put_mtd_device(c->mtd); - return NULL; + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + +out: + path_release(&nd); + return ERR_PTR(err); } -void jffs2_put_super (struct super_block *sb) +static void jffs2_put_super (struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); @@ -293,74 +259,53 @@ if (!(sb->s_flags & MS_RDONLY)) jffs2_stop_garbage_collect_thread(c); + down(&c->alloc_sem); + jffs2_flush_wbuf_pad(c); + up(&c->alloc_sem); jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); kfree(c->blocks); + jffs2_nand_flash_cleanup(c); + kfree(c->inocache_list); if (c->mtd->sync) c->mtd->sync(c->mtd); - put_mtd_device(c->mtd); - - D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); -} - -int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) -{ - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - - if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY)) - return -EROFS; - /* We stop if it was running, then restart if it needs to. - This also catches the case where it was stopped and this - is just a remount to restart it */ - if (!(sb->s_flags & MS_RDONLY)) - jffs2_stop_garbage_collect_thread(c); - - if (!(*flags & MS_RDONLY)) - jffs2_start_garbage_collect_thread(c); - - sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY); - - return 0; + D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); } -void jffs2_write_super (struct super_block *sb) +static void jffs2_kill_sb(struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - sb->s_dirt = 0; - - if (sb->s_flags & MS_RDONLY) - return; - - jffs2_garbage_collect_trigger(c); - jffs2_erase_pending_blocks(c); - jffs2_mark_erased_blocks(c); + generic_shutdown_super(sb); + put_mtd_device(c->mtd); + kfree(c); } - -static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super); +static struct file_system_type jffs2_fs_type = { + .owner = THIS_MODULE, + .name = "jffs2", + .get_sb = jffs2_get_sb, + .kill_sb = jffs2_kill_sb, +}; static int __init init_jffs2_fs(void) { int ret; - printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n"); - -#ifdef JFFS2_OUT_OF_KERNEL - /* sanity checks. Could we do these at compile time? */ - if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) { - printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n", - sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u)); - return -EIO; - } - - if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) { - printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n", - sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u)); - return -EIO; - } + printk(KERN_INFO "JFFS2 version 2.2." +#ifdef CONFIG_FS_JFFS2_NAND + " (NAND)" #endif + " (C) 2001-2003 Red Hat, Inc.\n"); + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), + 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + jffs2_i_init_once, NULL); + if (!jffs2_inode_cachep) { + printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); + return -ENOMEM; + } ret = jffs2_zlib_init(); if (ret) { printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n"); @@ -388,9 +333,10 @@ static void __exit exit_jffs2_fs(void) { + unregister_filesystem(&jffs2_fs_type); jffs2_destroy_slab_caches(); jffs2_zlib_exit(); - unregister_filesystem(&jffs2_fs_type); + kmem_cache_destroy(jffs2_inode_cachep); } module_init(init_jffs2_fs); diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c --- a/fs/jffs2/symlink.c Thu Dec 4 16:24:26 2003 +++ b/fs/jffs2/symlink.c Thu Dec 4 16:24:26 2003 @@ -3,35 +3,11 @@ * * Copyright (C) 2001, 2002 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $ + * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $ * */ @@ -39,7 +15,6 @@ #include #include #include -#include #include "nodelist.h" int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen); @@ -47,45 +22,17 @@ struct inode_operations jffs2_symlink_inode_operations = { - readlink: jffs2_readlink, - follow_link: jffs2_follow_link, - setattr: jffs2_setattr + .readlink = jffs2_readlink, + .follow_link = jffs2_follow_link, + .setattr = jffs2_setattr }; -static char *jffs2_getlink(struct dentry *dentry) -{ - struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); - char *buf; - int ret; - - down(&f->sem); - if (!f->metadata) { - up(&f->sem); - printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino); - return ERR_PTR(-EINVAL); - } - buf = kmalloc(f->metadata->size+1, GFP_USER); - if (!buf) { - up(&f->sem); - return ERR_PTR(-ENOMEM); - } - buf[f->metadata->size]=0; - - ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size); - up(&f->sem); - if (ret) { - kfree(buf); - return ERR_PTR(ret); - } - return buf; - -} int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen) { unsigned char *kbuf; int ret; - kbuf = jffs2_getlink(dentry); + kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); if (IS_ERR(kbuf)) return PTR_ERR(kbuf); @@ -99,7 +46,7 @@ unsigned char *buf; int ret; - buf = jffs2_getlink(dentry); + buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); if (IS_ERR(buf)) return PTR_ERR(buf); diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c --- a/fs/jffs2/write.c Thu Dec 4 16:24:25 2003 +++ b/fs/jffs2/write.c Thu Dec 4 16:24:25 2003 @@ -1,154 +1,70 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: write.c,v 1.30.2.1 2002/08/08 08:36:31 dwmw2 Exp $ + * $Id: write.c,v 1.78 2003/11/24 16:07:01 dwmw2 Exp $ * */ #include #include -#include +#include +#include +#include #include #include "nodelist.h" -#include "crc32.h" -/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, - fill in the raw_inode while you're at it. */ -struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) + +int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) { - struct inode *inode; - struct super_block *sb = dir_i->i_sb; struct jffs2_inode_cache *ic; - struct jffs2_sb_info *c; - struct jffs2_inode_info *f; - - D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); - - c = JFFS2_SB_INFO(sb); - memset(ri, 0, sizeof(*ri)); ic = jffs2_alloc_inode_cache(); if (!ic) { - return ERR_PTR(-ENOMEM); - } - memset(ic, 0, sizeof(*ic)); - - inode = new_inode(sb); - - if (!inode) { - jffs2_free_inode_cache(ic); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } - /* Alloc jffs2_inode_info when that's split in 2.5 */ + memset(ic, 0, sizeof(*ic)); - f = JFFS2_INODE_INFO(inode); - memset(f, 0, sizeof(*f)); init_MUTEX_LOCKED(&f->sem); f->inocache = ic; - inode->i_nlink = f->inocache->nlink = 1; + f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; - f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino; - D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino)); - jffs2_add_ino_cache(c, f->inocache); - - ri->magic = JFFS2_MAGIC_BITMASK; - ri->nodetype = JFFS2_NODETYPE_INODE; - ri->totlen = PAD(sizeof(*ri)); - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); - ri->mode = mode; - f->highest_version = ri->version = 1; - ri->uid = current->fsuid; - if (dir_i->i_mode & S_ISGID) { - ri->gid = dir_i->i_gid; - if (S_ISDIR(mode)) - ri->mode |= S_ISGID; - } else { - ri->gid = current->fsgid; - } - inode->i_mode = ri->mode; - inode->i_gid = ri->gid; - inode->i_uid = ri->uid; - inode->i_atime = inode->i_ctime = inode->i_mtime = - ri->atime = ri->mtime = ri->ctime = CURRENT_TIME; - inode->i_blksize = PAGE_SIZE; - inode->i_blocks = 0; - inode->i_size = 0; + f->inocache->ino = ++c->highest_ino; + f->inocache->state = INO_STATE_PRESENT; - insert_inode_hash(inode); + ri->ino = cpu_to_je32(f->inocache->ino); - return inode; -} - -/* This ought to be in core MTD code. All registered MTD devices - without writev should have this put in place. Bug the MTD - maintainer */ -static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) -{ - unsigned long i; - size_t totlen = 0, thislen; - int ret = 0; + D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); + jffs2_add_ino_cache(c, f->inocache); - for (i=0; iwrite(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base); - totlen += thislen; - if (ret || thislen != vecs[i].iov_len) - break; - to += vecs[i].iov_len; - } - if (retlen) - *retlen = totlen; - return ret; -} + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri->totlen = cpu_to_je32(PAD(sizeof(*ri))); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); + ri->mode = cpu_to_jemode(mode); + f->highest_version = 1; + ri->version = cpu_to_je32(f->highest_version); -static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) -{ - if (mtd->writev) - return mtd->writev(mtd,vecs,count,to,retlen); - else - return mtd_fake_writev(mtd, vecs, count, to, retlen); + return 0; } -static void writecheck(struct mtd_info *mtd, __u32 ofs) +#if CONFIG_JFFS2_FS_DEBUG > 0 +static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) { unsigned char buf[16]; - ssize_t retlen; + size_t retlen; int ret, i; - ret = mtd->read(mtd, ofs, 16, &retlen, buf); - if (ret && retlen != 16) { - D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen)); + ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); + if (ret || (retlen != 16)) { + D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); return; } ret = 0; @@ -157,32 +73,31 @@ ret = 1; } if (ret) { - printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs); + printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs); printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ofs, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); } } +#endif - - /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, write it to the flash, link it into the existing inode/fragment list */ -struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen) +struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_raw_node_ref *raw; struct jffs2_full_dnode *fn; - ssize_t retlen; + size_t retlen; struct iovec vecs[2]; int ret; + int retried = 0; + unsigned long cnt = 2; - D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { + D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n"); BUG(); } @@ -192,10 +107,10 @@ vecs[1].iov_base = (unsigned char *)data; vecs[1].iov_len = datalen; - writecheck(c->mtd, flash_ofs); + D1(writecheck(c, flash_ofs)); - if (ri->totlen != sizeof(*ri) + datalen) { - printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen); + if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { + printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); } raw = jffs2_alloc_raw_node_ref(); if (!raw) @@ -206,19 +121,28 @@ jffs2_free_raw_node_ref(raw); return ERR_PTR(-ENOMEM); } - raw->flash_offset = flash_ofs; - raw->totlen = PAD(ri->totlen); - raw->next_phys = NULL; - fn->ofs = ri->offset; - fn->size = ri->dsize; + fn->ofs = je32_to_cpu(ri->offset); + fn->size = je32_to_cpu(ri->dsize); fn->frags = 0; + + /* check number of valid vecs */ + if (!datalen || !data) + cnt = 1; + retry: fn->raw = raw; - ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen); + raw->flash_offset = flash_ofs; + raw->__totlen = PAD(sizeof(*ri)+datalen); + raw->next_phys = NULL; + + ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, + (alloc_mode==ALLOC_GC)?0:f->inocache->ino); + if (ret || (retlen != sizeof(*ri) + datalen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*ri)+datalen, flash_ofs, ret, retlen); + /* Mark the space as dirtied */ if (retlen) { /* Doesn't belong to any inode */ @@ -229,48 +153,96 @@ seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ - jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1); + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw); jffs2_mark_node_obsolete(c, raw); } else { printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); jffs2_free_raw_node_ref(raw); } + if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { + /* Try to reallocate space and retry */ + uint32_t dummy; + struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; + + retried = 1; + + D1(printk(KERN_DEBUG "Retrying failed write.\n")); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + if (alloc_mode == ALLOC_GC) { + ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); + } else { + /* Locking pain */ + up(&f->sem); + jffs2_complete_reservation(c); + + ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); + down(&f->sem); + } + + if (!ret) { + D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + goto retry; + } + D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(raw); + } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dnode(fn); - if (writelen) - *writelen = retlen; return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - jffs2_add_physical_node_ref(c, raw, retlen, 0); + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + */ + if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { + raw->flash_offset |= REF_PRISTINE; + } else { + raw->flash_offset |= REF_NORMAL; + } + jffs2_add_physical_node_ref(c, raw); /* Link into per-inode list */ raw->next_in_ino = f->inocache->nodes; f->inocache->nodes = raw; - D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen)); - if (writelen) - *writelen = retlen; + D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", + flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), + je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), + je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); + + if (retried) { + ACCT_SANITY_CHECK(c,NULL); + } - f->inocache->nodes = raw; return fn; } -struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen) +struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; - ssize_t retlen; + size_t retlen; struct iovec vecs[2]; + int retried = 0; int ret; - D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc)); - writecheck(c->mtd, flash_ofs); + D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", + je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), + je32_to_cpu(rd->name_crc))); + D1(writecheck(c, flash_ofs)); - D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { + D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); BUG(); } @@ -291,44 +263,414 @@ jffs2_free_raw_node_ref(raw); return ERR_PTR(-ENOMEM); } - raw->flash_offset = flash_ofs; - raw->totlen = PAD(rd->totlen); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - raw->next_phys = NULL; - fd->version = rd->version; - fd->ino = rd->ino; + fd->version = je32_to_cpu(rd->version); + fd->ino = je32_to_cpu(rd->ino); fd->nhash = full_name_hash(name, strlen(name)); fd->type = rd->type; memcpy(fd->name, name, namelen); fd->name[namelen]=0; + + retry: fd->raw = raw; - ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen); - if (ret || (retlen != sizeof(*rd) + namelen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + raw->flash_offset = flash_ofs; + raw->__totlen = PAD(sizeof(*rd)+namelen); + raw->next_phys = NULL; + + ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, + (alloc_mode==ALLOC_GC)?0:fd->ino); + if (ret || (retlen != sizeof(*rd) + namelen)) { + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ - if (retlen) { - jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1); - jffs2_mark_node_obsolete(c, raw); + if (retlen) { + raw->next_in_ino = NULL; + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw); + jffs2_mark_node_obsolete(c, raw); + } else { + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); + jffs2_free_raw_node_ref(raw); + } + if (!retried && (raw = jffs2_alloc_raw_node_ref())) { + /* Try to reallocate space and retry */ + uint32_t dummy; + struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; + + retried = 1; + + D1(printk(KERN_DEBUG "Retrying failed write.\n")); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + if (alloc_mode == ALLOC_GC) { + ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); - jffs2_free_raw_node_ref(raw); + /* Locking pain */ + up(&f->sem); + jffs2_complete_reservation(c); + + ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); + down(&f->sem); } + if (!ret) { + D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + goto retry; + } + D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(raw); + } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dirent(fd); - if (writelen) - *writelen = retlen; return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - jffs2_add_physical_node_ref(c, raw, retlen, 0); - if (writelen) - *writelen = retlen; + raw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, raw); + raw->next_in_ino = f->inocache->nodes; f->inocache->nodes = raw; + + if (retried) { + ACCT_SANITY_CHECK(c,NULL); + } + return fd; +} + +/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that + we don't have to go digging in struct inode or its equivalent. It should set: + mode, uid, gid, (starting)isize, atime, ctime, mtime */ +int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct jffs2_raw_inode *ri, unsigned char *buf, + uint32_t offset, uint32_t writelen, uint32_t *retlen) +{ + int ret = 0; + uint32_t writtenlen = 0; + + D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", + f->inocache->ino, offset, writelen)); + + while(writelen) { + struct jffs2_full_dnode *fn; + unsigned char *comprbuf = NULL; + unsigned char comprtype = JFFS2_COMPR_NONE; + uint32_t phys_ofs, alloclen; + uint32_t datalen, cdatalen; + int retried = 0; + + retry: + D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); + + ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); + break; + } + down(&f->sem); + datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); + cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen); + + comprtype = jffs2_compress(buf, &comprbuf, &datalen, &cdatalen); + + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); + + ri->ino = cpu_to_je32(f->inocache->ino); + ri->version = cpu_to_je32(++f->highest_version); + ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen)); + ri->offset = cpu_to_je32(offset); + ri->csize = cpu_to_je32(cdatalen); + ri->dsize = cpu_to_je32(datalen); + ri->compr = comprtype; + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); + + fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY); + + jffs2_free_comprbuf(comprbuf, buf); + + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); + up(&f->sem); + jffs2_complete_reservation(c); + if (!retried) { + /* Write error to be retried */ + retried = 1; + D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n")); + goto retry; + } + break; + } + ret = jffs2_add_full_dnode_to_inode(c, f, fn); + if (f->metadata) { + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + } + if (ret) { + /* Eep */ + D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + + up(&f->sem); + jffs2_complete_reservation(c); + break; + } + up(&f->sem); + jffs2_complete_reservation(c); + if (!datalen) { + printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); + ret = -EIO; + break; + } + D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); + writtenlen += datalen; + offset += datalen; + writelen -= datalen; + buf += datalen; + } + *retlen = writtenlen; + return ret; +} + +int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen) +{ + struct jffs2_raw_dirent *rd; + struct jffs2_full_dnode *fn; + struct jffs2_full_dirent *fd; + uint32_t alloclen, phys_ofs; + int ret; + + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though + */ + ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); + D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); + if (ret) { + up(&f->sem); + return ret; + } + + ri->data_crc = cpu_to_je32(0); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); + + D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", + jemode_to_cpu(ri->mode))); + + if (IS_ERR(fn)) { + D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); + /* Eeek. Wave bye bye */ + up(&f->sem); + jffs2_complete_reservation(c); + return PTR_ERR(fn); + } + /* No data here. Only a metadata node, which will be + obsoleted by the first data write + */ + f->metadata = fn; + + up(&f->sem); + jffs2_complete_reservation(c); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + + if (ret) { + /* Eep. */ + D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); + return ret; + } + + rd = jffs2_alloc_raw_dirent(); + if (!rd) { + /* Argh. Now we treat it like a normal delete */ + jffs2_complete_reservation(c); + return -ENOMEM; + } + + down(&dir_f->sem); + + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_f->inocache->ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = ri->ino; + rd->mctime = ri->ctime; + rd->nsize = namelen; + rd->type = DT_REG; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); + + jffs2_free_raw_dirent(rd); + + if (IS_ERR(fd)) { + /* dirent failed to write. Delete the inode normally + as if it were the final unlink() */ + jffs2_complete_reservation(c); + up(&dir_f->sem); + return PTR_ERR(fd); + } + + /* Link the fd into the inode's list, obsoleting an old + one if necessary. */ + jffs2_add_fd_to_list(c, fd, &dir_f->dents); + + jffs2_complete_reservation(c); + up(&dir_f->sem); + + return 0; +} + + +int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, + const char *name, int namelen, struct jffs2_inode_info *dead_f) +{ + struct jffs2_raw_dirent *rd; + struct jffs2_full_dirent *fd; + uint32_t alloclen, phys_ofs; + int ret; + + rd = jffs2_alloc_raw_dirent(); + if (!rd) + return -ENOMEM; + + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); + if (ret) { + jffs2_free_raw_dirent(rd); + return ret; + } + + down(&dir_f->sem); + + /* Build a deletion node */ + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_f->inocache->ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(0); + rd->mctime = cpu_to_je32(get_seconds()); + rd->nsize = namelen; + rd->type = DT_UNKNOWN; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); + + jffs2_free_raw_dirent(rd); + + if (IS_ERR(fd)) { + jffs2_complete_reservation(c); + up(&dir_f->sem); + return PTR_ERR(fd); + } + + /* File it. This will mark the old one obsolete. */ + jffs2_add_fd_to_list(c, fd, &dir_f->dents); + + up(&dir_f->sem); + + /* dead_f is NULL if this was a rename not a real unlink */ + /* Also catch the !f->inocache case, where there was a dirent + pointing to an inode which didn't exist. */ + if (dead_f && dead_f->inocache) { + + down(&dead_f->sem); + + while (dead_f->dents) { + /* There can be only deleted ones */ + fd = dead_f->dents; + + dead_f->dents = fd->next; + + if (fd->ino) { + printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", + dead_f->inocache->ino, fd->name, fd->ino); + } else { + D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); + } + jffs2_mark_node_obsolete(c, fd->raw); + jffs2_free_full_dirent(fd); + } + + dead_f->inocache->nlink--; + /* NB: Caller must set inode nlink if appropriate */ + up(&dead_f->sem); + } + + jffs2_complete_reservation(c); + + return 0; +} + + +int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen) +{ + struct jffs2_raw_dirent *rd; + struct jffs2_full_dirent *fd; + uint32_t alloclen, phys_ofs; + int ret; + + rd = jffs2_alloc_raw_dirent(); + if (!rd) + return -ENOMEM; + + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + if (ret) { + jffs2_free_raw_dirent(rd); + return ret; + } + + down(&dir_f->sem); + + /* Build a deletion node */ + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_f->inocache->ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(ino); + rd->mctime = cpu_to_je32(get_seconds()); + rd->nsize = namelen; + + rd->type = type; + + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); + + jffs2_free_raw_dirent(rd); + + if (IS_ERR(fd)) { + jffs2_complete_reservation(c); + up(&dir_f->sem); + return PTR_ERR(fd); + } + + /* File it. This will mark the old one obsolete. */ + jffs2_add_fd_to_list(c, fd, &dir_f->dents); + + jffs2_complete_reservation(c); + up(&dir_f->sem); + + return 0; } diff -Nru a/include/asm-arm/arch-adifcc/adi_evb.h b/include/asm-arm/arch-adifcc/adi_evb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/adi_evb.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,20 @@ +/* + * linux/include/asm/arch-80200fcc/adi_evb.h + * + * ADI 80200EVB evaluation board register/hardware definitions + * + * Author: Deepak Saxena + * + * Copyright (C) 2001 MontaVista Software Inc. + * + * 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. + */ + +#define ADI_EVB_RAMBASE 0xa0000000 +#define ADI_EVB_UART 0x00400000 /* UART */ +#define ADI_EVB_7SEG_1 0x00500000 /* 7-Segment */ + +#define PCIO_BASE 0 diff -Nru a/include/asm-arm/arch-adifcc/brh.h b/include/asm-arm/arch-adifcc/brh.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/brh.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,172 @@ +/* + * inclue/asm-arm/arch-adifcc/brh.h + * + * Register and other defines for BRH board + * + * Author: Deepak Saxena + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 _BRH_H_ +#define _BRH_H_ + +/* + * Registers @ 0x04000000 phys, 0xff400000 virt) + */ +#define BRH_REG_BASE 0xff400000 +#define BRH_REG(reg) (volatile u32 *)(BRH_REG_BASE | reg) + +#define BRH_SWITCH BRH_REG(0x0500) +#define BRH_PCI_SLAVE_INT BRH_REG(0x0000) +#define BRH_PCI_MEM0_XLATE BRH_REG(0x0010) +#define BRH_PCI_MEM1_XLATE BRH_REG(0x0018) +#define BRH_PCI_MEM2_XLATE BRH_REG(0x0020) +#define BRH_PCI_MAST_INT BRH_REG(0x0100) +#define BRH_PCI_MEM_ATU1 BRH_REG(0x0110) +#define BRH_PCI_MEM_ATU2 BRH_REG(0x0114) +#define BRH_PCI_IO_ATU BRH_REG(0x0118) +#define BRH_PCI_CONFIG_CTRL BRH_REG(0x0120) +#define BRH_DMA0_CTRL BRH_REG(0x0200) +#define BRH_DMA1_CTRL BRH_REG(0x0240) +#define BRH_DMA0_STATUS BRH_REG(0x0204) +#define BRH_DMA1_STATUS BRH_REG(0x0244) +#define BRH_DMA0_BYTES BRH_REG(0x0220) +#define BRH_DMA1_BYTES BRH_REG(0x0260) +#define BRH_DMA0_PADDR BRH_REG(0x0214) +#define BRH_DMA1_PADDR BRH_REG(0x0254) +#define BRH_DMA0_LADDR BRH_REG(0x021C) +#define BRH_DMA1_LADDR BRH_REG(0x025C) +#define BRH_DMA0_DCR BRH_REG(0x0224) +#define BRH_DMA1_DCR BRH_REG(0x0264) +#define BRH_TIMERA_CTRL BRH_REG(0x0300) +#define BRH_TIMERB_CTRL BRH_REG(0x0320) +#define BRH_TIMERA_PRELOAD BRH_REG(0x0304) +#define BRH_TIMERB_PRELOAD BRH_REG(0x0324) +#define BRH_TIMERA_VALUE BRH_REG(0x0308) +#define BRH_TIMERB_VALUE BRH_REG(0x0328) +#define BRH_INT_STAT BRH_REG(0x0400) +#define BRH_INT_MASK BRH_REG(0x0404) +#define BRH_INT_STEERING BRH_REG(0x0408) + + +/* + * Interrupts + */ +#define BRH_INT_SWI 0x00000001 +#define BRH_INT_TIMERA 0x00000002 +#define BRH_INT_TIMERB 0x00000004 +#define BRH_INT_DIAG 0x00000080 +#define BRH_INT_DMA0_EOT 0x00000100 +#define BRH_INT_DMA1_EOT 0x000001 + + +/* + * Rotary Switch Status Register + */ +#define BRH_BIG_ENDIAN_FLASH 0x00000020 +#define BRH_SWITCH_POS_MASK 0x00000007 + +/* + * PCI Slave Interrupt Status Register + */ +#define BRH_PCI_SLAVE_SERR 0x00000010 +#define BRH_PCI_SLAVE_PERR 0x00000100 +#define BRH_PCI_SLAVE_IFIFO_UNDER 0x00010000 +#define BRH_PCI_SLAVE_IFIFO_OVER 0x00020000 +#define BRH_PCI_SLAVE_OFIFO_UNDER 0x00040000 +#define BRH_PCI_SLAVE_OFIFO_OVER 0x00080000 + +/* + * PCI Slave Translation Register (Inbound ATU) + */ +#define BRH_PCI_SLAVE_ENDIAN_SWAP 0x00000001 + +#define BRH_PCI_SLAVE_SDRAM_MASK 0x06000000 + +/* + * PCI Master Interrupt Status Register + */ +#define BRH_PCI_MASTER_PERR 0x00000001 +#define BRH_PCI_MASTER_TABORT 0x00000004 +#define BRH_PCI_MASTER_MABORT 0x00000008 +#define BRH_PCI_MASTER_IFIFO_UNDER 0x00010000 +#define BRH_PCI_MASTER_IFIFO_OVER 0x00020000 +#define BRH_PCI_MASTER_OFIFO_UNDER 0x00040000 +#define BRH_PCI_MASTER_OFIFO_OVER 0x00080000 + +/* + * PCI Outbound Memory ATU Register + */ +#define BRH_PCI_ATU_BURST_LINEAR 0x00000000 +#define BRH_PCI_ATU_ENDIAN_SWAP 0x00000004 +#define BRH_PCI_ATU_FORCE_32BIT 0x00000008 + +#define BRH_PCI_ATU_ADDR_MASK 0x87000000 + +/* + * PCI Outbound I/O ATU Register + */ +#define BRH_PCI_IO_ATU_ADDR_MASK 0x87000000 + +/* + * DMA Control Register + */ +#define BRH_DMA_ENABLE 0x00000001 + +/* + * DMA Status Register + */ +#define BRH_DMA_PERR 0x00000001 +#define BRH_DMA_TABORT 0x00000004 +#define BRH_DMA_MABORT 0x00000008 +#define BRH_DMA_EOT 0x00000100 +#define BRH_DMA_ACTIVE 0x00000400 +#define BRH_DMA_IFIFO_UNDER 0x00010000 +#define BRH_DMA_IFIFO_OVER 0x00020000 +#define BRH_DMA_OFIFO_UNDER 0x00040000 +#define BRH_DMA_OFIFO_OVER 0x00080000 + +/* + * DMA Byte Count Register + */ +#define BRH_DMA_MAX_BYTES (1 << 24) + +/* + * DMA Local Address Register + */ +#define BRH_MAX_DMA_ADDR (1 << 26) + +/* + * Timer Control/Status Register + */ +#define BRH_TIMER_ENABLE 0x00000001 +#define BRH_TIMER_CONTINOUS 0x00000002 +#define BRH_TIMER_INTERRUPT 0x00000200 + +/* + * On board devices + */ + +#define BRH_UART0_BASE 0xff000000 +#define BRH_UART1_BASE 0xff100000 +#define BRH_LED_BASE 0xff200000 + +/* + * PCI I/O bits + */ +#define BRH_PCI_IO_VIRT 0xfd000000 +#define BRH_PCI_IO_PHYS 0x0a000000 +#define PCIO_BASE ((BRH_PCI_IO_VIRT - BRH_PCI_IO_PHYS)) + +#define PCIBIOS_MIN_IO 0x0a000000 +#define PCIBIOS_MIN_MEM 0x0c000000 + +#define pcibios_assign_all_busses() 1 + +#endif // _BRH_H_ diff -Nru a/include/asm-arm/arch-adifcc/dma.h b/include/asm-arm/arch-adifcc/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/dma.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/arch-80200fcc/dma.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff + +/* No DMA */ +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff -Nru a/include/asm-arm/arch-adifcc/hardware.h b/include/asm-arm/arch-adifcc/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/hardware.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-adifcc/hardware.h + * + * Hardware definitions for ADI based systems + * + * Author: Deepak Saxena + * + * Copyright (C) 2000-2001 MontaVista Software Inc. + * + * 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 __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +#if defined(CONFIG_ARCH_ADI_EVB) +#include "adi_evb.h" +#elif defined(CONFIG_ARCH_BRH) +#include "brh.h" +#else +#error "No ADI Implementation Selected" +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ diff -Nru a/include/asm-arm/arch-adifcc/io.h b/include/asm-arm/arch-adifcc/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/io.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,53 @@ +/* + * linux/include/asm-arm/arch-adifcc/io.h + * + * Author: Deepak Saxena + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io_pci(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#define __ioaddr(p) __io_pci(p) +#define __io(p) __io_pci(p) + +/* + * Generic virtual read/write + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + +#define __arch_ioremap __ioremap +#define __arch_iounmap __iounmap + +#endif diff -Nru a/include/asm-arm/arch-adifcc/irq.h b/include/asm-arm/arch-adifcc/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/irq.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-adifcc/irq.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 fixup_irq(irq) (irq) + + diff -Nru a/include/asm-arm/arch-adifcc/irqs.h b/include/asm-arm/arch-adifcc/irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,55 @@ +/* + * linux/include/asm-arm/arch-adifcc/irqs.h + * + * Author: Deepak Saxena + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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 IRQ_XS80200_BCU 0 /* Bus Control Unit */ +#define IRQ_XS80200_PMU 1 /* Performance Monitoring Unit */ +#define IRQ_XS80200_EXTIRQ 2 /* external IRQ signal */ +#define IRQ_XS80200_EXTFIQ 3 /* external IRQ signal */ + +#define XSCALE_PMU_IRQ IRQ_XS80200_PMU + +#define NR_XS80200_IRQS 4 +#define NR_IRQS NR_XS80200_IRQS + +#define IRQ_XSCALE_PMU IRQ_XS80200_PMU + +#ifdef CONFIG_ARCH_BRH + +/* Interrupts available on the BRH */ +#define IRQ_BRH(x) (NR_XS80200_IRQS + (x)) + +#define IRQ_BRH_SWI IRQ_BRH(0) +#define IRQ_BRH_TIMERA IRQ_BRH(1) +#define IRQ_BRH_TIMERB IRQ_BRH(2) +#define IRQ_BRH_ERROR IRQ_BRH(7) +#define IRQ_BRH_DMA_EOT IRQ_BRH(8) +#define IRQ_BRH_DMA_PARITY IRQ_BRH(9) +#define IRQ_BRH_DMA_TABORT IRQ_BRH(10) +#define IRQ_BRH_DMA_MABORT IRQ_BRH(11) +#define IRQ_BRH_PCI_PERR IRQ_BRH(16) +#define IRQ_BRH_PCI_SERR IRQ_BRH(19) +#define IRQ_BRH_ATU_PERR IRQ_BRH(20) +#define IRQ_BRH_ATU_TABORT IRQ_BRH(21) +#define IRQ_BRH_ATU_MABORT IRQ_BRH(22) +#define IRQ_BRH_UART_A IRQ_BRH(24) +#define IRQ_BRH_UART_B IRQ_BRH(25) +#define IRQ_BRH_PCI_INT_A IRQ_BRH(26) +#define IRQ_BRH_PCI_INT_B IRQ_BRH(27) +#define IRQ_BRH_PCI_INT_C IRQ_BRH(28) +#define IRQ_BRH_PCI_INT_D IRQ_BRH(29) +#define IRQ_BRH_SOFT_RESET IRQ_BRH(30) + +#undef NR_IRQS +#define NR_IRQS ((IRQ_BRH_SOFT_RESET)+1) + +#endif + + diff -Nru a/include/asm-arm/arch-adifcc/memory.h b/include/asm-arm/arch-adifcc/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/memory.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-adifcc/memory.h + * + * Copyright (c) 2001 MontaVista Software, Inc. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + + +#define PAGE_OFFSET ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0xC0000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + * + * These are dummies for now. + */ +#define __virt_to_bus__is_a_macro +#define __bus_to_virt__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff -Nru a/include/asm-arm/arch-adifcc/param.h b/include/asm-arm/arch-adifcc/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/param.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-adifcc/param.h + */ diff -Nru a/include/asm-arm/arch-adifcc/pci-bridge.h b/include/asm-arm/arch-adifcc/pci-bridge.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/pci-bridge.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * include/asm-arm/arch-iop310/pci-bridge.h + * + * Generic PCI hose support for Xscale/ARM. To eventually be + * moved to a more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 __KERNEL__ +#ifndef _ASM_PCI_BRIDGE_H +#define _ASM_PCI_BRIDGE_H + +struct device_node; +struct pci_controller; + +/* Get the PCI host controller for a bus */ +extern struct pci_controller* pci_bus_to_hose(int bus); + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct resource io_space; + struct resource mem_space; +}; + +/* These are used for config access before all the PCI probing + has been done. */ +int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 *val); +int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 *val); +int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 *val); +int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 val); +int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val); +int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val); +#endif +#endif /* __KERNEL__ */ diff -Nru a/include/asm-arm/arch-adifcc/pci.h b/include/asm-arm/arch-adifcc/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/pci.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,36 @@ +/* + * include/asm-arm/arch-xscale/pci.h + * + * Generic PCI support for Xscale/ARM. To eventually be moved to a + * more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ASM_ARCH_PCI_H +#define _ASM_ARCH_PCI_H + +extern struct pci_controller* pcibios_alloc_controller(void); +extern void pcibios_allocate_resources(void); +extern void pci_exclude_device(unsigned char, unsigned char); +extern struct pci_dev * fake_pci_dev(struct pci_controller *, int, int); +extern u8 common_swizzle(struct pci_dev *, u8 *); + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. + */ +#define PCI_IRQ_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ + _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ + _ctl_; }) + +#endif /* _ASM_ARCH_PCI_H */ diff -Nru a/include/asm-arm/arch-adifcc/pci_auto.h b/include/asm-arm/arch-adifcc/pci_auto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/pci_auto.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-iop310/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ARM_MACH_XSCALE_PCI_AUTO_H +#define _ARM_MACH_XSCALE_PCI_AUTO_H + +#include "pci-bridge.h" + +extern int pciauto_bus_scan(struct pci_controller *, int); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* _ARM_MACH_XSCALE_PCI_AUTO_H */ diff -Nru a/include/asm-arm/arch-adifcc/serial.h b/include/asm-arm/arch-adifcc/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/serial.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,69 @@ +/* + * include/asm-arm/arch-adifcc/serial.h + * + * Author: Deepak Saxena + * + * Copyright (c) 2001 MontaVista Software, Inc. + */ + +#ifndef _ARCH_SERIAL_H_ +#define _ARCH_SERIAL_H_ + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +/* + * We use SERIAL_IO_MEM type since these are memory mapped UARTs, + * not ISA style I/O ports. + */ + +#ifdef CONFIG_ARCH_ADI_EVB + +#define BASE_BAUD ( 1852000 / 16 ) + +#define RS_TABLE_SIZE 1 + +/* + * One serial port, int goes to FIQ, so we run in polled mode + */ +#define STD_SERIAL_PORT_DEFNS \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: 0, \ + flags: STD_COM_FLAGS, \ + iomem_base: 0xff400000, \ + io_type: SERIAL_IO_MEM \ + } /* ttyS0 */ + +#elif defined(CONFIG_ARCH_BRH) + +/* + * BRH uses 33MHz clock for uart + */ +#define BASE_BAUD ( 33000000 / 16 ) + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_BRH_UART_A, \ + flags: STD_COM_FLAGS, \ + iomem_base: BRH_UART0_BASE, \ + io_type: SERIAL_IO_MEM \ + }, /* ttyS0 */ \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_BRH_UART_B, \ + flags: STD_COM_FLAGS, \ + iomem_base: BRH_UART1_BASE, \ + io_type: SERIAL_IO_MEM \ + } /* ttyS1 */ +#endif + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif // _ARCH_SERIAL_H_ diff -Nru a/include/asm-arm/arch-adifcc/system.h b/include/asm-arm/arch-adifcc/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/system.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-adifcc/system.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +static inline void arch_idle(void) +{ +#if 0 + if (!hlt_counter) + cpu_do_idle(0); +#endif +} + + +static inline void arch_reset(char mode) +{ + if ( 1 && mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + /* Use on-chip reset capability */ + } +} + diff -Nru a/include/asm-arm/arch-adifcc/time.h b/include/asm-arm/arch-adifcc/time.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/time.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,12 @@ +/* + * linux/include/asm-arm/arch-adifcc/time.h + * + */ + + +/* + * No on board timer on 80200EVB, implemenation @ + * arch/arm/kernel/xscale-time.c + * On the BRH, we use the onboard timer and it's implemented in + * arch/arm/mach-adifcc/brh-time.c + */ diff -Nru a/include/asm-arm/arch-adifcc/timex.h b/include/asm-arm/arch-adifcc/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/timex.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,17 @@ +/* + * linux/include/asm-arm/arch-adifcc/timex.h + * + * XScale architecture timex specifications + */ + +#ifdef CONFIG_XSCALE_PMU_TIMER +/* + * This is for a timer based on the XS80200's PMU counter + */ +#define CLOCK_TICK_RATE 400000000 + +#else + +#define CLOCK_TICK_RATE 33000000 + +#endif diff -Nru a/include/asm-arm/arch-adifcc/uncompress.h b/include/asm-arm/arch-adifcc/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/uncompress.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,114 @@ +/* + * linux/include/asm-arm/arch-adifcc/uncompress.h + * + * Author: Deepak Saxena + * + * Copyright (c) 2001 MontaVista Software, Inc. + * + */ + +#ifndef _ARCH_UNCOMPRESS_H_ +#define _ARCH_UNCOMPRESS_H_ + +#ifdef CONFIG_ARCH_ADI_EVB +#define UART_BASE ((volatile unsigned char *)0x00400000) +#elif defined(CONFIG_ARCH_BRH) +#define UART_BASE ((volatile unsigned char *)0x03000000) +#define UART_BASE2 ((volatile unsigned char *)0x03100000) +#endif + +static __inline__ void putc(char c) +{ + /* + * Boards have peripherals wired in LE mode, so need to + * fiddle with the address to get the proper byte lane + * enabled. :) + */ +#if defined(__ARMEB__) && defined(_FOOBAR_) + while ((UART_BASE[6] & 0x60) != 0x60); + UART_BASE[3] = c; +#else + + while ((UART_BASE[5] & 0x60) != 0x60); + UART_BASE[0] = c; +#endif +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +#ifdef CONFIG_ARCH_BRH + +/* + * We need to determine what rev board we're running so that we + * can tell the system how much RAM there is. Can't do this in + * the board fixup function b/c the revision of the board can + * only be found through PCI config cycles, which would require + * the PCI registers to be mapped very early on. + */ + +#include +#include + +static u32 get_mem_size(void) +{ + u32 where = PCI_CLASS_REVISION & ~3; + u32 *paddress = (u32*)(0x08000000 | ( 1 << PCI_SLOT(0) + 11) | (PCI_FUNC(0) << 8) | where); + u8 rev_id; + + rev_id = (u8)(*paddress & 0xff); + + /* + * Old revision board, only 32 MB usable + */ + if(!rev_id) + return 0x02000000; + else + return 0x08000000; +} + +#define PARAM_ADDR 0xC0000100 + +static void setup_params(void) +{ + volatile struct tag *params = (struct tag*)PARAM_ADDR; + + params->hdr.tag = ATAG_CORE; + params->hdr.size = tag_size(tag_core); + params->u.core.flags = 0; + params->u.core.pagesize = PAGE_SIZE; + params->u.core.rootdev = 0; + + params = (volatile struct tag*)tag_next(params); + + params->hdr.tag = ATAG_MEM; + params->hdr.size = tag_size(tag_mem32); + params->u.mem.start = 0xc0000000; + params->u.mem.size = get_mem_size(); + + params = (volatile struct tag*)tag_next(params); + + params->hdr.tag = ATAG_NONE; + params->hdr.size = 0; +} + +#define arch_decomp_setup() setup_params() + +#else +#define arch_decomp_setup() +#endif + +#define arch_decomp_wdog() + + +#endif // _ARCH_UNCOMPRESS_H_ diff -Nru a/include/asm-arm/arch-adifcc/vmalloc.h b/include/asm-arm/arch-adifcc/vmalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-adifcc/vmalloc.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-adifcc/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (0xe8000000) diff -Nru a/include/asm-arm/arch-iop3xx/dma.h b/include/asm-arm/arch-iop3xx/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/dma.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,109 @@ +/* + * linux/include/asm-arm/arch-iop80310/dma.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 _IOP310_DMA_H_ +#define _IOP310_DMA_H_ + +/* 2 DMA on primary PCI and 1 on secondary for 80310 */ +#define MAX_IOP310_DMA_CHANNEL 3 +#define MAX_DMA_DESC 64 /*128 */ + +/* + * Make the generic DMA bits go away since we don't use it + */ +#define MAX_DMA_CHANNELS 0 + +#define MAX_DMA_ADDRESS 0xffffffff + +#define IOP310_DMA_P0 0 +#define IOP310_DMA_P1 1 +#define IOP310_DMA_S0 2 + +#define DMA_MOD_READ 0x0001 +#define DMA_MOD_WRITE 0x0002 +#define DMA_MOD_CACHED 0x0004 +#define DMA_MOD_NONCACHED 0x0008 + + +#define DMA_DESC_DONE 0x0010 +#define DMA_INCOMPLETE 0x0020 +#define DMA_HOLD 0x0040 +#define DMA_END_CHAIN 0x0080 +#define DMA_COMPLETE 0x0100 +#define DMA_NOTIFY 0x0200 +#define DMA_NEW_HEAD 0x0400 + +#define DMA_USER_MASK (DMA_NOTIFY | DMA_INCOMPLETE | \ + DMA_HOLD | DMA_COMPLETE) + +#define DMA_DCR_DAC 0x00000020 /* Dual Addr Cycle Enab */ +#define DMA_DCR_IE 0x00000010 /* Interrupt Enable */ +#define DMA_DCR_PCI_IOR 0x00000002 /* I/O Read */ +#define DMA_DCR_PCI_IOW 0x00000003 /* I/O Write */ +#define DMA_DCR_PCI_MR 0x00000006 /* Memory Read */ +#define DMA_DCR_PCI_MW 0x00000007 /* Memory Write */ +#define DMA_DCR_PCI_CR 0x0000000A /* Configuration Read */ +#define DMA_DCR_PCI_CW 0x0000000B /* Configuration Write */ +#define DMA_DCR_PCI_MRM 0x0000000C /* Memory Read Multiple */ +#define DMA_DCR_PCI_MRL 0x0000000E /* Memory Read Line */ +#define DMA_DCR_PCI_MWI 0x0000000F /* Mem Write and Inval */ + +#define DMA_USER_CMD_IE 0x00000001 /* user request int */ +#define DMA_USER_END_CHAIN 0x00000002 /* end of sgl chain flag */ + +/* ATU defines */ +#define IOP310_ATUCR_PRIM_OUT_ENAB /* Configuration */ 0x00000002 +#define IOP310_ATUCR_DIR_ADDR_ENAB /* Configuration */ 0x00000080 + + +typedef void (*dma_callback_t) (void *buf_context); +/* + * DMA Descriptor + */ +typedef struct _dma_desc +{ + u32 NDAR; /* next descriptor adress */ + u32 PDAR; /* PCI address */ + u32 PUADR; /* upper PCI address */ + u32 LADR; /* local address */ + u32 BC; /* byte count */ + u32 DC; /* descriptor control */ +} dma_desc_t; + +typedef struct _dma_sgl +{ + dma_desc_t dma_desc; /* DMA descriptor pointer */ + u32 status; /* descriptor status */ + void *data; /* local virt */ + struct _dma_sgl *next; /* next descriptor */ +} dma_sgl_t; + +/* dma sgl head */ +typedef struct _dma_head +{ + u32 total; /* total elements in SGL */ + u32 status; /* status of sgl */ + u32 mode; /* read or write mode */ + dma_sgl_t *list; /* pointer to list */ + dma_callback_t callback; /* callback function */ +} dma_head_t; + +/* function prototypes */ +int dma_request(dmach_t, const char *); +int dma_queue_buffer(dmach_t, dma_head_t *); +int dma_suspend(dmach_t); +int dma_resume(dmach_t); +int dma_flush_all(dmach_t); +void dma_free(dmach_t); +void dma_set_irq_threshold(dmach_t, int); +dma_sgl_t *dma_get_buffer(dmach_t, int); +void dma_return_buffer(dmach_t, dma_sgl_t *); + +#endif /* _ASM_ARCH_DMA_H */ diff -Nru a/include/asm-arm/arch-iop3xx/hardware.h b/include/asm-arm/arch-iop3xx/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/hardware.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * linux/include/asm-arm/arch-iop80310/hardware.h + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +#define PCIO_BASE 0x6e000000 + +#ifndef __ASSEMBLY__ +extern unsigned int processor_id; +#endif + +#define pcibios_assign_all_busses() 1 + +#ifdef CONFIG_ARCH_IOP310 +/* + * these are the values for the secondary PCI bus on the 80312 chip. I will + * have to do some fixup in the bus/dev fixup code + */ +#define PCIBIOS_MIN_IO 0x90010000 +#define PCIBIOS_MIN_MEM 0x88000000 + +// Generic chipset bits +#include "iop310.h" + +// Board specific +#if defined(CONFIG_ARCH_IQ80310) +#include "iq80310.h" +#endif + +#ifndef __ASSEMBLY__ +#define iop_is_310() ((processor_id & 0xffffe3f0) == 0x69052000) +#endif + +#else // !IOP310 + +#define iop_is_310() (0) + +#endif + +#ifdef CONFIG_ARCH_IOP321 + +#define PCIBIOS_MIN_IO 0x90000000 +#define PCIBIOS_MIN_MEM 0x80000000 + +#include "iop321.h" + +#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244) +#include "iq80321.h" +#endif + +#ifndef __ASSEMBLY__ +#define iop_is_321() ((processor_id & 0xfffff7e0) == 0x69052420) +#endif + +#else // !IOP321 + +#define iop_is_321() (0) + +#endif + +#endif /* _ASM_Arch_hardwARE_H */ diff -Nru a/include/asm-arm/arch-iop3xx/ide.h b/include/asm-arm/arch-iop3xx/ide.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/ide.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,51 @@ +/* + * include/asm-arm/arch-iop310/ide.h + * + * Generic IDE functions for IOP310 systems + * + * Author: Deepak Saxena + * + * Copyright 2001 MontaVista Software Inc. + * + * 09/26/2001 - Sharon Baartmans + * Fixed so it actually works. + */ + +#ifndef _ASM_ARCH_IDE_H_ +#define _ASM_ARCH_IDE_H_ + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + ide_ioreg_t reg; + int i; + int regincr = 1; + + memset(hw, 0, sizeof(*hw)); + + reg = (ide_ioreg_t)data_port; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += regincr; + } + + hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; + + if (irq) *irq = 0; +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ + /* There are no standard ports */ +} + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/io.h b/include/asm-arm/arch-iop3xx/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/io.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,100 @@ +/* + * linux/include/asm-arm/arch-iop310/io.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io_pci(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#define __ioaddr(p) __io_pci(p) +#define __io(p) __io_pci(p) + +/* + * We have to define our own here b/c XScale has some sideaffects + * dealing with data aborts that we have to workaround here. + * Basically after each I/O access, we do a NOP to protect + * the access from imprecise aborts. See section 2.3.4.4 of the + * XScale developer's manual for more info. + * + */ + +/* +#undef __arch_getb +#undef __arch_getl + +extern __inline__ unsigned char __arch_getb(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__( + "ldr%?b %0, [%1, #0] @ getw" + "mov r0, r0" + : "=&r" (value) : "r" (a)); + return (unsigned char)value; +} + +extern __inline__ unsigned int __arch_getl(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__( + "ldr%? %0, [%1, #0] @ getw" + "mov r0, r0" + : "=&r" (value) : "r" (a)); + return value; +} +*/ + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__( + "ldr%?h %0, [%1, #0] @ getw" + "mov r0, r0" + : "=&r" (value) : "r" (a)); + return value; +} + + +/* +#undef __arch_putb(v,a) +#undef __arch_putl(v,a) + +extern __inline__ void __arch_putb(unsigned int value, unsigned long a) +{ + __asm__ __volatile__( + "str%?b %0, [%1, #0] @ putw" + "mov r0, r0" + : : "r" (value), "r" (a)); +} + +extern __inline__ void __arch_putl(unsigned int value, unsigned long a) +{ + __asm__ __volatile__( + "str%? %0, [%1, #0] @ putw" + "mov r0, r0" + : : "r" (value), "r" (a)); +} +*/ + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__( + "str%?h %0, [%1, #0] @ putw" + "mov r0, r0" + : : "r" (value), "r" (a)); +} + +#define __arch_ioremap __ioremap +#define __arch_iounmap __iounmap + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/iop310-irqs.h b/include/asm-arm/arch-iop3xx/iop310-irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iop310-irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,80 @@ +/* + * linux/include/asm-arm/arch-iop310/irqs.h + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * 06/13/01: Added 80310 on-chip interrupt sources + * + */ + + +/* + * XS80200 specific IRQs + */ +#define IRQ_XS80200_BCU 0 /* Bus Control Unit */ +#define IRQ_XS80200_PMU 1 /* Performance Monitoring Unit */ +#define IRQ_XS80200_EXTIRQ 2 /* external IRQ signal */ +#define IRQ_XS80200_EXTFIQ 3 /* external IRQ signal */ + +#define NR_XS80200_IRQS 4 + +#define XSCALE_PMU_IRQ IRQ_XS80200_PMU + +/* + * IOP80310 chipset interrupts + */ +#define IOP310_IRQ_OFS NR_XS80200_IRQS +#define IOP310_IRQ(x) (IOP310_IRQ_OFS + (x)) + +/* + * On FIQ1ISR register + */ +#define IRQ_IOP310_DMA0 IOP310_IRQ(0) /* DMA Channel 0 */ +#define IRQ_IOP310_DMA1 IOP310_IRQ(1) /* DMA Channel 1 */ +#define IRQ_IOP310_DMA2 IOP310_IRQ(2) /* DMA Channel 2 */ +#define IRQ_IOP310_PMON IOP310_IRQ(3) /* Bus performance Unit */ +#define IRQ_IOP310_AAU IOP310_IRQ(4) /* Application Accelator Unit */ + +/* + * On FIQ2ISR register + */ +#define IRQ_IOP310_I2C IOP310_IRQ(5) /* I2C unit */ +#define IRQ_IOP310_MU IOP310_IRQ(6) /* messaging unit */ + +#define NR_IOP310_IRQS (IOP310_IRQ(6) + 1) + +#define NR_IRQS NR_IOP310_IRQS + + +/* + * Interrupts available on the Cyclone IQ80310 board + */ +#ifdef CONFIG_ARCH_IQ80310 + +#define IQ80310_IRQ_OFS NR_IOP310_IRQS +#define IQ80310_IRQ(y) ((IQ80310_IRQ_OFS) + (y)) + +#define IRQ_IQ80310_TIMER IQ80310_IRQ(0) /* Timer Interrupt */ +#define IRQ_IQ80310_I82559 IQ80310_IRQ(1) /* I82559 Ethernet Interrupt */ +#define IRQ_IQ80310_UART1 IQ80310_IRQ(2) /* UART1 Interrupt */ +#define IRQ_IQ80310_UART2 IQ80310_IRQ(3) /* UART2 Interrupt */ +#define IRQ_IQ80310_INTD IQ80310_IRQ(4) /* PCI INTD */ + + +/* + * ONLY AVAILABLE ON REV F OR NEWER BOARDS! + */ +#define IRQ_IQ80310_INTA IQ80310_IRQ(5) /* PCI INTA */ +#define IRQ_IQ80310_INTB IQ80310_IRQ(6) /* PCI INTB */ +#define IRQ_IQ80310_INTC IQ80310_IRQ(7) /* PCI INTC */ + +#undef NR_IRQS +#define NR_IRQS (IQ80310_IRQ(7) + 1) + +#endif // CONFIG_ARCH_IQ80310 + diff -Nru a/include/asm-arm/arch-iop3xx/iop310.h b/include/asm-arm/arch-iop3xx/iop310.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iop310.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,251 @@ +/* + * linux/include/asm/arch-iop310/iop310.h + * + * Intel IOP310 Compainion Chip definitions + * + * 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 _IOP310_HW_H_ +#define _IOP310_HW_H_ + +#ifndef __ASSEMBLY__ +#define iop_is_310() ((processor_id & 0xffffe3f0) == 0x69052000) +#endif + +/* + * IOP310 I/O and Mem space regions for PCI autoconfiguration + */ +#define IOP310_PCISEC_LOWER_IO 0x90010000 +#define IOP310_PCISEC_UPPER_IO 0x9001ffff +#define IOP310_PCISEC_LOWER_MEM 0x88000000 +#define IOP310_PCISEC_UPPER_MEM 0x8bffffff + +#define IOP310_PCIPRI_LOWER_IO 0x90000000 +#define IOP310_PCIPRI_UPPER_IO 0x9000ffff +#define IOP310_PCIPRI_LOWER_MEM 0x80000000 +#define IOP310_PCIPRI_UPPER_MEM 0x83ffffff + +#define IOP310_PCI_WINDOW_SIZE 64 * 0x100000 + +/* + * IOP310 chipset registers + */ +#define IOP310_VIRT_MEM_BASE 0xe8001000 /* chip virtual mem address*/ +#define IOP310_PHY_MEM_BASE 0x00001000 /* chip physical memory address */ +#define IOP310_REG_ADDR(reg) (IOP310_VIRT_MEM_BASE | IOP310_PHY_MEM_BASE | (reg)) + +/* PCI-to-PCI Bridge Unit 0x00001000 through 0x000010FF */ +#define IOP310_VIDR (volatile u16 *)IOP310_REG_ADDR(0x00001000) +#define IOP310_DIDR (volatile u16 *)IOP310_REG_ADDR(0x00001002) +#define IOP310_PCR (volatile u16 *)IOP310_REG_ADDR(0x00001004) +#define IOP310_PSR (volatile u16 *)IOP310_REG_ADDR(0x00001006) +#define IOP310_RIDR (volatile u8 *)IOP310_REG_ADDR(0x00001008) +#define IOP310_CCR (volatile u32 *)IOP310_REG_ADDR(0x00001009) +#define IOP310_CLSR (volatile u8 *)IOP310_REG_ADDR(0x0000100C) +#define IOP310_PLTR (volatile u8 *)IOP310_REG_ADDR(0x0000100D) +#define IOP310_HTR (volatile u8 *)IOP310_REG_ADDR(0x0000100E) +/* Reserved 0x0000100F through 0x00001017 */ +#define IOP310_PBNR (volatile u8 *)IOP310_REG_ADDR(0x00001018) +#define IOP310_SBNR (volatile u8 *)IOP310_REG_ADDR(0x00001019) +#define IOP310_SUBBNR (volatile u8 *)IOP310_REG_ADDR(0x0000101A) +#define IOP310_SLTR (volatile u8 *)IOP310_REG_ADDR(0x0000101B) +#define IOP310_IOBR (volatile u8 *)IOP310_REG_ADDR(0x0000101C) +#define IOP310_IOLR (volatile u8 *)IOP310_REG_ADDR(0x0000101D) +#define IOP310_SSR (volatile u16 *)IOP310_REG_ADDR(0x0000101E) +#define IOP310_MBR (volatile u16 *)IOP310_REG_ADDR(0x00001020) +#define IOP310_MLR (volatile u16 *)IOP310_REG_ADDR(0x00001022) +#define IOP310_PMBR (volatile u16 *)IOP310_REG_ADDR(0x00001024) +#define IOP310_PMLR (volatile u16 *)IOP310_REG_ADDR(0x00001026) +/* Reserved 0x00001028 through 0x00001033 */ +#define IOP310_CAPR (volatile u8 *)IOP310_REG_ADDR(0x00001034) +/* Reserved 0x00001035 through 0x0000103D */ +#define IOP310_BCR (volatile u16 *)IOP310_REG_ADDR(0x0000103E) +#define IOP310_EBCR (volatile u16 *)IOP310_REG_ADDR(0x00001040) +#define IOP310_SISR (volatile u16 *)IOP310_REG_ADDR(0x00001042) +#define IOP310_PBISR (volatile u32 *)IOP310_REG_ADDR(0x00001044) +#define IOP310_SBISR (volatile u32 *)IOP310_REG_ADDR(0x00001048) +#define IOP310_SACR (volatile u32 *)IOP310_REG_ADDR(0x0000104C) +#define IOP310_PIRSR (volatile u32 *)IOP310_REG_ADDR(0x00001050) +#define IOP310_SIOBR (volatile u8 *)IOP310_REG_ADDR(0x00001054) +#define IOP310_SIOLR (volatile u8 *)IOP310_REG_ADDR(0x00001055) +#define IOP310_SCDR (volatile u8 *)IOP310_REG_ADDR(0x00001056) + +#define IOP310_SMBR (volatile u16 *)IOP310_REG_ADDR(0x00001058) +#define IOP310_SMLR (volatile u16 *)IOP310_REG_ADDR(0x0000105A) +#define IOP310_SDER (volatile u16 *)IOP310_REG_ADDR(0x0000105C) +#define IOP310_QCR (volatile u16 *)IOP310_REG_ADDR(0x0000105E) +#define IOP310_CAPID (volatile u8 *)IOP310_REG_ADDR(0x00001068) +#define IOP310_NIPTR (volatile u8 *)IOP310_REG_ADDR(0x00001069) +#define IOP310_PMCR (volatile u16 *)IOP310_REG_ADDR(0x0000106A) +#define IOP310_PMCSR (volatile u16 *)IOP310_REG_ADDR(0x0000106C) +#define IOP310_PMCSRBSE (volatile u8 *)IOP310_REG_ADDR(0x0000106E) +/* Reserved 0x00001064 through 0x000010FFH */ + +/* Performance monitoring unit 0x00001100 through 0x000011FF*/ +#define IOP310_PMONGTMR (volatile u32 *)IOP310_REG_ADDR(0x00001100) +#define IOP310_PMONESR (volatile u32 *)IOP310_REG_ADDR(0x00001104) +#define IOP310_PMONEMISR (volatile u32 *)IOP310_REG_ADDR(0x00001108) +#define IOP310_PMONGTSR (volatile u32 *)IOP310_REG_ADDR(0x00001110) +#define IOP310_PMONPECR1 (volatile u32 *)IOP310_REG_ADDR(0x00001114) +#define IOP310_PMONPECR2 (volatile u32 *)IOP310_REG_ADDR(0x00001118) +#define IOP310_PMONPECR3 (volatile u32 *)IOP310_REG_ADDR(0x0000111C) +#define IOP310_PMONPECR4 (volatile u32 *)IOP310_REG_ADDR(0x00001120) +#define IOP310_PMONPECR5 (volatile u32 *)IOP310_REG_ADDR(0x00001124) +#define IOP310_PMONPECR6 (volatile u32 *)IOP310_REG_ADDR(0x00001128) +#define IOP310_PMONPECR7 (volatile u32 *)IOP310_REG_ADDR(0x0000112C) +#define IOP310_PMONPECR8 (volatile u32 *)IOP310_REG_ADDR(0x00001130) +#define IOP310_PMONPECR9 (volatile u32 *)IOP310_REG_ADDR(0x00001134) +#define IOP310_PMONPECR10 (volatile u32 *)IOP310_REG_ADDR(0x00001138) +#define IOP310_PMONPECR11 (volatile u32 *)IOP310_REG_ADDR(0x0000113C) +#define IOP310_PMONPECR12 (volatile u32 *)IOP310_REG_ADDR(0x00001140) +#define IOP310_PMONPECR13 (volatile u32 *)IOP310_REG_ADDR(0x00001144) +#define IOP310_PMONPECR14 (volatile u32 *)IOP310_REG_ADDR(0x00001148) + +/* Address Translation Unit 0x00001200 through 0x000012FF */ +#define IOP310_ATUVID (volatile u16 *)IOP310_REG_ADDR(0x00001200) +#define IOP310_ATUDID (volatile u16 *)IOP310_REG_ADDR(0x00001202) +#define IOP310_PATUCMD (volatile u16 *)IOP310_REG_ADDR(0x00001204) +#define IOP310_PATUSR (volatile u16 *)IOP310_REG_ADDR(0x00001206) +#define IOP310_ATURID (volatile u8 *)IOP310_REG_ADDR(0x00001208) +#define IOP310_ATUCCR (volatile u32 *)IOP310_REG_ADDR(0x00001209) +#define IOP310_ATUCLSR (volatile u8 *)IOP310_REG_ADDR(0x0000120C) +#define IOP310_ATULT (volatile u8 *)IOP310_REG_ADDR(0x0000120D) +#define IOP310_ATUHTR (volatile u8 *)IOP310_REG_ADDR(0x0000120E) + +#define IOP310_PIABAR (volatile u32 *)IOP310_REG_ADDR(0x00001210) +/* Reserved 0x00001214 through 0x0000122B */ +#define IOP310_ASVIR (volatile u16 *)IOP310_REG_ADDR(0x0000122C) +#define IOP310_ASIR (volatile u16 *)IOP310_REG_ADDR(0x0000122E) +#define IOP310_ERBAR (volatile u32 *)IOP310_REG_ADDR(0x00001230) +#define IOP310_ATUCAPPTR (volatile u8 *)IOP310_REG_ADDR(0x00001234) +/* Reserved 0x00001235 through 0x0000123B */ +#define IOP310_ATUILR (volatile u8 *)IOP310_REG_ADDR(0x0000123C) +#define IOP310_ATUIPR (volatile u8 *)IOP310_REG_ADDR(0x0000123D) +#define IOP310_ATUMGNT (volatile u8 *)IOP310_REG_ADDR(0x0000123E) +#define IOP310_ATUMLAT (volatile u8 *)IOP310_REG_ADDR(0x0000123F) +#define IOP310_PIALR (volatile u32 *)IOP310_REG_ADDR(0x00001240) +#define IOP310_PIATVR (volatile u32 *)IOP310_REG_ADDR(0x00001244) +#define IOP310_SIABAR (volatile u32 *)IOP310_REG_ADDR(0x00001248) +#define IOP310_SIALR (volatile u32 *)IOP310_REG_ADDR(0x0000124C) +#define IOP310_SIATVR (volatile u32 *)IOP310_REG_ADDR(0x00001250) +#define IOP310_POMWVR (volatile u32 *)IOP310_REG_ADDR(0x00001254) +/* Reserved 0x00001258 through 0x0000125B */ +#define IOP310_POIOWVR (volatile u32 *)IOP310_REG_ADDR(0x0000125C) +#define IOP310_PODWVR (volatile u32 *)IOP310_REG_ADDR(0x00001260) +#define IOP310_POUDR (volatile u32 *)IOP310_REG_ADDR(0x00001264) +#define IOP310_SOMWVR (volatile u32 *)IOP310_REG_ADDR(0x00001268) +#define IOP310_SOIOWVR (volatile u32 *)IOP310_REG_ADDR(0x0000126C) +/* Reserved 0x00001270 through 0x00001273*/ +#define IOP310_ERLR (volatile u32 *)IOP310_REG_ADDR(0x00001274) +#define IOP310_ERTVR (volatile u32 *)IOP310_REG_ADDR(0x00001278) +/* Reserved 0x00001279 through 0x0000127C*/ +#define IOP310_ATUCAPID (volatile u8 *)IOP310_REG_ADDR(0x00001280) +#define IOP310_ATUNIPTR (volatile u8 *)IOP310_REG_ADDR(0x00001281) +#define IOP310_APMCR (volatile u16 *)IOP310_REG_ADDR(0x00001282) +#define IOP310_APMCSR (volatile u16 *)IOP310_REG_ADDR(0x00001284) +/* Reserved 0x00001286 through 0x00001287 */ +#define IOP310_ATUCR (volatile u32 *)IOP310_REG_ADDR(0x00001288) +/* Reserved 0x00001289 through 0x0000128C*/ +#define IOP310_PATUISR (volatile u32 *)IOP310_REG_ADDR(0x00001290) +#define IOP310_SATUISR (volatile u32 *)IOP310_REG_ADDR(0x00001294) +#define IOP310_SATUCMD (volatile u16 *)IOP310_REG_ADDR(0x00001298) +#define IOP310_SATUSR (volatile u16 *)IOP310_REG_ADDR(0x0000129A) +#define IOP310_SODWVR (volatile u32 *)IOP310_REG_ADDR(0x0000129C) +#define IOP310_SOUDR (volatile u32 *)IOP310_REG_ADDR(0x000012A0) +#define IOP310_POCCAR (volatile u32 *)IOP310_REG_ADDR(0x000012A4) +#define IOP310_SOCCAR (volatile u32 *)IOP310_REG_ADDR(0x000012A8) +#define IOP310_POCCDR (volatile u32 *)IOP310_REG_ADDR(0x000012AC) +#define IOP310_SOCCDR (volatile u32 *)IOP310_REG_ADDR(0x000012B0) +#define IOP310_PAQCR (volatile u32 *)IOP310_REG_ADDR(0x000012B4) +#define IOP310_SAQCR (volatile u32 *)IOP310_REG_ADDR(0x000012B8) +#define IOP310_PATUIMR (volatile u32 *)IOP310_REG_ADDR(0x000012BC) +#define IOP310_SATUIMR (volatile u32 *)IOP310_REG_ADDR(0x000012C0) +/* Reserved 0x000012C4 through 0x000012FF */ +/* Messaging Unit 0x00001300 through 0x000013FF */ +#define IOP310_MUIMR0 (volatile u32 *)IOP310_REG_ADDR(0x00001310) +#define IOP310_MUIMR1 (volatile u32 *)IOP310_REG_ADDR(0x00001314) +#define IOP310_MUOMR0 (volatile u32 *)IOP310_REG_ADDR(0x00001318) +#define IOP310_MUOMR1 (volatile u32 *)IOP310_REG_ADDR(0x0000131C) +#define IOP310_MUIDR (volatile u32 *)IOP310_REG_ADDR(0x00001320) +#define IOP310_MUIISR (volatile u32 *)IOP310_REG_ADDR(0x00001324) +#define IOP310_MUIIMR (volatile u32 *)IOP310_REG_ADDR(0x00001328) +#define IOP310_MUODR (volatile u32 *)IOP310_REG_ADDR(0x0000132C) +#define IOP310_MUOISR (volatile u32 *)IOP310_REG_ADDR(0x00001330) +#define IOP310_MUOIMR (volatile u32 *)IOP310_REG_ADDR(0x00001334) +#define IOP310_MUMUCR (volatile u32 *)IOP310_REG_ADDR(0x00001350) +#define IOP310_MUQBAR (volatile u32 *)IOP310_REG_ADDR(0x00001354) +#define IOP310_MUIFHPR (volatile u32 *)IOP310_REG_ADDR(0x00001360) +#define IOP310_MUIFTPR (volatile u32 *)IOP310_REG_ADDR(0x00001364) +#define IOP310_MUIPHPR (volatile u32 *)IOP310_REG_ADDR(0x00001368) +#define IOP310_MUIPTPR (volatile u32 *)IOP310_REG_ADDR(0x0000136C) +#define IOP310_MUOFHPR (volatile u32 *)IOP310_REG_ADDR(0x00001370) +#define IOP310_MUOFTPR (volatile u32 *)IOP310_REG_ADDR(0x00001374) +#define IOP310_MUOPHPR (volatile u32 *)IOP310_REG_ADDR(0x00001378) +#define IOP310_MUOPTPR (volatile u32 *)IOP310_REG_ADDR(0x0000137C) +#define IOP310_MUIAR (volatile u32 *)IOP310_REG_ADDR(0x00001380) +/* DMA Controller 0x00001400 through 0x000014FF */ +#define IOP310_DMA0CCR (volatile u32 *)IOP310_REG_ADDR(0x00001400) +#define IOP310_DMA0CSR (volatile u32 *)IOP310_REG_ADDR(0x00001404) +/* Reserved 0x001408 through 0x00140B */ +#define IOP310_DMA0DAR (volatile u32 *)IOP310_REG_ADDR(0x0000140C) +#define IOP310_DMA0NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001410) +#define IOP310_DMA0PADR (volatile u32 *)IOP310_REG_ADDR(0x00001414) +#define IOP310_DMA0PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001418) +#define IOP310_DMA0LADR (volatile u32 *)IOP310_REG_ADDR(0x0000141C) +#define IOP310_DMA0BCR (volatile u32 *)IOP310_REG_ADDR(0x00001420) +#define IOP310_DMA0DCR (volatile u32 *)IOP310_REG_ADDR(0x00001424) +/* Reserved 0x00001428 through 0x0000143F */ +#define IOP310_DMA1CCR (volatile u32 *)IOP310_REG_ADDR(0x00001440) +#define IOP310_DMA1CSR (volatile u32 *)IOP310_REG_ADDR(0x00001444) +/* Reserved 0x00001448 through 0x0000144B */ +#define IOP310_DMA1DAR (volatile u32 *)IOP310_REG_ADDR(0x0000144C) +#define IOP310_DMA1NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001450) +#define IOP310_DMA1PADR (volatile u32 *)IOP310_REG_ADDR(0x00001454) +#define IOP310_DMA1PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001458) +#define IOP310_DMA1LADR (volatile u32 *)IOP310_REG_ADDR(0x0000145C) +#define IOP310_DMA1BCR (volatile u32 *)IOP310_REG_ADDR(0x00001460) +#define IOP310_DMA1DCR (volatile u32 *)IOP310_REG_ADDR(0x00001464) +/* Reserved 0x00001468 through 0x0000147F */ +#define IOP310_DMA2CCR (volatile u32 *)IOP310_REG_ADDR(0x00001480) +#define IOP310_DMA2CSR (volatile u32 *)IOP310_REG_ADDR(0x00001484) +/* Reserved 0x00001488 through 0x0000148B */ +#define IOP310_DMA2DAR (volatile u32 *)IOP310_REG_ADDR(0x0000148C) +#define IOP310_DMA2NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001490) +#define IOP310_DMA2PADR (volatile u32 *)IOP310_REG_ADDR(0x00001494) +#define IOP310_DMA2PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001498) +#define IOP310_DMA2LADR (volatile u32 *)IOP310_REG_ADDR(0x0000149C) +#define IOP310_DMA2BCR (volatile u32 *)IOP310_REG_ADDR(0x000014A0) +#define IOP310_DMA2DCR (volatile u32 *)IOP310_REG_ADDR(0x000014A4) + +/* Memory controller 0x00001500 through 0x0015FF */ + +/* core interface unit 0x00001640 - 0x0000167F */ +#define IOP310_CIUISR (volatile u32 *)IOP310_REG_ADDR(0x00001644) + +/* PCI and Peripheral Interrupt Controller 0x00001700 - 0x0000171B */ +#define IOP310_IRQISR (volatile u32 *)IOP310_REG_ADDR(0x00001700) +#define IOP310_FIQ2ISR (volatile u32 *)IOP310_REG_ADDR(0x00001704) +#define IOP310_FIQ1ISR (volatile u32 *)IOP310_REG_ADDR(0x00001708) +#define IOP310_PDIDR (volatile u32 *)IOP310_REG_ADDR(0x00001710) + +/* AAU registers. DJ 0x00001800 - 0x00001838 */ +#define IOP310_AAU_ACR (volatile u32 *)IOP310_REG_ADDR(0x00001800) +#define IOP310_AAU_ASR (volatile u32 *)IOP310_REG_ADDR(0x00001804) +#define IOP310_AAU_ADAR (volatile u32 *)IOP310_REG_ADDR(0x00001808) +#define IOP310_AAU_ANDAR (volatile u32 *)IOP310_REG_ADDR(0x0000180C) +#define IOP310_AAU_SAR1 (volatile u32 *)IOP310_REG_ADDR(0x00001810) +#define IOP310_AAU_SAR2 (volatile u32 *)IOP310_REG_ADDR(0x00001814) +#define IOP310_AAU_SAR3 (volatile u32 *)IOP310_REG_ADDR(0x00001818) +#define IOP310_AAU_SAR4 (volatile u32 *)IOP310_REG_ADDR(0x0000181C) +#define IOP310_AAU_DAR (volatile u32 *)IOP310_REG_ADDR(0x00001820) +#define IOP310_AAU_ABCR (volatile u32 *)IOP310_REG_ADDR(0x00001824) +#define IOP310_AAU_ADCR (volatile u32 *)IOP310_REG_ADDR(0x00001828) +#define IOP310_AAU_SAR5 (volatile u32 *)IOP310_REG_ADDR(0x0000182C) +#define IOP310_AAU_SAR6 (volatile u32 *)IOP310_REG_ADDR(0x00001830) +#define IOP310_AAU_SAR7 (volatile u32 *)IOP310_REG_ADDR(0x00001834) +#define IOP310_AAU_SAR8 (volatile u32 *)IOP310_REG_ADDR(0x00001838) + +#endif // _IOP310_HW_H_ diff -Nru a/include/asm-arm/arch-iop3xx/iop321-irqs.h b/include/asm-arm/arch-iop3xx/iop321-irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iop321-irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,105 @@ +/* + * linux/include/asm-arm/arch-iop3xx/irqs.h + * + * Author: Rory Bolt + * Copyright: (C) 2002 Rory Bolt + * + * 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 IOP321_IRQS_H +#define IOP321_IRQS_H + +/* + * IOP80321 chipset interrupts + */ +#define IOP321_IRQ_OFS 0 +#define IOP321_IRQ(x) (IOP321_IRQ_OFS + (x)) + +/* + * On IRQ or FIQ register + */ +#define IRQ_IOP321_DMA0_EOT IOP321_IRQ(0) +#define IRQ_IOP321_DMA0_EOC IOP321_IRQ(1) +#define IRQ_IOP321_DMA1_EOT IOP321_IRQ(2) +#define IRQ_IOP321_DMA1_EOC IOP321_IRQ(3) +#define IRQ_IOP321_RSVD_4 IOP321_IRQ(4) +#define IRQ_IOP321_RSVD_5 IOP321_IRQ(5) +#define IRQ_IOP321_AA_EOT IOP321_IRQ(6) +#define IRQ_IOP321_AA_EOC IOP321_IRQ(7) +#define IRQ_IOP321_CORE_PMON IOP321_IRQ(8) +#define IRQ_IOP321_TIMER0 IOP321_IRQ(9) +#define IRQ_IOP321_TIMER1 IOP321_IRQ(10) +#define IRQ_IOP321_I2C_0 IOP321_IRQ(11) +#define IRQ_IOP321_I2C_1 IOP321_IRQ(12) +#define IRQ_IOP321_MESSAGING IOP321_IRQ(13) +#define IRQ_IOP321_ATU_BIST IOP321_IRQ(14) +#define IRQ_IOP321_PERFMON IOP321_IRQ(15) +#define IRQ_IOP321_CORE_PMU IOP321_IRQ(16) +#define IRQ_IOP321_BIU_ERR IOP321_IRQ(17) +#define IRQ_IOP321_ATU_ERR IOP321_IRQ(18) +#define IRQ_IOP321_MCU_ERR IOP321_IRQ(19) +#define IRQ_IOP321_DMA0_ERR IOP321_IRQ(20) +#define IRQ_IOP321_DMA1_ERR IOP321_IRQ(21) +#define IRQ_IOP321_RSVD_22 IOP321_IRQ(22) +#define IRQ_IOP321_AA_ERR IOP321_IRQ(23) +#define IRQ_IOP321_MSG_ERR IOP321_IRQ(24) +#define IRQ_IOP321_SSP IOP321_IRQ(25) +#define IRQ_IOP321_RSVD_26 IOP321_IRQ(26) +#define IRQ_IOP321_XINT0 IOP321_IRQ(27) +#define IRQ_IOP321_XINT1 IOP321_IRQ(28) +#define IRQ_IOP321_XINT2 IOP321_IRQ(29) +#define IRQ_IOP321_XINT3 IOP321_IRQ(30) +#define IRQ_IOP321_HPI IOP321_IRQ(31) + +#define NR_IOP321_IRQS (IOP321_IRQ(31) + 1) + +#define NR_IRQS NR_IOP321_IRQS + + +/* + * Interrupts available on the IQ80321 board + */ + +/* + * On board devices + */ +#define IRQ_IQ80321_I82544 IRQ_IOP321_XINT0 +#define IRQ_IQ80321_UART IRQ_IOP321_XINT1 + +/* + * PCI interrupts + */ +#define IRQ_IQ80321_INTA IRQ_IOP321_XINT0 +#define IRQ_IQ80321_INTB IRQ_IOP321_XINT1 +#define IRQ_IQ80321_INTC IRQ_IOP321_XINT2 +#define IRQ_IQ80321_INTD IRQ_IOP321_XINT3 + +/* + * Interrupts available on the IQ31244 board + */ +/* + * On board devices + */ +#define IRQ_IQ31244_I82546 IRQ_IOP321_XINT0 +#define IRQ_IQ31244_UART IRQ_IOP321_XINT1 + +#define IRQ_IQ31244_SATA0 IRQ_IOP321_XINT2 +#define IRQ_IQ31244_SATA1 IRQ_IOP321_XINT2 +#define IRQ_IQ31244_SATA2 IRQ_IOP321_XINT2 +#define IRQ_IQ31244_SATA3 IRQ_IOP321_XINT2 + +/* + * PCI interrupts + */ +#define IRQ_IQ31244_INTA IRQ_IOP321_XINT0 +#define IRQ_IQ31244_INTB IRQ_IOP321_XINT1 +#define IRQ_IQ31244_INTC IRQ_IOP321_XINT2 +#define IRQ_IQ31244_INTD IRQ_IOP321_XINT3 + +#define XSCALE_PMU_IRQ IRQ_IOP321_CORE_PMU + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/iop321.h b/include/asm-arm/arch-iop3xx/iop321.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iop321.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,201 @@ +/* + * linux/include/asm/arch-iop3xx/iop321.h + * + * Intel IOP321 Chip definitions + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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 _IOP321_HW_H_ +#define _IOP321_HW_H_ + +#ifndef __ASSEMBLY__ +#define iop_is_321() ((processor_id & 0xfffff7e0) == 0x69052420) +#endif + +/* + * IOP321 I/O and Mem space regions for PCI autoconfiguration + */ +#define IOP321_PCI_LOWER_IO 0x90000000 +#define IOP321_PCI_UPPER_IO 0x9000ffff +#define IOP321_PCI_LOWER_MEM 0x80000000 +#define IOP321_PCI_UPPER_MEM 0x83ffffff + +#define IOP321_PCI_WINDOW_SIZE 64 * 0x100000 + +/* + * IOP321 chipset registers + */ +#define IOP321_VIRT_MEM_BASE 0xfff00000 /* chip virtual mem address*/ +#define IOP321_PHY_MEM_BASE 0xffffe000 /* chip physical memory address */ +#define IOP321_REG_ADDR(reg) (IOP321_VIRT_MEM_BASE | (reg)) + +/* Reserved 0x00000000 through 0x000000FF */ + +/* Address Translation Unit 0x00000100 through 0x000001FF */ +#define IOP321_ATUVID (volatile u16 *)IOP321_REG_ADDR(0x00000100) +#define IOP321_ATUDID (volatile u16 *)IOP321_REG_ADDR(0x00000102) +#define IOP321_ATUCMD (volatile u16 *)IOP321_REG_ADDR(0x00000104) +#define IOP321_ATUSR (volatile u16 *)IOP321_REG_ADDR(0x00000106) +#define IOP321_ATURID (volatile u8 *)IOP321_REG_ADDR(0x00000108) +#define IOP321_ATUCCR (volatile u32 *)IOP321_REG_ADDR(0x00000109) +#define IOP321_ATUCLSR (volatile u8 *)IOP321_REG_ADDR(0x0000010C) +#define IOP321_ATULT (volatile u8 *)IOP321_REG_ADDR(0x0000010D) +#define IOP321_ATUHTR (volatile u8 *)IOP321_REG_ADDR(0x0000010E) +#define IOP321_ATUBIST (volatile u8 *)IOP321_REG_ADDR(0x0000010F) +#define IOP321_IABAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000110) +#define IOP321_IAUBAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000114) +#define IOP321_IABAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000118) +#define IOP321_IAUBAR1 (volatile u32 *)IOP321_REG_ADDR(0x0000011C) +#define IOP321_IABAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000120) +#define IOP321_IAUBAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000124) +#define IOP321_ASVIR (volatile u16 *)IOP321_REG_ADDR(0x0000012C) +#define IOP321_ASIR (volatile u16 *)IOP321_REG_ADDR(0x0000012E) +#define IOP321_ERBAR (volatile u32 *)IOP321_REG_ADDR(0x00000130) +/* Reserved 0x00000134 through 0x0000013B */ +#define IOP321_ATUILR (volatile u8 *)IOP321_REG_ADDR(0x0000013C) +#define IOP321_ATUIPR (volatile u8 *)IOP321_REG_ADDR(0x0000013D) +#define IOP321_ATUMGNT (volatile u8 *)IOP321_REG_ADDR(0x0000013E) +#define IOP321_ATUMLAT (volatile u8 *)IOP321_REG_ADDR(0x0000013F) +#define IOP321_IALR0 (volatile u32 *)IOP321_REG_ADDR(0x00000140) +#define IOP321_IATVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000144) +#define IOP321_ERLR (volatile u32 *)IOP321_REG_ADDR(0x00000148) +#define IOP321_ERTVR (volatile u32 *)IOP321_REG_ADDR(0x0000014C) +#define IOP321_IALR1 (volatile u32 *)IOP321_REG_ADDR(0x00000150) +#define IOP321_IALR2 (volatile u32 *)IOP321_REG_ADDR(0x00000154) +#define IOP321_IATVR2 (volatile u32 *)IOP321_REG_ADDR(0x00000158) +#define IOP321_OIOWTVR (volatile u32 *)IOP321_REG_ADDR(0x0000015C) +#define IOP321_OMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000160) +#define IOP321_OUMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000164) +#define IOP321_OMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x00000168) +#define IOP321_OUMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x0000016C) +/* Reserved 0x00000170 through 0x00000177*/ +#define IOP321_OUDWTVR (volatile u32 *)IOP321_REG_ADDR(0x00000178) +/* Reserved 0x0000017C through 0x0000017F*/ +#define IOP321_ATUCR (volatile u32 *)IOP321_REG_ADDR(0x00000180) +#define IOP321_PCSR (volatile u32 *)IOP321_REG_ADDR(0x00000184) +#define IOP321_ATUISR (volatile u32 *)IOP321_REG_ADDR(0x00000188) +#define IOP321_ATUIMR (volatile u32 *)IOP321_REG_ADDR(0x0000018C) +#define IOP321_IABAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000190) +#define IOP321_IAUBAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000194) +#define IOP321_IALR3 (volatile u32 *)IOP321_REG_ADDR(0x00000198) +#define IOP321_IATVR3 (volatile u32 *)IOP321_REG_ADDR(0x0000019C) +/* Reserved 0x000001A0 through 0x000001A3*/ +#define IOP321_OCCAR (volatile u32 *)IOP321_REG_ADDR(0x000001A4) +/* Reserved 0x000001A8 through 0x000001AB*/ +#define IOP321_OCCDR (volatile u32 *)IOP321_REG_ADDR(0x000001AC) +/* Reserved 0x000001B0 through 0x000001BB*/ +#define IOP321_PDSCR (volatile u32 *)IOP321_REG_ADDR(0x000001BC) +#define IOP321_PMCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001C0) +#define IOP321_PMNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001C1) +#define IOP321_APMCR (volatile u16 *)IOP321_REG_ADDR(0x000001C2) +#define IOP321_APMCSR (volatile u16 *)IOP321_REG_ADDR(0x000001C4) +/* Reserved 0x000001C6 through 0x000001DF */ +#define IOP321_PCIXCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001E0) +#define IOP321_PCIXNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001E1) +#define IOP321_PCIXCMD (volatile u16 *)IOP321_REG_ADDR(0x000001E2) +#define IOP321_PCIXSR (volatile u32 *)IOP321_REG_ADDR(0x000001E4) +#define IOP321_PCIIRSR (volatile u32 *)IOP321_REG_ADDR(0x000001EC) + +/* Messaging Unit 0x00000300 through 0x000003FF */ +/* DMA Controller 0x00000400 through 0x000004FF */ +#define IOP321_DMA0_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000400) +#define IOP321_DMA0_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000404) +#define IOP321_DMA0_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000040c) +#define IOP321_DMA0_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000410) +#define IOP321_DMA0_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000414) +#define IOP321_DMA0_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000418) +#define IOP321_DMA0_LADR (volatile u32 *)IOP321_REG_ADDR(0x0000041c) +#define IOP321_DMA0_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000420) +#define IOP321_DMA0_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000424) +#define IOP321_DMA1_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000440) +#define IOP321_DMA1_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000444) +#define IOP321_DMA1_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000044c) +#define IOP321_DMA1_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000450) +#define IOP321_DMA1_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000454) +#define IOP321_DMA1_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000458) +#define IOP321_DMA1_LADR (volatile u32 *)IOP321_REG_ADDR(0x0000045c) +#define IOP321_DMA1_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000460) +#define IOP321_DMA1_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000464) + +/* Memory controller 0x00000500 through 0x0005FF */ +/* Peripheral bus interface unit 0x00000680 through 0x0006FF */ +/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */ +/* Internal arbitration unit 0x00000780 through 0x0007BF */ + +/* GPIO */ +#define IOP321_GPOE (volatile u32 *)IOP321_REG_ADDR(0x000007c4) +#define IOP321_GPID (volatile u32 *)IOP321_REG_ADDR(0x000007c8) +#define IOP321_GPOD (volatile u32 *)IOP321_REG_ADDR(0x000007cc) + +/* Interrupt Controller */ +#define IOP321_INTCTL (volatile u32 *)IOP321_REG_ADDR(0x000007D0) +#define IOP321_INTSTR (volatile u32 *)IOP321_REG_ADDR(0x000007D4) +#define IOP321_IINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007D8) +#define IOP321_FINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007DC) + +/* Timers */ + +#define IOP321_TU_TMR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E0) +#define IOP321_TU_TMR1 (volatile u32 *)IOP321_REG_ADDR(0x000007E4) + +#define IOP321_TMR_TC 0x01 +#define IOP321_TMR_EN 0x02 +#define IOP321_TMR_RELOAD 0x04 +#define IOP321_TMR_PRIVILEGED 0x09 + +#define IOP321_TMR_RATIO_1_1 0x00 +#define IOP321_TMR_RATIO_4_1 0x10 +#define IOP321_TMR_RATIO_8_1 0x20 +#define IOP321_TMR_RATIO_16_1 0x30 + +#define IOP321_TU_TCR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E8) +#define IOP321_TU_TCR1 (volatile u32 *)IOP321_REG_ADDR(0x000007EC) +#define IOP321_TU_TRR0 (volatile u32 *)IOP321_REG_ADDR(0x000007F0) +#define IOP321_TU_TRR1 (volatile u32 *)IOP321_REG_ADDR(0x000007F4) +#define IOP321_TU_TISR (volatile u32 *)IOP321_REG_ADDR(0x000007F8) +#define IOP321_TU_WDTCR (volatile u32 *)IOP321_REG_ADDR(0x000007FC) + +#ifndef __ASSEMBLY__ +#define intctl_read(val) asm volatile("mrc p6,0,%0,c0,c0,0":"=r" (val)) +#define _intctl_write(val) asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val)) +#define intstr_read(val) asm volatile("mrc p6,0,%0,c4,c0,0":"=r" (val)) +#define _intstr_write(val) asm volatile("mcr p6,0,%0,c4,c0,0"::"r" (val)) + +static inline void intctl_write(u32 val) { _intctl_write(val); } +static inline void intstr_write(u32 val) { _intstr_write(val); } +#endif + +/* Application accelerator unit 0x00000800 - 0x000008FF */ +#define IOP321_AAU_ACR (volatile u32 *)IOP321_REG_ADDR(0x00000800) +#define IOP321_AAU_ASR (volatile u32 *)IOP321_REG_ADDR(0x00000804) +#define IOP321_AAU_ADAR (volatile u32 *)IOP321_REG_ADDR(0x00000808) +#define IOP321_AAU_ANDAR (volatile u32 *)IOP321_REG_ADDR(0x0000080C) +#define IOP321_AAU_SAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000810) +/* SAR2...SAR32 0x00000814 - 0x000008A4 */ +#define IOP321_AAU_DAR (volatile u32 *)IOP321_REG_ADDR(0x00000820) +#define IOP321_AAU_ABCR (volatile u32 *)IOP321_REG_ADDR(0x00000824) +#define IOP321_AAU_ADCR (volatile u32 *)IOP321_REG_ADDR(0x00000828) +#define IOP321_AAU_EDCR0 (volatile u32 *)IOP321_REG_ADDR(0x0000083c) +#define IOP321_AAU_EDCR1 (volatile u32 *)IOP321_REG_ADDR(0x00000860) +#define IOP321_AAU_EDCR2 (volatile u32 *)IOP321_REG_ADDR(0x00000884) + +/* SSP serial port unit 0x00001600 - 0x0000167F */ +/* I2C bus interface unit 0x00001680 - 0x000016FF */ +#define IOP321_I2C_ICR0 (volatile u32 *)IOP321_REG_ADDR(0x00001680) +#define IOP321_I2C_ICR1 (volatile u32 *)IOP321_REG_ADDR(0x000016a0) +#define IOP321_I2C_ISR0 (volatile u32 *)IOP321_REG_ADDR(0x00001684) +#define IOP321_I2C_ISR1 (volatile u32 *)IOP321_REG_ADDR(0x000016a4) +#define IOP321_I2C_ISAR0 (volatile u32 *)IOP321_REG_ADDR(0x00001688) +#define IOP321_I2C_ISAR1 (volatile u32 *)IOP321_REG_ADDR(0x000016a8) +#define IOP321_I2C_IDBR0 (volatile u32 *)IOP321_REG_ADDR(0x0000168c) +#define IOP321_I2C_IDBR1 (volatile u32 *)IOP321_REG_ADDR(0x000016ac) +#define IOP321_I2C_IBMR0 (volatile u32 *)IOP321_REG_ADDR(0x00001694) +#define IOP321_I2C_IBMR1 (volatile u32 *)IOP321_REG_ADDR(0x000016b4) + +#endif // _IOP321_HW_H_ diff -Nru a/include/asm-arm/arch-iop3xx/iq80310.h b/include/asm-arm/arch-iop3xx/iq80310.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iq80310.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,30 @@ +/* + * linux/include/asm/arch-iop80310/iq80310.h + * + * Intel IQ-80310 evaluation board registers + */ + +#ifndef _IQ80310_H_ +#define _IQ80310_H_ + +#define IQ80310_RAMBASE 0xa0000000 +#define IQ80310_UART1 0xfe800000 /* UART #1 */ +#define IQ80310_UART2 0xfe810000 /* UART #2 */ +#define IQ80310_INT_STAT 0xfe820000 /* Interrupt (XINT3#) Status */ +#define IQ80310_BOARD_REV 0xfe830000 /* Board revision register */ +#define IQ80310_CPLD_REV 0xfe840000 /* CPLD revision register */ +#define IQ80310_7SEG_1 0xfe840000 /* 7-Segment MSB */ +#define IQ80310_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */ +#define IQ80310_PCI_INT_STAT 0xfe850000 /* PCI Interrupt Status */ +#define IQ80310_INT_MASK 0xfe860000 /* Interrupt (XINT3#) Mask */ +#define IQ80310_BACKPLANE 0xfe870000 /* Backplane Detect */ +#define IQ80310_TIMER_LA0 0xfe880000 /* Timer LA0 */ +#define IQ80310_TIMER_LA1 0xfe890000 /* Timer LA1 */ +#define IQ80310_TIMER_LA2 0xfe8a0000 /* Timer LA2 */ +#define IQ80310_TIMER_LA3 0xfe8b0000 /* Timer LA3 */ +#define IQ80310_TIMER_EN 0xfe8c0000 /* Timer Enable */ +#define IQ80310_ROTARY_SW 0xfe8d0000 /* Rotary Switch */ +#define IQ80310_JTAG 0xfe8e0000 /* JTAG Port Access */ +#define IQ80310_BATT_STAT 0xfe8f0000 /* Battery Status */ + +#endif // _IQ80310_H_ diff -Nru a/include/asm-arm/arch-iop3xx/iq80321.h b/include/asm-arm/arch-iop3xx/iq80321.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/iq80321.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,17 @@ +/* + * linux/include/asm/arch-iop321/iq80321.h + * + * Intel IQ-80321 evaluation board registers + */ + +#ifndef _IQ80321_H_ +#define _IQ80321_H_ + +#define IQ80321_RAMBASE 0xa0000000 +#define IQ80321_UART1 0xfe800000 /* UART #1 */ +#define IQ80321_7SEG_1 0xfe840000 /* 7-Segment MSB */ +#define IQ80321_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */ +#define IQ80321_ROTARY_SW 0xfe8d0000 /* Rotary Switch */ +#define IQ80321_BATT_STAT 0xfe8f0000 /* Battery Status */ + +#endif // _IQ80321_H_ diff -Nru a/include/asm-arm/arch-iop3xx/irq.h b/include/asm-arm/arch-iop3xx/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/irq.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-iop80310/irq.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 fixup_irq(irq) (irq) + + diff -Nru a/include/asm-arm/arch-iop3xx/irqs.h b/include/asm-arm/arch-iop3xx/irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,25 @@ +/* + * linux/include/asm-arm/arch-iop310/irqs.h + * + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * + */ + +/* + * Whic iop3xx implementation is this? + */ +#ifdef CONFIG_ARCH_IOP310 + +#include "iop310-irqs.h" + +#else + +#include "iop321-irqs.h" + +#endif + diff -Nru a/include/asm-arm/arch-iop3xx/memory.h b/include/asm-arm/arch-iop3xx/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/memory.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,62 @@ +/* + * linux/include/asm-arm/arch-iop80310/memory.h + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + + +#define TASK_SIZE ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +#define PAGE_OFFSET ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0xa0000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __bus_to_virt__is_a_macro + +#ifdef CONFIG_ARCH_IOP310 + +#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP310_SIATVR)) | ((*IOP310_SIABAR) & 0xfffffff0)) + +#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP310_SIALR)) | ( *IOP310_SIATVR))) + +#elif defined(CONFIG_ARCH_IOP321) + +#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP321_IATVR2)) | ((*IOP321_IABAR2) & 0xfffffff0)) + +#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP321_IALR2)) | ( *IOP321_IATVR2))) + +#endif + +/* boot mem allocate global pointer for MU circular queues QBAR */ +#ifdef CONFIG_IOP3XX_MU +extern void *mu_mem; +#endif + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/message.h b/include/asm-arm/arch-iop3xx/message.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/message.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,118 @@ +/* + * Definitions for IQ80310 messageing unit + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2001 Intel 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. + * + */ + +#ifndef _IOP310_MU_H_ +#define _IOP310_MU_H_ + +#define MUDB_PCI_INTD 0x80000000 +#define MUDB_PCI_INTC 0x40000000 +#define MUDB_PCI_INTB 0x20000000 +#define MUDB_PCI_INTA 0x10000000 +#define MUDB_PCI_SOFT27 0x08000000 +#define MUDB_PCI_SOFT26 0x04000000 +#define MUDB_PCI_SOFT25 0x02000000 +#define MUDB_PCI_SOFT24 0x01000000 +#define MUDB_PCI_SOFT23 0x00800000 +#define MUDB_PCI_SOFT22 0x00400000 +#define MUDB_PCI_SOFT21 0x00200000 +#define MUDB_PCI_SOFT20 0x00100000 +#define MUDB_PCI_SOFT19 0x00080000 +#define MUDB_PCI_SOFT18 0x00040000 +#define MUDB_PCI_SOFT17 0x00020000 +#define MUDB_PCI_SOFT16 0x00010000 +#define MUDB_PCI_SOFT15 0x00008000 +#define MUDB_PCI_SOFT14 0x00004000 +#define MUDB_PCI_SOFT13 0x00002000 +#define MUDB_PCI_SOFT12 0x00001000 +#define MUDB_PCI_SOFT11 0x00000800 +#define MUDB_PCI_SOFT10 0x00000400 +#define MUDB_PCI_SOFT9 0x00000200 +#define MUDB_PCI_SOFT8 0x00000100 +#define MUDB_PCI_SOFT7 0x00000080 +#define MUDB_PCI_SOFT6 0x00000040 +#define MUDB_PCI_SOFT5 0x00000020 +#define MUDB_PCI_SOFT4 0x00000010 +#define MUDB_PCI_SOFT3 0x00000008 +#define MUDB_PCI_SOFT2 0x00000004 +#define MUDB_PCI_SOFT1 0x00000002 +#define MUDB_PCI_SOFT0 0x00000001 + +#define MUCR_QUEUE_ENABLE 0x0001 +#define MUCR_QUEUE_4K 0x0002 +#define MUCR_QUEUE_8K 0x0004 +#define MUCR_QUEUE_16K 0x0008 +#define MUCR_QUEUE_32K 0x0010 +#define MUCR_QUEUE_64K 0x0020 + +#define QUEUE_16K 0x04000 +#define QUEUE_32K 0x08000 +#define QUEUE_64K 0x10000 +#define QUEUE_128K 0x20000 +#define QUEUE_256K 0x40000 + +#define ENTRY_4K 4000 +#define ENTRY_8K 8000 +#define ENTRY_16K 16000 +#define ENTRY_32K 32000 +#define ENTRY_64K 64000 + +/* MU Message Descriptors */ +typedef struct _mu_msg_desc +{ + struct list_head link; /* queue entry */ + u8 reg_num; /* register number */ + u32 message; /* Message content */ +} mu_msg_desc_t; + +/* MU msg callback type */ +typedef void (*mu_msg_cb_t) (mu_msg_desc_t *); + +/* MU Doorbell callback type*/ +typedef void (*mu_db_cb_t) (u32); + + +/* message frame list descriptor */ +typedef struct _mfa_list +{ + u32 mfa; /* message frame address */ + struct _mfa_list *next_list; /* pointer to next list element */ +} mfa_list_t; + +/* MU CQ callback type */ +typedef void (*mu_cq_cb_t) (u32); + +/* MU IR callback type */ +typedef void (*mu_ir_cb_t) (u32); + + +/* prototypes */ +int mu_msg_request(u32 *); +int mu_msg_set_callback(u32, u8, mu_msg_cb_t); +int mu_msg_post(u32, u32, u8); +int mu_msg_free(u32, u8); +int mu_db_request(u32 *); +int mu_db_set_callback(u32, mu_db_cb_t); +void mu_db_ring(u32, u32); +int mu_db_free(u32); +int mu_cq_request(u32 *, u32); +int mu_cq_inbound_init(u32, mfa_list_t *, u32, mu_cq_cb_t); +int mu_cq_enable(u32); +u32 mu_cq_get_frame(u32); +int mu_cq_post_frame(u32, u32); +int mu_cq_free(u32); +int mu_ir_request(u32 *); +int mu_ir_set_callback(u32, mu_ir_cb_t); +int mu_ir_free(u32); +void mu_set_irq_threshold(u32, int); + +#endif +/* EOF */ diff -Nru a/include/asm-arm/arch-iop3xx/param.h b/include/asm-arm/arch-iop3xx/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/param.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-iop80310/param.h + */ diff -Nru a/include/asm-arm/arch-iop3xx/pci-bridge.h b/include/asm-arm/arch-iop3xx/pci-bridge.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pci-bridge.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * include/asm-arm/arch-iop310/pci-bridge.h + * + * Generic PCI hose support for Xscale/ARM. To eventually be + * moved to a more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 __KERNEL__ +#ifndef _ASM_PCI_BRIDGE_H +#define _ASM_PCI_BRIDGE_H + +struct device_node; +struct pci_controller; + +/* Get the PCI host controller for a bus */ +extern struct pci_controller* pci_bus_to_hose(int bus); + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct resource io_space; + struct resource mem_space; +}; + +/* These are used for config access before all the PCI probing + has been done. */ +int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 *val); +int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 *val); +int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 *val); +int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 val); +int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val); +int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val); +#endif +#endif /* __KERNEL__ */ diff -Nru a/include/asm-arm/arch-iop3xx/pci.h b/include/asm-arm/arch-iop3xx/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pci.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,36 @@ +/* + * include/asm-arm/arch-xscale/pci.h + * + * Generic PCI support for Xscale/ARM. To eventually be moved to a + * more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ASM_ARCH_PCI_H +#define _ASM_ARCH_PCI_H + +extern struct pci_controller* pcibios_alloc_controller(void); +extern void pcibios_allocate_resources(void); +extern void pci_exclude_device(unsigned char, unsigned char); +extern struct pci_dev * fake_pci_dev(struct pci_controller *, int, int); +extern u8 common_swizzle(struct pci_dev *, u8 *); + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. + */ +#define PCI_IRQ_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ + _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ + _ctl_; }) + +#endif /* _ASM_ARCH_PCI_H */ diff -Nru a/include/asm-arm/arch-iop3xx/pci_auto.h b/include/asm-arm/arch-iop3xx/pci_auto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pci_auto.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-iop310/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ARM_MACH_XSCALE_PCI_AUTO_H +#define _ARM_MACH_XSCALE_PCI_AUTO_H + +#include "pci-bridge.h" + +extern int pciauto_bus_scan(struct pci_controller *, int); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* _ARM_MACH_XSCALE_PCI_AUTO_H */ diff -Nru a/include/asm-arm/arch-iop3xx/pci_iop310.h b/include/asm-arm/arch-iop3xx/pci_iop310.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pci_iop310.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,21 @@ +/* + * include/asm-arm/arch-iop310/pci_iop310.h + * + * IOP310 PCI support. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _PCI_IOP310_H +#define _PCI_IOP310_H + +extern struct pci_ops iop310_ops; +extern void iop310_init(void); + +#endif /* _PCI_IOP310_H */ diff -Nru a/include/asm-arm/arch-iop3xx/pci_iop321.h b/include/asm-arm/arch-iop3xx/pci_iop321.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pci_iop321.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,20 @@ +/* + * include/asm-arm/arch-iop3xx/pci_iop321.h + * + * IOP321 PCI support. + * + * Author: Rory Bolt + * Copyright (C) 2002 Rory Bolt + * + * 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 _PCI_IOP321_H +#define _PCI_IOP321_H + +extern struct pci_ops iop321_ops; +extern void iop321_init(void); + +#endif /* _PCI_IOP321_H */ diff -Nru a/include/asm-arm/arch-iop3xx/pmon.h b/include/asm-arm/arch-iop3xx/pmon.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/pmon.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,50 @@ +/* + * Definitions for XScale 80312 PMON + * (C) 2001 Intel Corporation + * Author: Chen Chen(chen.chen@intel.com) + * + * 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 _IOP310_PMON_H_ +#define _IOP310_PMON_H_ + +/* + * Different modes for Event Select Register for intel 80312 + */ + +#define IOP310_PMON_MODE0 0x00000000 +#define IOP310_PMON_MODE1 0x00000001 +#define IOP310_PMON_MODE2 0x00000002 +#define IOP310_PMON_MODE3 0x00000003 +#define IOP310_PMON_MODE4 0x00000004 +#define IOP310_PMON_MODE5 0x00000005 +#define IOP310_PMON_MODE6 0x00000006 +#define IOP310_PMON_MODE7 0x00000007 + +typedef struct _iop310_pmon_result +{ + u32 timestamp; /* Global Time Stamp Register */ + u32 timestamp_overflow; /* Time Stamp overflow count */ + u32 event_count[14]; /* Programmable Event Counter + Registers 1-14 */ + u32 event_overflow[14]; /* Overflow counter for PECR1-14 */ +} iop310_pmon_res_t; + +/* function prototypes */ + +/* Claim IQ80312 PMON for usage */ +int iop310_pmon_claim(void); + +/* Start IQ80312 PMON */ +int iop310_pmon_start(int, int); + +/* Stop Performance Monitor Unit */ +int iop310_pmon_stop(iop310_pmon_res_t *); + +/* Release IQ80312 PMON */ +int iop310_pmon_release(int); + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/serial.h b/include/asm-arm/arch-iop3xx/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/serial.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,60 @@ +/* + * include/asm-arm/arch-iop3xx/serial.h + */ + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#ifdef CONFIG_ARCH_IQ80310 + +#define IRQ_UART1 IRQ_IQ80310_UART1 +#define IRQ_UART2 IRQ_IQ80310_UART2 + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_UART2, \ + flags: STD_COM_FLAGS, \ + iomem_base: 0xfe810000, \ + io_type: SERIAL_IO_MEM \ + }, /* ttyS0 */ \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_UART1, \ + flags: STD_COM_FLAGS, \ + iomem_base: 0xfe800000, \ + io_type: SERIAL_IO_MEM \ + } /* ttyS0 */ + +#endif // CONFIG_ARCH_IQ80310 + +#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244) + +#define RS_TABLE_SIZE 1 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + magic: 0, \ + baud_base: BASE_BAUD, \ + irq: IRQ_IOP321_XINT1, \ + flags: STD_COM_FLAGS, \ + iomem_base: 0xfe800000, \ + io_type: SERIAL_IO_MEM \ + } /* ttyS0 */ +#endif + +#define EXTRA_SERIAL_PORT_DEFNS + diff -Nru a/include/asm-arm/arch-iop3xx/system.h b/include/asm-arm/arch-iop3xx/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/system.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,35 @@ +/* + * linux/include/asm-arm/arch-iop80310/system.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + + +static inline void arch_reset(char mode) +{ +#ifdef CONFIG_ARCH_IOP321 + if (machine_is_iq80321() || machine_is_iq31244()) + *IOP321_PCSR = 0x30; +#endif + + if ( 1 && mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + /* No on-chip reset capability */ + cpu_reset(0); + } +} + diff -Nru a/include/asm-arm/arch-iop3xx/time.h b/include/asm-arm/arch-iop3xx/time.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/time.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,12 @@ +/* + * linux/include/asm-arm/arch-iop80310/time.h + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + */ + diff -Nru a/include/asm-arm/arch-iop3xx/timex.h b/include/asm-arm/arch-iop3xx/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/timex.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,32 @@ +/* + * linux/include/asm-arm/arch-iop3xx/timex.h + * + * IOP310 architecture timex specifications + */ + + + +#ifdef CONFIG_ARCH_IQ80310 + +#ifndef CONFIG_XSCALE_PMU_TIMER + +/* This is for the on-board timer */ +#define CLOCK_TICK_RATE 33000000 /* Underlying HZ */ + +#else + +/* This is for the underlying xs80200 PMU clock. We run the core @ 733MHz */ +#define CLOCK_TICK_RATE 733000000 + +#endif // IQ80310 + +#elif defined(CONFIG_ARCH_IOP3XX) /* All run at 200Mhz */ + +#define CLOCK_TICK_RATE 200000000 + + +#else + +#error "No IOP3xx timex information for this architecture" + +#endif diff -Nru a/include/asm-arm/arch-iop3xx/uncompress.h b/include/asm-arm/arch-iop3xx/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/uncompress.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/arch-iop80310/uncompress.h + */ + +#include + +#ifdef CONFIG_ARCH_IQ80310 +#define UART_BASE ((volatile unsigned char *)0xfe810000) +#elif defined(CONFIG_ARCH_IQ80321) || defined (CONFIG_ARCH_IQ31244) +#define UART_BASE ((volatile unsigned char *)0xfe800000) +#endif + +static __inline__ void putc(char c) +{ + while ((UART_BASE[5] & 0x60) != 0x60); + UART_BASE[0] = c; +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -Nru a/include/asm-arm/arch-iop3xx/vmalloc.h b/include/asm-arm/arch-iop3xx/vmalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/vmalloc.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-iop310/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (0xe8000000) diff -Nru a/include/asm-arm/arch-iop3xx/xor.h b/include/asm-arm/arch-iop3xx/xor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-iop3xx/xor.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,28 @@ +/* + * include/asm-arm/arch-iop3xx/xor.h + * + * Copyright (C) 2003 Intel Corp. + * + * 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 _ASM_ARCH_XOR_H +#define _ASM_ARCH_XOR_H + +/* + * Function prototypes + */ +void xor_iop3xxaau_2(unsigned long bytes, unsigned long *p1, unsigned long *p2); + +void xor_iop3xxaau_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3); + +void xor_iop3xxaau_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4); + +void xor_iop3xxaau_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5); + +#endif /* _ASM_ARCH_XOR_H */ diff -Nru a/include/asm-arm/arch-ixp2000/dma.h b/include/asm-arm/arch-ixp2000/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/dma.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/arch-ixdp2400/dma.h + * + * Copyright (C) 2002 Intel Corp. + * + * 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 __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff + +/* No DMA */ +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff -Nru a/include/asm-arm/arch-ixp2000/gpio.h b/include/asm-arm/arch-ixp2000/gpio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/gpio.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,55 @@ +/* + * include/asm-arm/arch-ixp2000/ixp2000-gpio.h + * + * Copyright (C) 2002 Intel 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. + */ + +/* + * IXP2000 GPIO in/out, edge/level detection for IRQs: + * IRQs are generated on Falling-edge, Rising-Edge, Level-low, Level-High + * or both Falling-edge and Rising-edge. + * This must be called *before* the corresponding IRQ is registerd. + * Use this instead of directly setting the GPIO registers. + * GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb) + */ +#ifndef _ASM_ARCH_IXP2000_GPIO_H_ +#define _ASM_ARCH_IXP2000_GPIO_H_ + +#ifndef __ASSEMBLY__ +#define GPIO_OUT 0x0 +#define GPIO_IN 0x80 + +#define IXP2000_GPIO_LOW 0 +#define IXP2000_GPIO_HIGH 1 + +#define GPIO_NO_EDGES 0 +#define GPIO_FALLING_EDGE 1 +#define GPIO_RISING_EDGE 2 +#define GPIO_BOTH_EDGES 3 +#define GPIO_LEVEL_LOW 4 +#define GPIO_LEVEL_HIGH 8 + +extern void set_GPIO_IRQ_edge(int gpio_nr, int edge); +extern void set_GPIO_IRQ_level(int gpio_nr, int level); +extern void gpio_line_config(int line, int style); + +static inline int gpio_line_get(int line) +{ + return (((*IXP2000_GPIO_PLR) >> line) & 1); +} + +static inline void gpio_line_set(int line, int value) +{ + if (value == IXP2000_GPIO_HIGH) { + ixp_reg_write(IXP2000_GPIO_POSR, BIT(line)); + } else if (value == IXP2000_GPIO_LOW) + ixp_reg_write(IXP2000_GPIO_POCR, BIT(line)); +} + +#endif /* !__ASSEMBLY__ */ +#endif /* ASM_ARCH_IXP2000_GPIO_H_ */ + diff -Nru a/include/asm-arm/arch-ixp2000/hardware.h b/include/asm-arm/arch-ixp2000/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/hardware.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/arch-ixdp2400/hardware.h + * + * Hardware definitions for IXP2000 based systems + * + * Author: Naeem M Afzal + * + * Maintainer: Deepak Saxena + * + * Copyright (C) 2001-2002 Intel Corp. + * Copyright (C) 2003 MontaVista Software, Inc. + * + * 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 __ASM_ARCH_HARDWARE_H__ +#define __ASM_ARCH_HARDWARE_H__ + +/* + * Generic chipset bits + */ +#include "ixp2000.h" +#include "gpio.h" + +/* PCI IO info */ +//#define PCIO_BASE (VIRT_PCI_IO - PHY_PCI_IO) +#define PCIO_BASE PCI_IO_VIRT_BASE + +#define PCIBIOS_MIN_IO 0x00000000 +#define PCIBIOS_MIN_MEM 0x00000000 + +#define pcibios_assign_all_busses() 0 + +/* + * board specific definitions + */ +#include "ixdp2400.h" + +#include "ixdp2800.h" + +#endif /* _ASM_ARCH_HARDWARE_H__ */ diff -Nru a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/io.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,89 @@ +/* + * linux/include/asm-arm/arch-ixdp2000/io.h + * + * Author: Naeem M Afzal + * + * Copyright (C) 2002 Intel Corp. + * + * 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 __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io_pci(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +/* + * We don't need this for now. If we get to the point where + * we need to have > 64K I/O access, we need to fix this so + * that it saves/restores the previous I/O window setting. + */ +#if 0 +static inline unsigned __ixp_io(unsigned long p) +{ + unsigned long ext = *IXP2000_PCI_ADDR_EXT & 0xffff; + + ext |= p & 0xffff0000; + + *IXP2000_PCI_ADDR_EXT = ext; + + return __io_pci(p); +} +#endif + +/* + * Generic virtual read/write + */ + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + +/* + * IXP2000 currently does not do bytelane or data swapping on + * PCI I/O cycles, so we need to override the default functions. + * + * Will retest once we have "working" silicon. + */ +#define alignb(addr) ((addr & ~3) + (3 - (addr & 3))) +#define alignw(addr) ((addr & ~2) + (2 - (addr & 2))) + +#define outb(v,p) __raw_writeb(v,alignb(__io_pci(p))) +#define outw(v,p) __raw_writew((v),alignw(__io_pci(p))) +#define outl(v,p) __raw_writel((v),__io_pci(p)) + +#define inb(p) ({ unsigned int __v = __raw_readb(alignb(__io_pci(p))); __v; }) +#define inw(p) \ + ({ unsigned int __v = (__raw_readw(alignw(__io_pci(p)))); __v; }) +#define inl(p) \ + ({ unsigned int __v = (__raw_readl(__io_pci(p))); __v; }) + +#define outsb(p,d,l) __raw_writesb(alignb(__io_pci(p)),d,l) +#define outsw(p,d,l) __raw_writesw(alignw(__io_pci(p)),d,l) +#define outsl(p,d,l) __raw_writesl(__io_pci(p),d,l) + +#define insb(p,d,l) __raw_readsb(alignb(__io_pci(p)),d,l) +#define insw(p,d,l) __raw_readsw(alignw(__io_pci(p)),d,l) +#define insl(p,d,l) __raw_readsl(__io_pci(p),d,l) + +#define __arch_ioremap __ioremap +#define __arch_iounmap __iounmap + +#endif diff -Nru a/include/asm-arm/arch-ixp2000/irq.h b/include/asm-arm/arch-ixp2000/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/irq.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-ixp2000/irq.h + * + * Copyright (C) 2002 Intel Corp. + * + * 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 fixup_irq(irq) (irq) + + diff -Nru a/include/asm-arm/arch-ixp2000/irqs.h b/include/asm-arm/arch-ixp2000/irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,118 @@ +/* + * linux/include/asm-arm/arch-ixp2000/irqs.h + * + * Original Author: Naeem Afzal + * Maintainer: Deepak Saxena + * + * Copyright: (C) 2002 Intel Corp. + * + * 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 _IRQS_H +#define _IRQS_H + +/* + * Some interrupt numbers go unused b/c the IRQ mask/ummask/status + * register has those bit reserved. We just mark those interrupts + * as invalid and this allows us to do mask/unmask with a single + * shit operation instead of having to map the IRQ number to + * a HW IRQ number. + */ +#define IRQ_IXP2000_SWI 0 /* soft interrupt */ +#define IRQ_IXP2000_ERRSUM 1 /* OR of all bits in ErrorStatus reg*/ +#define IRQ_IXP2000_UART 2 +#define IRQ_IXP2000_GPIO 3 +#define IRQ_IXP2000_TIMER1 4 +#define IRQ_IXP2000_TIMER2 5 +#define IRQ_IXP2000_TIMER3 6 +#define IRQ_IXP2000_TIMER4 7 +#define IRQ_IXP2000_PMU 8 +#define IRQ_IXP2000_SPF 9 /* Slow port framer IRQ */ +#define IRQ_IXP2000_DMA1 10 +#define IRQ_IXP2000_DMA2 11 +#define IRQ_IXP2000_DMA3 12 +#define IRQ_IXP2000_PCI_DOORBELL 13 +#define IRQ_IXP2000_ME_ATTN 14 +#define IRQ_IXP2000_PCI 15 +#define IRQ_IXP2000_THDA0 16 +#define IRQ_IXP2000_THDA1 17 +#define IRQ_IXP2000_THDA2 18 +#define IRQ_IXP2000_THDA3 19 +#define IRQ_IXP2000_THDB0 24 +#define IRQ_IXP2000_THDB1 25 +#define IRQ_IXP2000_THDB2 26 +#define IRQ_IXP2000_THDB3 27 + +/* define generic GPIOs */ +#define IRQ_IXP2000_GPIO0 32 +#define IRQ_IXP2000_GPIO1 33 +#define IRQ_IXP2000_GPIO2 34 +#define IRQ_IXP2000_GPIO3 35 +#define IRQ_IXP2000_GPIO4 36 +#define IRQ_IXP2000_GPIO5 37 +#define IRQ_IXP2000_GPIO6 38 +#define IRQ_IXP2000_GPIO7 39 + +/* split off the 2 PCI sources */ +#define IRQ_IXP2000_PCIA 40 +#define IRQ_IXP2000_PCIB 41 + +/* Int sources from IRQ_ERROR_STATUS */ +#define IRQ_IXP2000_DRAM0_MIN_ERR 42 +#define IRQ_IXP2000_DRAM0_MAJ_ERR 43 +#define IRQ_IXP2000_DRAM1_MIN_ERR 44 +#define IRQ_IXP2000_DRAM1_MAJ_ERR 45 +#define IRQ_IXP2000_DRAM2_MIN_ERR 46 +#define IRQ_IXP2000_DRAM2_MAJ_ERR 47 +#define IRQ_IXP2000_SRAM0_ERR 48 +#define IRQ_IXP2000_SRAM1_ERR 49 +#define IRQ_IXP2000_SRAM2_ERR 50 +#define IRQ_IXP2000_SRAM3_ERR 51 +#define IRQ_IXP2000_MEDIA_ERR 52 +#define IRQ_IXP2000_PCI_ERR 53 +#define IRQ_IXP2000_SP_INT 54 + +#define NR_IXP2000_IRQS 55 + +#define XSCALE_PMU_IRQ IRQ_IXP2000_PMU + +#if defined(CONFIG_ARCH_IXDP2400) +/* + * IXDP2400 specific IRQs + */ +#define IRQ_IXDP2400(x) (NR_IXP2000_IRQS + (x)) + +//#define IRQ_IXDP2400_SETHERNET IRQ_IXDP2400(0) /* Slave NPU NIC irq */ +#define IRQ_IXDP2400_INGRESS_NPU IRQ_IXDP2400(0) /* Slave NPU irq */ +#define IRQ_IXDP2400_METHERNET IRQ_IXDP2400(1) /* Master NPU NIC irq */ +#define IRQ_IXDP2400_MEDIA_PCI IRQ_IXDP2400(2) /* Media on PCI irq */ +#define IRQ_IXDP2400_MEDIA_SP IRQ_IXDP2400(3) /* Media on SlowPort */ +#define IRQ_IXDP2400_SF_PCI IRQ_IXDP2400(4) /* Sw Fab. on PCI */ +#define IRQ_IXDP2400_SF_SP IRQ_IXDP2400(5) /* Switch Fab on SP */ +#define IRQ_IXDP2400_PMC IRQ_IXDP2400(6) /* PMC slot ineterrupt*/ +#define IRQ_IXDP2400_TVM IRQ_IXDP2400(7) /* Temp & Voltage */ + +#define IRQ_IXP2000_INTERRUPT ((IRQ_IXDP2400_TVM)+1) +#define NR_IXDP2400_IRQS (IRQ_IXDP2400_TVM+1) + +#elif defined(CONFIG_ARCH_IXDP2800) +/* IXDP2800 specific IRQs */ +#define IRQ_IXDP2800(x) (NR_IXP2000_IRQS + (x)) +#define IRQ_IXDP2800_EGRESS_NIC IRQ_IXDP2800(0) +#define IRQ_IXDP2800_INGRESS_NPU IRQ_IXDP2800(1) +#define IRQ_IXDP2800_PMC_PCI IRQ_IXDP2800(2) +#define IRQ_IXDP2800_FABRIC_PCI IRQ_IXDP2800(3) +#define IRQ_IXDP2800_FABRIC IRQ_IXDP2800(4) +#define IRQ_IXDP2800_MEDIA IRQ_IXDP2800(5) + +#define IRQ_IXP2000_INTERRUPT (IRQ_IXDP2800_MEDIA) +#define NR_IXDP2800_IRQS (IRQ_IXDP2800_MEDIA+1) +#endif /* CONFIG_ARCH_XXX */ + +#undef NR_IRQS +#define NR_IRQS ((IRQ_IXP2000_INTERRUPT)+1) + +#endif /*_IRQS_H*/ diff -Nru a/include/asm-arm/arch-ixp2000/ixdp2400.h b/include/asm-arm/arch-ixp2000/ixdp2400.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/ixdp2400.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,54 @@ +/* + * inclue/asm-arm/arch-ixp2000/ixmb2400.h + * + * Register and other defines for IXDP2400 + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 _IXDP2400_H_ +#define _IXDP2400_H_ + + +/* + * On board CPLD memory map + */ +#define IXDP2400_PHY_CPLD_BASE 0xc7000000 +#define IXDP2400_VIRT_CPLD_BASE 0xd4000000 +#define IXDP2400_CPLD_SIZE 0x01000000 + + +#define IXDP2400_CPLD_REG(reg) (volatile unsigned long *)(IXDP2400_VIRT_CPLD_BASE | reg) + +#define IXDP2400_CPLD_SYSLED IXDP2400_CPLD_REG(0x0) +#define IXDP2400_CPLD_DISP_DATA IXDP2400_CPLD_REG(0x4) +#define IXDP2400_CPLD_CLOCK_SPEED IXDP2400_CPLD_REG(0x8) +#define IXDP2400_CPLD_INT IXDP2400_CPLD_REG(0xc) +#define IXDP2400_CPLD_REV IXDP2400_CPLD_REG(0x10) +#define IXDP2400_CPLD_SYS_CLK_M IXDP2400_CPLD_REG(0x14) +#define IXDP2400_CPLD_SYS_CLK_N IXDP2400_CPLD_REG(0x18) +#define IXDP2400_CPLD_INT_MASK IXDP2400_CPLD_REG(0x48) + +/* + * Interrupt register mask bits on CPLD register + */ +#define IXDP2400_MASK_INGRESS (1<<0) +#define IXDP2400_MASK_EGRESS_NIC (1<<1) /*Master Ethernet */ +#define IXDP2400_MASK_MEDIA_PCI (1<<2) /* media PCI interrupt */ +#define IXDP2400_MASK_MEDIA_SP (1<<3) /* media slow port interrupt*/ +#define IXDP2400_MASK_SF_PCI (1<<4) /* Sw Fabric PCI intrpt */ +#define IXDP2400_MASK_SF_SP (1<<5) /* SW Fabric SlowPort intrpt */ +#define IXDP2400_MASK_PMC (1<<6) +#define IXDP2400_MASK_TVM (1<<7) + +#define IXDP2400_GPIO_I2C_ENABLE 0x02 +#define IXDP2400_GPIO_SCL 0x07 +#define IXDP2400_GPIO_SDA 0x06 + +#endif /*_IXDP2400_H_ */ diff -Nru a/include/asm-arm/arch-ixp2000/ixdp2800.h b/include/asm-arm/arch-ixp2000/ixdp2800.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/ixdp2800.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,50 @@ +/* + * inclue/asm-arm/arch-ixp2000/ixdp2800.h + * + * Register and other defines for IXDP2800 + * + * Author: Jeff Daly + * + * Copyright 2002-2003 Intel Corp. + * + * 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 _IXDP2800_H_ +#define _IXDP2800_H_ + +/* CPLD interrupt register definition */ +#define IXDP2800_PHY_CPLD_BASE 0xc7000000 +#define IXDP2800_VIRT_CPLD_BASE 0xd4000000 +#define IXDP2800_CPLD_SIZE 0x01000000 + +#define IXDP2800_CPLD IXDP2800_VIRT_CPLD_BASE + +#define IXDP2800_CPLD_REG(reg) (volatile u32 *)(IXDP2800_CPLD | reg) + +#define IXDP2800_CPLD_INT IXDP2800_CPLD_REG(0x0) +#define IXDP2800_CPLD_INT_MASK IXDP2800_CPLD_REG(0x140) + +/* + * * Interrupt register mask bits on CPLD register + * */ +#define IXDP2800_MASK_EGRESS_NIC (1<<0) /*Master Ethernet */ +#define IXDP2800_MASK_INGRESS (1<<1) +#define IXDP2800_MASK_PMC (1<<2) +#define IXDP2800_MASK_FABRIC_PCI (1<<3) /* Sw Fabric PCI intrpt */ +#define IXDP2800_MASK_FABRIC_SP (1<<4) /* SW Fabric SlowPort intrpt */ +#define IXDP2800_MASK_MEDIA (1<<5) /* media slow port interrupt */ + +/* LED defines */ +#define IXDP2800_LED0_REG IXDP2800_CPLD_REG(0x10c) +#define IXDP2800_LED1_REG IXDP2800_CPLD_REG(0x108) +#define IXDP2800_LED2_REG IXDP2800_CPLD_REG(0x104) +#define IXDP2800_LED3_REG IXDP2800_CPLD_REG(0x100) + +#define IXDP2800_GPIO_I2C_ENABLE 0x05 +#define IXDP2800_GPIO_SCL 0x07 +#define IXDP2800_GPIO_SDA 0x06 + +#endif /*_IXDP2800_H_ */ diff -Nru a/include/asm-arm/arch-ixp2000/ixp2000.h b/include/asm-arm/arch-ixp2000/ixp2000.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/ixp2000.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,535 @@ +/* + * include/asm-arm/arch-ixp2000/ixp2000.h + * + * Generic register definitions for IXP2000 based systems. + * + * Original Author: Naeem Afzal + * + * Maintainer: Deepak Saxena + * + * Copyright 2002 Intel Corp. + * + * 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 _IXP2000_H_ +#define _IXP2000_H_ + +#ifndef __ASM_ARCH_HARDWARE_H__ +#error "Do not include this file directly. Instead include " +#endif + +#ifndef BIT +#define BIT(bit) (1 << (bit)) +#endif + +#define PHYS_SDRAM_BASE 0x1c000000 /* start for upper 64M */ +#define INITRD_LOCATION 0x1c600000 +#define INITRD_SIZE 0x00400000 +#define PHYS_SDRAM_SIZE (64*1024*1024) + +#define FLASH_BASE 0xc4000000 +#define MAX_FLASH_SIZE 0x04000000 + +/* + * Static I/O regions. The manual defines each region as being several + * MB in size, but all the registers are within the first 4K, so there's + * no purpose in mapping the whole region in. + */ + +#define PMU_PHYS_BASE 0xc0050000 +#define PMU_VIRT_BASE 0xfaff7000 +#define PMU_SIZE 0x1000 + +#define GLOBAL_REG_PHYS_BASE 0xc0004000 +#define GLOBAL_REG_VIRT_BASE 0xfaff8000 +#define GLOBAL_REG_SIZE 0x1000 + +#define GPIO_PHYS_BASE 0xc0010000 +#define GPIO_VIRT_BASE 0xfaff9000 +#define GPIO_SIZE 0x1000 + +#define TIMER_PHYS_BASE 0xc0020000 +#define TIMER_VIRT_BASE 0xfaffa000 +#define TIMER_SIZE 0x1000 + +#define UART_PHYS_BASE 0xc0030000 +#define UART_VIRT_BASE 0xfaffb000 +#define UART_SIZE 0x1000 + +#define SLOWPORT_CSR_PHYS_BASE 0xc0080000 +#define SLOWPORT_CSR_VIRT_BASE 0xfaffc000 +#define SLOWPORT_CSR_SIZE 0x1000 + +#define INTCTL_PHYS_BASE 0xd6000000 +#define INTCTL_VIRT_BASE 0xfaffd000 +#define INTCTL_SIZE 0x01000 + +#define PCI_CREG_PHYS_BASE 0xde000000 +#define PCI_CREG_VIRT_BASE 0xfaffe000 +#define PCI_CREG_SIZE 0x1000 + +#define PCI_CSR_PHYS_BASE 0xdf000000 +#define PCI_CSR_VIRT_BASE 0xfafff000 +#define PCI_CSR_SIZE 0x1000 + +#define PCI_CFG0_PHYS_BASE 0xda000000 +#define PCI_CFG0_VIRT_BASE 0xfb000000 +#define PCI_CFG0_SIZE 0x01000000 + +#define PCI_CFG1_PHYS_BASE 0xdb000000 +#define PCI_CFG1_VIRT_BASE 0xfc000000 +#define PCI_CFG1_SIZE 0x01000000 + +#define PCI_IO_PHYS_BASE 0xd8000000 +#define PCI_IO_VIRT_BASE 0xfd000000 +#define PCI_IO_SIZE 0x02000000 + +/* + * This is needed for all I/O (CB=00) due to an errata in IXP2400: + * + * We block interrupts b/c this must be atomic. + * + */ +#if 0 +#ifndef __ASSEMBLY__ +#if defined(CONFIG_ARCH_IXDP2400) || defined(CONFIG_ARCH_IXDP2401) +static inline void ixp_reg_write(volatile unsigned long *reg, unsigned long val) +{ + volatile unsigned long dummy; + unsigned long flags; + + + local_irq_save(flags); + *reg = val; + mb(); + dummy = *reg; + local_irq_restore(flags); +} +#else +#define ixp2000_reg_write(reg, val) (*reg = val); +#endif // IXP2400 +#endif // __ASSEMBLY__ +#endif + +#define ixp_reg_write(reg, val) (*reg = val) + +/* + * Timers + */ +#define IXP2000_TIMER_REG(x) ((volatile unsigned long*)(TIMER_VIRT_BASE+(x))) +/* Timer control */ +#define IXP2000_T1_CTL IXP2000_TIMER_REG(0x00) +#define IXP2000_T2_CTL IXP2000_TIMER_REG(0x04) +#define IXP2000_T3_CTL IXP2000_TIMER_REG(0x08) +#define IXP2000_T4_CTL IXP2000_TIMER_REG(0x0c) +/* Store initial value */ +#define IXP2000_T1_CLD IXP2000_TIMER_REG(0x10) +#define IXP2000_T2_CLD IXP2000_TIMER_REG(0x14) +#define IXP2000_T3_CLD IXP2000_TIMER_REG(0x18) +#define IXP2000_T4_CLD IXP2000_TIMER_REG(0x1c) +/* Read current value */ +#define IXP2000_T1_CSR IXP2000_TIMER_REG(0x20) +#define IXP2000_T2_CSR IXP2000_TIMER_REG(0x24) +#define IXP2000_T3_CSR IXP2000_TIMER_REG(0x28) +#define IXP2000_T4_CSR IXP2000_TIMER_REG(0x2c) +/* Clear associated timer interrupt */ +#define IXP2000_T1_CLR IXP2000_TIMER_REG(0x30) +#define IXP2000_T2_CLR IXP2000_TIMER_REG(0x34) +#define IXP2000_T3_CLR IXP2000_TIMER_REG(0x38) +#define IXP2000_T4_CLR IXP2000_TIMER_REG(0x3c) +/* Timer watchdog enable for T4 */ +#define IXP2000_TWDE IXP2000_TIMER_REG(0x40) + + +/* + * Interrupt controller registers + */ +#define IXP2000_INTCTL_REG(reg) (volatile unsigned long*)(INTCTL_VIRT_BASE | reg) +#define IXP2000_IRQ_STATUS IXP2000_INTCTL_REG(0x08) +#define IXP2000_IRQ_ENABLE IXP2000_INTCTL_REG(0x10) +#define IXP2000_IRQ_ENABLE_SET IXP2000_INTCTL_REG(0x10) +#define IXP2000_IRQ_ENABLE_CLR IXP2000_INTCTL_REG(0x18) +#define IXP2000_FIQ_ENABLE_CLR IXP2000_INTCTL_REG(0x14) +#define IXP2000_IRQ_ERR_STATUS IXP2000_INTCTL_REG(0x24) +#define IXP2000_IRQ_ERR_ENABLE_SET IXP2000_INTCTL_REG(0x2c) +#define IXP2000_FIQ_ERR_ENABLE_CLR IXP2000_INTCTL_REG(0x30) +#define IXP2000_IRQ_ERR_ENABLE_CLR IXP2000_INTCTL_REG(0x34) + +/* + * IRQ mask/unmask bits. These map 1:1 to IRQ number + */ +#define IRQ_MASK_SOFT (1 << 0) +#define IRQ_MASK_ERRSUM (1 << 1) +#define IRQ_MASK_UART (1 << 2) +#define IRQ_MASK_GPIO (1 << 3) +#define IRQ_MASK_TIMER1 (1 << 4) +#define IRQ_MASK_TIMER2 (1 << 5) +#define IRQ_MASK_TIMER3 (1 << 6) +#define IRQ_MASK_TIMER4 (1 << 7) +#define IRQ_MASK_PMU (1 << 8) +#define IRQ_MASK_SPF (1 << 9) /* Slowport Framer */ +#define IRQ_MASK_DMA1_DONE (1 << 10) +#define IRQ_MASK_DMA2_DONE (1 << 11) +#define IRQ_MASK_DMA3_DONE (1 << 12) +#define IRQ_MASK_DOORBELL (1 << 13) /* PCI Doorbell */ +#define IRQ_MASK_UENG (1 << 14) /* ME attention */ +#define IRQ_MASK_PCI (1 << 15) /* OR of INTA or INTB */ +#define IRQ_MASK_THDA0 (1 << 16) /* ThreadA 0-31 */ +#define IRQ_MASK_THDA1 (1 << 17) /* ThreadA 32-63 */ +#define IRQ_MASK_THDA2 (1 << 18) /* ThreadA 64-95 */ +#define IRQ_MASK_THDA3 (1 << 19) /* ThreadA 96-127 */ +#define IRQ_MASK_THDB0 (1 << 24) /* ThreadB 0-31 */ +#define IRQ_MASK_THDB1 (1 << 25) /* ThreadB 32-63 */ +#define IRQ_MASK_THDB2 (1 << 26) /* ThreadB 64-95 */ +#define IRQ_MASK_THDB3 (1 << 27) /* ThreadB 96-127 */ + +/* + * Mask of valid IRQs in the 32-bit IRQ register. We use + * this to mark certain IRQs as being in-valid. + */ +#define IXP2000_VALID_IRQ_MASK 0x0f0f8fff + +/* + * 16550 UART + */ +#define IXP2000_UART_BASE UART_VIRT_BASE + +/* + * PCI config register access from core + */ +#define IXP2000_PCI_CREG(reg) (volatile unsigned long*)(PCI_CREG_VIRT_BASE | reg) +#define IXP2000_PCI_CMDSTAT IXP2000_PCI_CREG(0x04) +#define IXP2000_PCI_CSR_BAR IXP2000_PCI_CREG(0x10) +#define IXP2000_PCI_SRAM_BAR IXP2000_PCI_CREG(0x14) +#define IXP2000_PCI_SDRAM_BAR IXP2000_PCI_CREG(0x18) + +/* + * PCI CSRs + */ +#define IXP2000_PCI_CSR(reg) (volatile unsigned long*)(PCI_CSR_VIRT_BASE | reg) + +/* + * PCI outbound interrupts + */ +#define IXP2000_PCI_OUT_INT_STATUS IXP2000_PCI_CSR(0x30) +#define IXP2000_PCI_OUT_INT_MASK IXP2000_PCI_CSR(0x34) +/* + * PCI communications + */ +#define IXP2000_PCI_MAILBOX0 IXP2000_PCI_CSR(0x50) +#define IXP2000_PCI_MAILBOX1 IXP2000_PCI_CSR(0x54) +#define IXP2000_PCI_MAILBOX2 IXP2000_PCI_CSR(0x58) +#define IXP2000_PCI_MAILBOX3 IXP2000_PCI_CSR(0x5C) +#define IXP2000_XSCALE_DOORBELL IXP2000_PCI_CSR(0x60) +#define IXP2000_XSCALE_DOORBELL_SETUP IXP2000_PCI_CSR(0x64) +#define IXP2000_PCI_DOORBELL IXP2000_PCI_CSR(0x70) +#define IXP2000_PCI_DOORBELL_SETUP IXP2000_PCI_CSR(0x74) + +/* + * DMA engines + */ +#define IXP2000_PCI_CH1_BYTE_CNT IXP2000_PCI_CSR(0x80) +#define IXP2000_PCI_CH1_ADDR IXP2000_PCI_CSR(0x84) +#define IXP2000_PCI_CH1_DRAM_ADDR IXP2000_PCI_CSR(0x88) +#define IXP2000_PCI_CH1_DESC_PTR IXP2000_PCI_CSR(0x8C) +#define IXP2000_PCI_CH1_CNTRL IXP2000_PCI_CSR(0x90) +#define IXP2000_PCI_CH1_ME_PARAM IXP2000_PCI_CSR(0x94) +#define IXP2000_PCI_CH2_BYTE_CNT IXP2000_PCI_CSR(0xA0) +#define IXP2000_PCI_CH2_ADDR IXP2000_PCI_CSR(0xA4) +#define IXP2000_PCI_CH2_DRAM_ADDR IXP2000_PCI_CSR(0xA8) +#define IXP2000_PCI_CH2_DESC_PTR IXP2000_PCI_CSR(0xAC) +#define IXP2000_PCI_CH2_CNTRL IXP2000_PCI_CSR(0xB0) +#define IXP2000_PCI_CH2_ME_PARAM IXP2000_PCI_CSR(0xB4) +#define IXP2000_PCI_CH3_BYTE_CNT IXP2000_PCI_CSR(0xC0) +#define IXP2000_PCI_CH3_ADDR IXP2000_PCI_CSR(0xC4) +#define IXP2000_PCI_CH3_DRAM_ADDR IXP2000_PCI_CSR(0xC8) +#define IXP2000_PCI_CH3_DESC_PTR IXP2000_PCI_CSR(0xCC) +#define IXP2000_PCI_CH3_CNTRL IXP2000_PCI_CSR(0xD0) +#define IXP2000_PCI_CH3_ME_PARAM IXP2000_PCI_CSR(0xD4) +#define IXP2000_DMA_INF_MODE IXP2000_PCI_CSR(0xE0) +/* + * Size masks for BARs + */ +#define IXP2000_PCI_SRAM_BASE_ADDR_MASK IXP2000_PCI_CSR(0xFC) +#define IXP2000_PCI_DRAM_BASE_ADDR_MASK IXP2000_PCI_CSR(0x100) +/* + * Control and uEngine related + */ +#define IXP2000_PCI_CONTROL IXP2000_PCI_CSR(0x13C) +#define IXP2000_PCI_ADDR_EXT IXP2000_PCI_CSR(0x140) +#define IXP2000_PCI_ME_PUSH_STATUS IXP2000_PCI_CSR(0x148) +#define IXP2000_PCI_ME_PUSH_EN IXP2000_PCI_CSR(0x14C) +#define IXP2000_PCI_ERR_STATUS IXP2000_PCI_CSR(0x150) +#define IXP2000_PCI_ERR_ENABLE IXP2000_PCI_CSR(0x154) +/* + * Inbound PCI interrupt control + */ +#define IXP2000_PCI_XSCALE_INT_STATUS IXP2000_PCI_CSR(0x158) +#define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C) + +#define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */ +#define IXP2000_PCICNTL_PCF (1<<28) /* PCI Centrolfunction bit */ +#define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */ + +/* These are from the IRQ register in the PCI ISR register */ +#define PCI_CONTROL_BE_DEO (1 << 22) /* Big Endian Data Enable Out */ +#define PCI_CONTROL_BE_DEI (1 << 21) /* Big Endian Data Enable In */ +#define PCI_CONTROL_BE_BEO (1 << 20) /* Big Endian Byte Enable Out */ +#define PCI_CONTROL_BE_BEI (1 << 19) /* Big Endian Byte Enable In */ +#define PCI_CONTROL_PNR (1 << 17) /* PCI Not Reset bit of SA_CONTROL */ + + +#define IXP2000_PCI_RST_REL (1 << 2) +#define CFG_RST_DIR (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF) +#define CFG_PCI_BOOT_HOST (1 << 2) +#define CFG_BOOT_PROM (1 << 1) + + +/* + * SlowPort CSRs + * + * The slowport is used to access things like flash, SONET framer control + * ports, slave microprocessors, CPLDs, and others of chip memory mapped + * peripherals. + */ +#define SLOWPORT_CSR(reg) (volatile unsigned long*)(SLOWPORT_CSR_VIRT_BASE | reg) + +#define IXP2000_SLOWPORT_CCR SLOWPORT_CSR(0x00) +#define IXP2000_SLOWPORT_WTC1 SLOWPORT_CSR(0x04) +#define IXP2000_SLOWPORT_WTC2 SLOWPORT_CSR(0x08) +#define IXP2000_SLOWPORT_RTC1 SLOWPORT_CSR(0x0c) +#define IXP2000_SLOWPORT_RTC2 SLOWPORT_CSR(0x10) +#define IXP2000_SLOWPORT_FSR SLOWPORT_CSR(0x14) +#define IXP2000_SLOWPORT_PCR SLOWPORT_CSR(0x18) +#define IXP2000_SLOWPORT_ADC SLOWPORT_CSR(0x1C) +#define IXP2000_SLOWPORT_FAC SLOWPORT_CSR(0x20) +#define IXP2000_SLOWPORT_FRM SLOWPORT_CSR(0x24) +#define IXP2000_SLOWPORT_FIN SLOWPORT_CSR(0x28) + +/* + * CCR values. + * The CCR configures the clock division for the slowport interface. + */ +#define SLOWPORT_CCR_DIV_1 0x00 +#define SLOWPORT_CCR_DIV_2 0x01 +#define SLOWPORT_CCR_DIV_4 0x02 +#define SLOWPORT_CCR_DIV_6 0x03 +#define SLOWPORT_CCR_DIV_8 0x04 +#define SLOWPORT_CCR_DIV_10 0x05 +#define SLOWPORT_CCR_DIV_12 0x06 +#define SLOWPORT_CCR_DIV_14 0x07 +#define SLOWPORT_CCR_DIV_16 0x08 +#define SLOWPORT_CCR_DIV_18 0x09 +#define SLOWPORT_CCR_DIV_20 0x0a +#define SLOWPORT_CCR_DIV_22 0x0b +#define SLOWPORT_CCR_DIV_24 0x0c +#define SLOWPORT_CCR_DIV_26 0x0d +#define SLOWPORT_CCR_DIV_28 0x0e +#define SLOWPORT_CCR_DIV_30 0x0f + +/* + * PCR values. PCR configure the mode of the interfac3 + */ +#define SLOWPORT_MODE_FLASH 0x00 +#define SLOWPORT_MODE_LUCENT 0x01 +#define SLOWPORT_MODE_PMC_SIERRA 0x02 +#define SLOWPORT_MODE_INTEL_UP 0x03 +#define SLOWPORT_MODE_MOTOROLA_UP 0x04 + +/* + * ADC values. Defines data and address bus widths + */ +#define SLOWPORT_ADDR_WIDTH_8 0x0000 +#define SLOWPORT_ADDR_WIDTH_16 0x0001 +#define SLOWPORT_ADDR_WIDTH_24 0x0002 +#define SLOWPORT_ADDR_WIDTH_32 0x0003 +#define SLOWPORT_DATA_WIDTH_8 0x0000 +#define SLOWPORT_DATA_WIDTH_16 0x0100 +#define SLOWPORT_DATA_WIDTH_24 0x0200 +#define SLOWPORT_DATA_WIDTH_32 0x0300 + +/* + * Masks and shifts for various fields in the WTC and RTC registers + */ +#define SLOWPORT_WRTC_MASK_HD 0x0003 +#define SLOWPORT_WRTC_MASK_SU 0x003c +#define SLOWPORT_WRTC_MASK_PW 0x03c0 + +#define SLOWPORT_WRTC_SHIFT_HD 0x00 +#define SLOWPORT_WRTC_SHIFT_SU 0x02 +#define SLOWPORT_WRTC_SHFIT_PW 0x06 + + +/* + * Boards may multiplex different devices on the 2nd channel of + * the slowport interface that each need different configuration + * settings. For example, the IXDP2400 uses channel 2 on the interface + * to access the CPLD, the switch fabric card, and te media card. Each + * one needs a different mode so drivers must save/restore the mode + * before and after each operation. + * + * acquire_slowport(&your_config); + * ... + * do slowport operations + * ... + * release_slowport(); + * + * Note that while you have the slowport, you are holding a spinlock, + * so do not do anything you would not normally do if you had explicitly + * acquired any lock. + * + * The configuration only affects device 2 on the slowport, so the + * MTD map driver does not acquire/release the slowport. + */ +#ifndef __ASSEMBLY__ +struct slowport_cfg { + unsigned long CCR; /* Clock divide */ + unsigned long WTC; /* Write Timing Control */ + unsigned long RTC; /* Read Timing Control */ + unsigned long PCR; /* Protocol Control Register */ + unsigned long ADC; /* Address/Data Width Control */ +}; + +void acquire_slowport(struct slowport_cfg *); +void release_slowport(void); +#endif + +/* + * GPIO registers & GPIO interface + */ +#define IXP2000_GPIO_REG(x) ((volatile unsigned long*)(GPIO_VIRT_BASE+(x))) +#define IXP2000_GPIO_PLR IXP2000_GPIO_REG(0x00) +#define IXP2000_GPIO_PDPR IXP2000_GPIO_REG(0x04) +#define IXP2000_GPIO_PDSR IXP2000_GPIO_REG(0x08) +#define IXP2000_GPIO_PDCR IXP2000_GPIO_REG(0x0c) +#define IXP2000_GPIO_POPR IXP2000_GPIO_REG(0x10) +#define IXP2000_GPIO_POSR IXP2000_GPIO_REG(0x14) +#define IXP2000_GPIO_POCR IXP2000_GPIO_REG(0x18) +#define IXP2000_GPIO_REDR IXP2000_GPIO_REG(0x1c) +#define IXP2000_GPIO_FEDR IXP2000_GPIO_REG(0x20) +#define IXP2000_GPIO_EDSR IXP2000_GPIO_REG(0x24) +#define IXP2000_GPIO_LSHR IXP2000_GPIO_REG(0x28) +#define IXP2000_GPIO_LSLR IXP2000_GPIO_REG(0x2c) +#define IXP2000_GPIO_LDSR IXP2000_GPIO_REG(0x30) +#define IXP2000_GPIO_INER IXP2000_GPIO_REG(0x34) +#define IXP2000_GPIO_INSR IXP2000_GPIO_REG(0x38) +#define IXP2000_GPIO_INCR IXP2000_GPIO_REG(0x3c) +#define IXP2000_GPIO_INST IXP2000_GPIO_REG(0x40) + +/* + * PMU (performance monitoring) + */ +#define IXP2000_PMU_REG(x) ((volatile unsigned long*)(PMU_VIRT_BASE+(x))) +#define IXP2000_PMU_CHAPCMD0 IXP2000_PMU_REG(0x000) +#define IXP2000_PMU_CHAPEVN0 IXP2000_PMU_REG(0x004) +#define IXP2000_PMU_CHAPSTAT0 IXP2000_PMU_REG(0x008) +#define IXP2000_PMU_CHAPDATA0 IXP2000_PMU_REG(0x00c) +#define IXP2000_PMU_CHAPCMD1 IXP2000_PMU_REG(0x010) +#define IXP2000_PMU_CHAPEVN1 IXP2000_PMU_REG(0x014) +#define IXP2000_PMU_CHAPSTAT1 IXP2000_PMU_REG(0x018) +#define IXP2000_PMU_CHAPDATA1 IXP2000_PMU_REG(0x01c) +#define IXP2000_PMU_CHAPCMD2 IXP2000_PMU_REG(0x020) +#define IXP2000_PMU_CHAPEVN2 IXP2000_PMU_REG(0x024) +#define IXP2000_PMU_CHAPSTAT2 IXP2000_PMU_REG(0x028) +#define IXP2000_PMU_CHAPCMD3 IXP2000_PMU_REG(0x030) +#define IXP2000_PMU_CHAPEVN3 IXP2000_PMU_REG(0x034) +#define IXP2000_PMU_CHAPSTAT3 IXP2000_PMU_REG(0x038) +#define IXP2000_PMU_CHAPCMD4 IXP2000_PMU_REG(0x040) +#define IXP2000_PMU_CHAPEVN4 IXP2000_PMU_REG(0x044) +#define IXP2000_PMU_CHAPSTAT4 IXP2000_PMU_REG(0x048) +#define IXP2000_PMU_CHAPCMD5 IXP2000_PMU_REG(0x050) +#define IXP2000_PMU_CHAPEVN5 IXP2000_PMU_REG(0x054) +#define IXP2000_PMU_CHAPSTAT5 IXP2000_PMU_REG(0x058) +#define IXP2000_PMU_PMUINTEN IXP2000_PMU_REG(0xc00) +#define IXP2000_PMU_PMUINTMSK IXP2000_PMU_REG(0xd00) +#define IXP2000_PMU_PMUINTSTAT IXP2000_PMU_REG(0xe00) +#define IXP2000_PMU_PMUCFG IXP2000_PMU_REG(0xf00) + +/* PMU CHAP Event bits */ +#define PMU_CHAPEVN_DDBS(x) ((x) << 16) /* Dec Design BlockSel */ +#define PMU_CHAPEVN_DDBS_PMU (PMU_CHAPEVN_DDBS(1)) /* Design Block PMU */ +#define PMU_CHAPEVN_DEC0_MUX(x) ((x) << 23) /* Dec0 Mux Select */ +#define PMU_CHAPEVN_DEC0_MUX_NULL (PMU_CHAPEVN_DEC0_MUX(7)) /* Dec every cycle */ + +/* PMU CHAP Command bits */ +#define PMU_CHAPCMD_ACTIVATE (1 << 0) +#define PMU_CHAPCMD_OP(x) ((x) << 16) +#define PMU_CHAPCMD_STOP (PMU_CHAPCMD_OP(0)) +#define PMU_CHAPCMD_START (PMU_CHAPCMD_OP(1)) +#define PMU_CHAPCMD_SAMPLE (PMU_CHAPCMD_OP(2)) +#define PMU_CHAPCMD_RESET (PMU_CHAPCMD_OP(4)) +#define PMU_CHAPCMD_RESTART (PMU_CHAPCMD_OP(5)) +#define PMU_CHAPCMD_SAMPLERESTART (PMU_CHAPCMD_OP(6)) +#define PMU_CHAPCMD_PRELOAD (PMU_CHAPCMD_OP(15)) +#define PMU_CHAPCMD_SAC (1 << 20) +#define PMU_CHAPCMD_CC(x) ((x) << 21) /* condition codes */ +#define PMU_CHAPCMD_FALSE (PMU_CHAPCMD_CC(0)) +#define PMU_CHAPCMD_GT (PMU_CHAPCMD_CC(1)) +#define PMU_CHAPCMD_EQ (PMU_CHAPCMD_CC(2)) +#define PMU_CHAPCMD_GTE (PMU_CHAPCMD_CC(3)) +#define PMU_CHAPCMD_LT (PMU_CHAPCMD_CC(4)) +#define PMU_CHAPCMD_NE (PMU_CHAPCMD_CC(5)) +#define PMU_CHAPCMD_LTE (PMU_CHAPCMD_CC(6)) +#define PMU_CHAPCMD_TRUE (PMU_CHAPCMD_CC(7)) +#define PMU_CHAPCMD_THIE (1 << 24) /* Threshold */ +#define PMU_CHAPCMD_CTIE (1 << 25) /* Cmd trigger */ +#define PMU_CHAPCMD_OUIE (1 << 26) /* Over/underflow */ + +/* PMU CFG */ +#define PMU_PMUCFG_AUTOCFG (1 << 18) /* Reinit(?) the PMU */ +/* PMU INTSTAT */ +#define PMU_PMUINTSTAT_TCD (1 << 31) /* Init complete */ + +/* + * "Global" registers...whatever that's supposed to mean. + */ +#define GLOBAL_REG_BASE (GLOBAL_REG_VIRT_BASE + 0x0a00) +#define GLOBAL_REG(reg) (volatile unsigned long*)(GLOBAL_REG_BASE | reg) +#define IXP2000_RESET0 GLOBAL_REG(0x0c) +#define IXP2000_RESET1 GLOBAL_REG(0x10) +#define IXP2000_CCR GLOBAL_REG(0x14) +#define IXP2000_STRAP_OPTIONS GLOBAL_REG(0x18) + +#define IXP2400_CPU_ID 0x69054190 +#define IXP2400_CPU_MASK 0xfffffff0 + +#define IXP2800_CPU_ID 0x690541a0 +#define IXP2800_CPU_MASK 0xfffffff0 + +#define RSTALL (1 << 16) + +#ifndef __ASSEMBLY__ +static inline unsigned int npu_has_flash(void) +{ + return ((*IXP2000_STRAP_OPTIONS) & (CFG_BOOT_PROM)); +} + +static inline unsigned int npu_is_pcimaster(void) +{ + return ((*IXP2000_STRAP_OPTIONS) & (CFG_PCI_BOOT_HOST)); +} + +static inline unsigned int npu_is_master(void) +{ + return ((npu_has_flash()) && (npu_is_pcimaster()) ); +} + +/* + * IXP2400 A0/A1 and all IXP2800 have broken slowport + */ +static inline unsigned npu_has_broken_slowport(void) +{ + extern unsigned int processor_id; + + return (((processor_id & IXP2800_CPU_MASK) == IXP2800_CPU_ID) || + (((processor_id & IXP2400_CPU_MASK) == IXP2400_CPU_ID) + && !(processor_id & 0xf))); +} + + +#endif + +#endif /* _IXP2000_H_ */ diff -Nru a/include/asm-arm/arch-ixp2000/leds.h b/include/asm-arm/arch-ixp2000/leds.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/leds.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,77 @@ +/* + * inclue/asm-arm/arch-ixp2000/leds.h + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 _LEDS_H_ +#define _LEDS_H_ +// encodings for the 4 char alphanum display +#define DISPLAY_NULL 0x20 +#define DISPLAY_0 0x30 +#define DISPLAY_1 0x31 +#define DISPLAY_2 0x32 +#define DISPLAY_3 0x33 +#define DISPLAY_4 0x34 +#define DISPLAY_5 0x35 +#define DISPLAY_6 0x36 +#define YISPLAY_7 0x37 +#define DISPLAY_8 0x38 +#define DISPLAY_9 0x39 +#define DISPLAY_A 0x41 +#define DISPLAY_B 0x42 +#define DISPLAY_C 0x43 +#define DISPLAY_D 0x44 +#define DISPLAY_E 0x45 +#define DISPLAY_F 0x46 +#define DISPLAY_G 0x47 +#define DISPLAY_H 0x48 +#define DISPLAY_I 0x49 +#define DISPLAY_J 0x4A +#define DISPLAY_K 0x4B +#define DISPLAY_L 0x4C +#define DISPLAY_M 0x4D +#define DISPLAY_N 0x4E +#define DISPLAY_O 0x4F +#define DISPLAY_P 0x50 +#define DISPLAY_Q 0x51 +#define DISPLAY_R 0x52 +#define DISPLAY_S 0x53 +#define DISPLAY_T 0x54 +#define DISPLAY_U 0x55 +#define DISPLAY_V 0x56 +#define DISPLAY_W 0x57 +#define DISPLAY_X 0x58 +#define DISPLAY_Y 0x59 +#define DISPLAY_Z 0x5A + +#define LEDDATA0 (VIRT_CPLD_CSR + 0x04) +#define LEDDATA1 (VIRT_CPLD_CSR + 0x05) +#define LEDDATA2 (VIRT_CPLD_CSR + 0x06) +#define LEDDATA3 (VIRT_CPLD_CSR + 0x07) + + +/* Set the a char to LED */ +#ifdef __ARMEB__ +#define SETLED3(p) { *(volatile unsigned char *)LEDDATA3=p; }; +#define SETLED2(p) { *(volatile unsigned char *)LEDDATA2=p; }; +#define SETLED1(p) { *(volatile unsigned char *)LEDDATA1=p; }; +#define SETLED0(p) { *(volatile unsigned char *)LEDDATA0=p; }; +#else +#define SETLED0(p) { *(volatile unsigned char *)LEDDATA3=p; }; +#define SETLED1(p) { *(volatile unsigned char *)LEDDATA2=p; }; +#define SETLED2(p) { *(volatile unsigned char *)LEDDATA1=p; }; +#define SETLED3(p) { *(volatile unsigned char *)LEDDATA0=p; }; +#endif + +#define DISPLAY_LEDS(a,b,c,d) {SETLED0(a);SETLED1(b);SETLED2(c);SETLED3(d); } + + +#endif diff -Nru a/include/asm-arm/arch-ixp2000/memory.h b/include/asm-arm/arch-ixp2000/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/memory.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,66 @@ +/* + * linux/include/asm-arm/arch-ixdp2400/memory.h + * + * Copyright (c) 2002 Intel Corp. + * + * 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 __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#include + +/* + * Task size: 1GB + */ +#define TASK_SIZE ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +#define PAGE_OFFSET ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0x1c000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro + + +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ + +// #define __virt_to_bus__is_a_macro +//#define __virt_to_bus(v) + +static inline unsigned int __virt_to_bus(unsigned v) +{ + return ((__virt_to_phys(v) - 0x0) + (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)); +} + +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(b) \ + __phys_to_virt((((b - (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)) + 0x0))) + +#endif diff -Nru a/include/asm-arm/arch-ixp2000/param.h b/include/asm-arm/arch-ixp2000/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/param.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-ixdp2400/param.h + */ diff -Nru a/include/asm-arm/arch-ixp2000/pci-bridge.h b/include/asm-arm/arch-ixp2000/pci-bridge.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/pci-bridge.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * include/asm-arm/arch-ixdp2400/pci-bridge.h + * + * Generic PCI hose support for Xscale/ARM. To eventually be + * moved to a more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 __KERNEL__ +#ifndef _ASM_PCI_BRIDGE_H +#define _ASM_PCI_BRIDGE_H + +struct device_node; +struct pci_controller; + +/* Get the PCI host controller for a bus */ +extern struct pci_controller* pci_bus_to_hose(int bus); + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct resource io_space; + struct resource mem_space; +}; + +/* These are used for config access before all the PCI probing + has been done. */ +int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 *val); +int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 *val); +int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 *val); +int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 val); +int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val); +int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val); +#endif +#endif /* __KERNEL__ */ diff -Nru a/include/asm-arm/arch-ixp2000/pci.h b/include/asm-arm/arch-ixp2000/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/pci.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,37 @@ +/* + * include/asm-arm/arch-ixdp2400/pci.h + * + * Generic PCI support for Xscale/ARM. To eventually be moved to a + * more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ASM_ARCH_PCI_H +#define _ASM_ARCH_PCI_H + +extern struct pci_controller* pcibios_alloc_controller(void); +extern void pcibios_allocate_resources(void); +extern void pci_exclude_device(unsigned char, unsigned char); +extern struct pci_dev * fake_pci_dev(struct pci_controller *, int, int); +extern u8 common_swizzle(struct pci_dev *, u8 *); + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. + */ +#define PCI_IRQ_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ + _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ + _ctl_; }) + + +#endif /* _ASM_ARCH_PCI_H */ diff -Nru a/include/asm-arm/arch-ixp2000/pci_auto.h b/include/asm-arm/arch-ixp2000/pci_auto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/pci_auto.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-iop310/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ARM_MACH_XSCALE_PCI_AUTO_H +#define _ARM_MACH_XSCALE_PCI_AUTO_H + +#include "pci-bridge.h" + +extern int pciauto_bus_scan(struct pci_controller *, int); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* _ARM_MACH_XSCALE_PCI_AUTO_H */ diff -Nru a/include/asm-arm/arch-ixp2000/serial.h b/include/asm-arm/arch-ixp2000/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/serial.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,32 @@ +/* + * include/asm-arm/arch-ixp2000/serial.h + * + * Serial port defn for ixp2000 based systems + * + * Author: Deepak Saxena + * + * Copyright (c) 2002 MontaVista Software, Inc. + */ + + +#define BASE_BAUD 50000000 / 16 // IS THIS ALWAYS TRUE? + +#define STD_COM_FLAGS (ASYNC_SKIP_TEST) + +#define RS_TABLE_SIZE 1 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + type: PORT_XSCALE, \ + xmit_fifo_size: 16, \ + baud_base: BASE_BAUD, \ + irq: IRQ_IXP2000_UART, \ + flags: STD_COM_FLAGS, \ + iomem_base: IXP2000_UART_BASE+3,\ + io_type: SERIAL_IO_MEM, \ + iomem_reg_shift: 2 \ + } + +#define EXTRA_SERIAL_PORT_DEFNS + + diff -Nru a/include/asm-arm/arch-ixp2000/serial_reg.h b/include/asm-arm/arch-ixp2000/serial_reg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/serial_reg.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,95 @@ +/* + * include/asm-arm/arch-ixp2000/serial_reg.h + * + * Author: Naeem M Afzal + * + * Copyright (c) 2002 Intel Corp. + * + * 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 _ARCH_SERIAL_H_ +#define _ARCH_SERIAL_H_ + +#define IXP2000_CSR(x) (volatile unsinged long *)(IXP2000_UART_BASE + (x)) +#define CSR_UARTCR IXP2000_CSR(0x0c) +#define CSR_UARTSR IXP2000_CSR(0x14) +#define CSR_UARTDR IXP2000_CSR(0x00) +#define CSR_UARTIER IXP2000_CSR(0x04) +#define CSR_UARTIIR IXP2000_CSR(0x04) +#define CSR_UARTFCR IXP2000_CSR(0x08) + +#define UART_CR CSR_UARTCR +#define UART_SR CSR_UARTSR +#define UART_DR CSR_UARTDR +#define UART_IER CSR_UARTIER +#define UART_IIR CSR_UARTIIR +#define UART_FCR CSR_UARTFCR + +#define UTDR 0x00 /* DLAB = 0 */ +#define UTDLL 0x00 /* DLAB = 1 */ +#define UTIER 0x04 /* DLAB = 0 */ +#define UTDLM 0x04 /* DLAB = 1 */ +#define UTFCR 0x08 +#define UTIIR 0x08 +#define UTCR 0x0c +#define UTSR 0x14 + +#define UART_RX UTDR /* Receive port, read only */ +#define UART_TX UTDR /* transmit port, write only */ + +/* bit definition on IER */ +#define UTCR_XIE (1 << 1) /* Xmit interrupt enable */ +#define UTCR_TIE UTCR_XIE /* Xmit interrupt enable */ +#define UTCR_RIE (1 << 0) /* Rcv interrupt enable */ +#define UTCR_RLSE (1 << 2) /* Rcv line status interrupt enable */ +#define UTCR_RTOIE (1 << 4) /* Rcv timeout status interrupt enable */ +#define UTCR_EN (1 << 6) /* Enable uart */ + +/* dont need these below */ +#define UTCR_9600_BAUD (0x17 << 16) +#define UTCR_19200_BAUD (0xB << 16) +#define UTCR_38400_BAUD (0x5 << 16) +#define UTCR_57600_BAUD (0x3 << 16) +#define UTCR_115200_BAUD (0x1 << 16) + +/* LCR def */ +#define UTCR_PARENB (1 << 3) /* Parity Enable */ +#define UTCR_EVNEN_PARITY (1 << 4) /* Even parity */ + +#define UTCR_8_BIT (0x3 << 0) /* 8 bit */ +#define UTCR_7_BIT (0x2 << 0) /* 7 bit */ +#define UTCR_6_BIT (0x1 << 0) /* 6 bit */ +#define UTCR_5_BIT (0x0 << 0) /* 5 bit */ + +#define UTCR_1_STOP_BIT (0 << 2) /* 1 stop bit */ +#define UTCR_2_STOP_BIT (1 << 2) /* 2 stop bits */ +#define UTCR_BRK (1<<6) +#define UTCR_DLAB (1<<7) + + +#define UTCR_DSS_MASK (0x3 << 0) /* data size mask */ +#define UTCR_SBS_MASK (0x1 << 2) /* stop bit select mask */ + +#define UTCR_INT_CLEAR (1 << 2) /* UART_INT_MASK */ + +/* LSR */ +#define UTSR_RPE (1<<2) /* Parity error */ +#define UTSR_RFE (1<<3) /* Framing error */ +#define UTSR_ROR (1<<1) /* receiver overrun */ +#define UTSR_RXR (1<<0) /* receiver not empty */ +#define UTSR_TXR (1<<5) /* Transmit Fifo not full */ +#define UTSR_TXE (1<<6) /* xmit fifo empty */ +#define UTSR_RXF (0<<0) /* receive fifo full */ +#define UTSR_TXF (0<<5) /* xmit fifo full */ + +#define UART_LCR_DLAB (1<<7) /* DLAB bit */ +#define UART_FCR_ENABLE_FIFO (1<<0) /* FIFOs enable */ +#define UART_FCR_RESET (3<<1) /* RSET FIFOs */ +#define UART_FCR_TRIGGER_8 (1<<7) /* 6:7=01 trigger on 8bits*/ + +#endif /* _ARCH_SERIAL_H */ + diff -Nru a/include/asm-arm/arch-ixp2000/slave.h b/include/asm-arm/arch-ixp2000/slave.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/slave.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,152 @@ +/* + * inclue/asm-arm/arch-ixp2000/slave.h + * + * Register and other defines for IXMB2400 for slave NPU board + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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 _SLAVE_H +#define _SLAVE_H + +#define MISC_CONTROL_OFF 0x04 +#define IXP_RESET0_OFF 0x0C +#define CCR_OFF 0x14 +#define STRAP_OPTIONS_OFF 0x18 + +/* slave's csr as seen from master PCI*/ +#define GLOBAL_CONTROL_BASE_FRM_PCI 0x4A00 +#define IXP_RESET0_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + IXP_RESET0_OFF) +#define CCR_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + CCR_OFF) +#define STRAP_OPTIONS_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + STRAP_OPTIONS_OFF) +#define MISC_CONTROL_FRM_PCI (GLOBAL_CONTROL_BASE_FRM_PCI + MISC_CONTROL_OFF) + +#define SLOW_PORT_CSR_BASE_FRM_PCI 0x80000 +#define SCRATCH_BASE_FRM_PCI 0xF0000 + +#define DDR_RX_DLL_VAL 0x11 +#define DDR_RX_DESKEW_VAL 0x11 +#define DDR_RDDLYSEL_RECEN_VAL 0x11 + +#define SRAM_CH1_BASE_FRM_PCI 0xF9800 +#define SRAM_CH0_BASE_FRM_PCI 0xF9C00 +#define SRAM_CH_BASE_FRM_PCI 0xF9000 + +#define DU_CONTROL_OFF 0x0 +#define DU_ECC_TEST_OFF 0x18 +#define DU_INIT_OFF 0x20 +#define DU_CONTROL2_OFF 0x28 +#define DDR_RCOMP_IO_CONFIG_OFF 0x3c0 +#define DDR_RDDLYSEL_RECEN_OFF 0x3c8 +#define DDR_RX_DLL_OFF 0x650 +#define DDR_RX_DESKEW_OFF 0x688 + +#define CR0_FRCSMRCOMP_OFF 0x100 +#define CR0_DSTRENGTHSEL_OFF 0x130 +#define CR0_DDQRCOMP_OFF 0x148 +#define CR0_DCTLRCOMP_OFF 0x190 +#define CR0_DRCVRCOMP_OFF 0x1D8 +#define CR0_DCKERCOMP_OFF 0x228 +#define CR0_DCSRCOMP_OFF 0x2B0 +#define CR0_DCKRCOMP_OFF 0x338 +#define CR0_DX8X16CKECSCKSEL_OFF 0x220 +#define CR0_RCOMPPRD_OFF 0x108 +#define CR0_DIGFIL_OFF 0x118 + +#define CR0_SLEWPROGRAMMED_OFF 0x128 +#define CR0_OVRRIDEH_OFF 0x138 +#define CR0_OVRRIDEV_OFF 0x140 +#define CR0_JT_CONFIG_OFF 0x3C0 + +#define CR0_FRCSMRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_FRCSMRCOMP_OFF) +#define CR0_DSTRENGTHSEL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DSTRENGTHSEL_OFF) +#define CR0_DDQRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DDQRCOMP_OFF) +#define CR0_DCTLRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCTLRCOMP_OFF) +#define CR0_DRCVRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DRCVRCOMP_OFF) +#define CR0_DCKERCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCKERCOMP_OFF) +#define CR0_DCSRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCSRCOMP_OFF) +#define CR0_DCKRCOMP_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DCKRCOMP_OFF) +#define CR0_DX8X16CKECSCKSEL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DX8X16CKECSCKSEL_OFF) +#define CR0_RCOMPPRD_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_RCOMPPRD_OFF) +#define CR0_DIGFIL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_DIGFIL_OFF) + +#define CR0_SLEWPROGRAMMED_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_SLEWPROGRAMMED_OFF) +#define CR0_OVRRIDEH_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_OVRRIDEH_OFF) +#define CR0_OVRRIDEV_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_OVRRIDEV_OFF) +#define CR0_JT_CONFIG_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + CR0_JT_CONFIG_OFF) + +#define DRAM_CH0_BASE_FRM_PCI 0xFD800 + +#define DU_CONTROL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_CONTROL_OFF) +#define DU_ECC_TEST_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_ECC_TEST_OFF) +#define DU_INIT_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_INIT_OFF) +#define DU_CONTROL2_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DU_CONTROL2_OFF) +#define DDR_RCOMP_IO_CONFIG_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RCOMP_IO_CONFIG_OFF) +#define DDR_RDDLYSEL_RECEN_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RDDLYSEL_RECEN_OFF) +#define DDR_RX_DLL_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RX_DLL_OFF) +#define DDR_RX_DESKEW_FRM_PCI (DRAM_CH0_BASE_FRM_PCI + DDR_RX_DESKEW_OFF) + +#define PCI_OUT_INT_MASK_OFF 0x34 +#define MAILBOX_1_OFF 0x54 +#define PCI_CONTROL_OFF 0x13C +#define PCI_ADDR_EXT_OFF 0x140 +#define XSCALE_INT_STATUS_OFF 0x158 +#define XSCALE_INT_ENABLE_OFF 0x15C + +#define PCI_CSR_BASE_FRM_PCI 0xFE000 + +#define PCI_OUT_INT_MASK_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_OUT_INT_MASK_OFF) +#define PCI_CONTROL_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_CONTROL_OFF) +#define PCI_ADDR_EXT_FRM_PCI (PCI_CSR_BASE_FRM_PCI + PCI_ADDR_EXT_OFF) + +#define SLAVE_PCI_CMD_STAT_VAL (PCI_COMMAND_INVALIDATE \ + | PCI_COMMAND_MEMORY \ + | PCI_COMMAND_IO) + +#define CFG_PCI_BOOT_HOST (1 << 2) +#define PCI_OUT_INT_MASK_VAL (1<<1) +#define XSCALE_RESET_BIT 0x00000001 + +#define FLASH_WRITE_ENABLE (1 << 9) +#define FLASH_ALIAS_DISABLE (1 << 8) + +#define IXP_TYPE_2400 0 +#define IXP_TYPE_2800 1 + +#define IXP_IOC_QUERY_INFO 0x1 +#define IXP_IOC_RELEASE_RST 0x2 + +#define IXP_FLAG_ROM_BOOT (1<<0x0) +#define IXP_FLAG_PCI_HOST (1<<0x1) +#define IXP_FLAG_PCI_ARB (1<<0x2) +#define IXP_FLAG_NPU_UP (1<<0x3) /* Slave NPU is running after reset */ +#define IXP_FLAG_NO_FLASH (1<<0x4) /* Slave NPU does not have flash*/ + + +struct ixp_info { + char name[32]; + unsigned short ixp_type; + unsigned short ixp_rev; + + unsigned long sdram_size; + unsigned long sram_size; + + unsigned long flags; + + unsigned long csr_bar; + unsigned long sram_bar; + unsigned long sdram_bar; + + unsigned long csr_ioaddr; + unsigned long sram_ioaddr; + unsigned long sdram_ioaddr; + struct ixp_info *next; +}; + +#endif diff -Nru a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/system.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/arch-ixp2400/system.h + * + * Copyright (C) 2002 Intel Corp. + * + * 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. + */ + +static inline void arch_idle(void) +{ +#if 0 + while (!current->need_resched && !hlt_counter) { + cpu_do_idle(IDLE_CLOCK_SLOW); + cpu_do_idle(IDLE_WAIT_FAST); + cpu_do_idle(IDLE_CLOCK_FAST); + } +#endif +} + + +static inline void arch_reset(char mode) +{ + cli(); + /* Use on-chip reset capability */ + if (*IXP2000_STRAP_OPTIONS & CFG_PCI_BOOT_HOST) { + *(IXP2000_RESET0) |= (RSTALL); + udelay(1000); + } +} diff -Nru a/include/asm-arm/arch-ixp2000/time.h b/include/asm-arm/arch-ixp2000/time.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/time.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3 @@ +/* + * Place keeper so arch/arm/kernel/time.c builds + */ diff -Nru a/include/asm-arm/arch-ixp2000/timex.h b/include/asm-arm/arch-ixp2000/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/timex.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-ix2000/timex.h + * + * IXP2000 architecture timex specifications + */ + + +/* + * This is somewhat bogus, but we need something to make + * happy. Each board can have a different timer tick rate, so we + * determine the _real_ latch at run time. + */ +#define CLOCK_TICK_RATE (50000000) /* 50MHz APB clock - OK for most */ diff -Nru a/include/asm-arm/arch-ixp2000/uncompress.h b/include/asm-arm/arch-ixp2000/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/uncompress.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * linux/include/asm-arm/arch-ixp2000/uncompress.h + * Author: Naeem Afzal + * + * 3/27/03: Jeff Daly + * Modified to support multiple machine types + * + * Copyright 2002 Intel Corp. + * + * 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. + * + */ + +/* At this point, the MMU is not on, so use physical addresses */ + + +#define UART_BASE 0xc0030000 + +#ifdef __ARMEB__ +#define PHYS(x) ((volatile unsigned char *)(UART_BASE + x + 3)) +#else +#define PHYS(x) ((volatile unsigned char *)(UART_BASE + x)) +#endif + +#define UARTDR PHYS(0x00) /* Transmit reg dlab=0 */ +#define UARTDLL PHYS(0x00) /* Divisor Latch reg dlab=1*/ +#define UARTDLM PHYS(0x04) /* Divisor Latch reg dlab=1*/ +#define UARTIER PHYS(0x04) /* Interrupt enable reg */ +#define UARTFCR PHYS(0x08) /* FIFO control reg dlab =0*/ +#define UARTLCR PHYS(0x0c) /* Control reg */ +#define UARTSR PHYS(0x14) /* Status reg */ + +/* + * The following code assumes the serial port has already been + * initialized by the bootloader or such... + */ + +#define THRE 0x20 /* bit5=1, means transmit holding reg empty */ + +static void puts( const char *s ) +{ + int i,j; + + for (i = 0; *s; i++, s++) { + /* wait for space in the UART's transmiter */ + j = 0x1000; + while (--j && !(*UARTSR & THRE)); + /* if a LF, also do CR... */ + if (*s == '\n') { + /* send the CR character out. */ + *UARTDR = '\r'; + /* wait for space in the UART's transmiter */ + j = 0x1000; + while (--j && !(*UARTSR & THRE)); + } + /* send the character out. */ + *UARTDR = *s; + } +} + +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -Nru a/include/asm-arm/arch-ixp2000/vmalloc.h b/include/asm-arm/arch-ixp2000/vmalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp2000/vmalloc.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/arch-ixp2000/vmalloc.h + * + * Author: Naeem Afzal + * + * Copyright 2002 Intel Corp. + * + * 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. + * + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define FIRST_STATIC_ENTRY VIRT_CPLD_CSR +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END 0xd4000000 diff -Nru a/include/asm-arm/arch-ixp425/dma.h b/include/asm-arm/arch-ixp425/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/dma.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,52 @@ +/* + * linux/include/asm-arm/arch-80200fcc/dma.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + * + * 2002: Modified for IXP425 by Intel Corporation. + * + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#include +#include +#include +#include + +#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_64M) + +/* No DMA */ +#define MAX_DMA_CHANNELS 0 + +/* + * Only first 64MB of memory can be accessed via PCI. + * We use GFP_DMA to allocate safe buffers to do map/unmap. + * This is really ugly and we need a better way of specifying + * DMA-capable regions of memory. + */ +static inline void __arch_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + unsigned int sz = SZ_64M >> PAGE_SHIFT; + + /* + * Only adjust if > 64M on current system + */ + if (node || (zone_size[0] <= sz)) + return; + + zone_size[1] = zone_size[0] - sz; + zone_size[0] = sz; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +#define arch_adjust_zones(node, size, holes) \ + __arch_adjust_zones(node, size, holes) + +#endif /* _ASM_ARCH_DMA_H */ diff -Nru a/include/asm-arm/arch-ixp425/gpio.h b/include/asm-arm/arch-ixp425/gpio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/gpio.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,94 @@ +/* + * arch/arm/mach-ixp425/gpio.h + * + * Copyright (C) 2002 Intel 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. + * + */ + +#ifndef _ASM_ARCH_GPIO_H_ +#define _ASM_ARCH_GPIO_H_ + +#ifndef __ASSEMBLY__ + +#include + +/* GPIO pin mappings */ +#define IXP425_GPIO_PIN_15 15 +#define IXP425_GPIO_PIN_14 14 +#define IXP425_GPIO_PIN_13 13 +#define IXP425_GPIO_PIN_12 12 +#define IXP425_GPIO_PIN_11 11 +#define IXP425_GPIO_PIN_10 10 +#define IXP425_GPIO_PIN_9 9 +#define IXP425_GPIO_PIN_8 8 +#define IXP425_GPIO_PIN_7 7 +#define IXP425_GPIO_PIN_6 6 +#define IXP425_GPIO_PIN_5 5 +#define IXP425_GPIO_PIN_4 4 +#define IXP425_GPIO_PIN_3 3 +#define IXP425_GPIO_PIN_2 2 +#define IXP425_GPIO_PIN_1 1 +#define IXP425_GPIO_PIN_0 0 + +#define IXP425_GPIO_PIN_MAX IXP425_GPIO_PIN_15 + +/* GPIO pin types */ +#define IXP425_GPIO_OUT 1 +#define IXP425_GPIO_IN 2 + +/* GPIO interrupt types */ +#define IXP425_GPIO_ACTIVE_HIGH 0x4 /* Default */ +#define IXP425_GPIO_ACTIVE_LOW 0x8 +#define IXP425_GPIO_RISING_EDGE 0x10 +#define IXP425_GPIO_FALLING_EDGE 0x20 +#define IXP425_GPIO_TRANSITIONAL 0x40 + +/* GPIO signal types */ +#define IXP425_GPIO_LOW 0 +#define IXP425_GPIO_HIGH 1 + +/* GPIO Clocks */ +#define IXP425_GPIO_CLK_0 14 +#define IXP425_GPIO_CLK_1 15 + +/* + * GPIO clock frequencies. These correspond to fractions of the + * 66 MHz APB clock. + */ +#define IXP425_GPIO_33_MHZ 0x1 /* Default */ +#define IXP425_GPIO_22_MHZ 0x2 +#define IXP425_GPIO_16_5_MHZ 0x3 +#define IXP425_GPIO_13_2_MHZ 0x4 +#define IXP425_GPIO_11_MHZ 0x5 +#define IXP425_GPIO_9_4_MHZ 0x6 +#define IXP425_GPIO_8_3_MHZ 0x7 +#define IXP425_GPIO_7_3_MHZ 0x8 +#define IXP425_GPIO_6_6_MHZ 0x9 +#define IXP425_GPIO_6_MHZ 0xa +#define IXP425_GPIO_5_5_MHZ 0xb +#define IXP425_GPIO_5_1_MHZ 0xc +#define IXP425_GPIO_4_7_MHZ 0xd +#define IXP425_GPIO_4_4_MHZ 0xf + +#define IXP425_GPIO_CLK0_ENABLE 0x100 +#define IXP425_GPIO_CLK1_ENABLE 0x1000000 + +/* Left shift values to set clock terminal count (TC) and duty cycle (DC)*/ +#define IXP425_GPIO_CLK0TC_LSH 4 +#define IXP425_GPIO_CLK1TC_LSH 20 +#define IXP425_GPIO_CLK0DC_LSH 0 +#define IXP425_GPIO_CLK1DC_LSH 16 + + +extern void gpio_line_get(u8 line, int *value); +extern void gpio_line_set(u8 line, int value); +extern void gpio_line_config(u8 line, u32 style); +extern void gpio_line_isr_clear(u8 line); + +#endif // __ASSEMBLY__ + +#endif diff -Nru a/include/asm-arm/arch-ixp425/hardware.h b/include/asm-arm/arch-ixp425/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/hardware.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,30 @@ +/* + * hardware.h + * + * Copyright (C) 2002 Intel 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. + * + */ + +/* + * Hardware definitions for IXP425 based systems + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H__ +#define __ASM_ARCH_HARDWARE_H__ + +/* common definitions for all boards */ +#include "ixp425.h" +#include "gpio.h" + +#define PCIO_BASE 0 +#define PCIBIOS_MIN_IO 0x0 +#define PCIBIOS_MIN_MEM 0x0 + +#define pcibios_assign_all_busses() 1 + +#endif /* _ASM_ARCH_HARDWARE_H */ diff -Nru a/include/asm-arm/arch-ixp425/ide.h b/include/asm-arm/arch-ixp425/ide.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/ide.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,78 @@ +/* + * include/asm-arm/arch-ixp425/ide.h + * + * IDE hooks for IXP425 systems + * + * Author: Deepak Saxena + * + * Copyright 2003 (c) MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + */ + +#include + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + ide_ioreg_t reg = data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; + } + if (irq != NULL) + *irq = 0; + hw->io_ports[IDE_IRQ_OFFSET] = 0; +} + +/* + * Register the standard ports for this architecture with the IDE driver. + */ +static __inline__ void +ide_init_default_hwifs(void) +{ + /* Nothing to declare... */ +} + +/* + * We can't put cpu->le16 conversions in the generic header + * b/c it breaks other devices such as e100. It seems that + * only IDE has this problem with swapped data but that + * doesn't seem quite right either. Need to study PCI + * analyzer logs more to fully understand underlying issue. + */ +#undef outw_p +#undef outsw +#undef inw_p +#undef insw + +#define outw_p(val, port) outw((cpu_to_le16(val)), (port)) +#define inw_p(port) (le16_to_cpu(inw(port))) + +static inline void outsw(u32 p, u16* addr, u32 count) +{ + while(count--) + outw(cpu_to_le16(*addr++), p); +} + +static inline void insw(u32 p, u16* addr, u32 count) +{ + while(count--) + *addr++ = le16_to_cpu(inw(p)); +} + + diff -Nru a/include/asm-arm/arch-ixp425/io.h b/include/asm-arm/arch-ixp425/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/io.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,233 @@ +/* + * linux/include/asm-arm/arch-ixp425/io.h + * + * Author: Deepak Saxena + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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 __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +/* + * Needed for VMALLOC_STARt + */ +#include +#include + +#define IO_SPACE_LIMIT 0xffffffff + +#define __mem_isa(a) ((unsigned long)(a)) + +/* + * IXP425 does not have a transparent cpu -> PCI I/O translation + * window. Instead, it has a set of registers that must be tweaked + * with the proper byte lanes, command types, and address for the + * transaction. This means that we need to override the default + * I/O functions. + */ + +extern void ixp425_outb(u8 v, u32 p); +extern void ixp425_outw(u16 v, u32 p); +extern void ixp425_outl(u32 v, u32 p); + +extern u8 ixp425_inb(u32 p); +extern u16 ixp425_inw(u32 p); +extern u32 ixp425_inl(u32 p); + +extern void ixp425_outsb(u32 p, u8 *addr, u32 count); +extern void ixp425_outsw(u32 p, u16 *addr, u32 count); +extern void ixp425_outsl(u32 p, u32 *addr, u32 count); + +extern void ixp425_insb(u32 p, u8 *addr, u32 count); +extern void ixp425_insw(u32 p, u16 *addr, u32 count); +extern void ixp425_insl(u32 p, u32 *addr, u32 count); + +#define outb(v, p) ixp425_outb(v, p) +#define outw(v, p) ixp425_outw(v, p) +#define outl(v, p) ixp425_outl(v, p) + +#define inb(p) ixp425_inb(p) +#define inw(p) ixp425_inw(p) +#define inl(p) ixp425_inl(p) + +#define outsb(p, a, c) ixp425_outsb(p, a, c) +#define outsw(p, a, c) ixp425_outsw(p, a, c) +#define outsl(p, a, c) ixp425_outsl(p, a, c) + +#define insb(p, a, c) ixp425_insb(p, a, c) +#define insw(p, a, c) ixp425_insw(p, a, c) +#define insl(p, a, c) ixp425_insl(p, a, c) + + + +/* + * Generic virtual read/write + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + + +/* + * IXP425 also does not have a transparent PCI MEM translation + * window. For this reason, we have to use the NP registers for + * all PCI mem acceses and have to implement custom + * ioremap/unmap/etc functions. :( We need to check and make + * sure that the address being accessed is a PCI address and + * if not, fall back to the normal code. + */ + +static inline void +__writeb(u8 v, u32 p) +{ + u32 n, byte_enables, data; + + if(p > VMALLOC_START) { + __raw_writeb(v, p); + return; + } + + n = p % 4; + byte_enables = (0xf & ~BIT(n)) << IXP425_PCI_NP_CBE_BESL; + data = v << (8*n); + ixp425_pci_write(p, byte_enables | NP_CMD_MEMWRITE, data); +} + +static inline void +__writew(u16 v, u32 p) +{ + u32 n, byte_enables, data; + + if(p > VMALLOC_START) { + __raw_writew(v, p); + return; + } + + n = p % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << IXP425_PCI_NP_CBE_BESL; + data = v << (8*n); + ixp425_pci_write(p, byte_enables | NP_CMD_MEMWRITE, data); +} + +static inline void +__writel(u32 v, u32 p) +{ + if(p > VMALLOC_START) { + __raw_writel(v, p); + return; + } + + ixp425_pci_write(p, NP_CMD_MEMWRITE, v); +} + +static inline unsigned char +__readb(u32 p) +{ + u32 n, byte_enables, data; + + if(p > VMALLOC_START) + return __raw_readb(p); + + n = p % 4; + byte_enables = (0xf & ~BIT(n)) << IXP425_PCI_NP_CBE_BESL; + if (ixp425_pci_read(p, byte_enables | NP_CMD_MEMREAD, &data)) + return 0xff; + + return data >> (8*n); +} + +static inline unsigned short +__readw(u32 p) +{ + u32 n, byte_enables, data; + + if(p > VMALLOC_START) + return __raw_readw(p); + + n = p % 4; + byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << IXP425_PCI_NP_CBE_BESL; + if (ixp425_pci_read(p, byte_enables | NP_CMD_MEMREAD, &data)) + return 0xffff; + + return data>>(8*n); +} + +static inline unsigned long +__readl(u32 p) +{ + u32 data; + + if(p > VMALLOC_START) + return __raw_readl(p); + + if (ixp425_pci_read(p, NP_CMD_MEMREAD, &data)) + return 0xffffffff; + + return data; +} + +#define readb(addr) __readb(addr) +#define readw(addr) __readw(addr) +#define readl(addr) __readl(addr) +#define writeb(v, addr) __writeb(v, addr) +#define writew(v, addr) __writew(v, addr) +#define writel(v, addr) __writel(v, addr) + +/* + * We can use the built-in functions b/c they end up calling + * our versions of writeb/readb + */ +#define memset_io(c,v,l) _memset_io((c),(v),(l)) +#define memcpy_fromio(a,c,l) _memcpy_fromio((a),(c),(l)) +#define memcpy_toio(c,a,l) _memcpy_toio((c),(a),(l)) + +#define eth_io_copy_and_sum(s,c,l,b) \ + eth_copy_and_sum((s),(c),(l),(b)) + +static inline void * +__arch_ioremap(unsigned long phys_addr, size_t size, unsigned long flags) +{ + extern void * __ioremap(unsigned long, size_t, unsigned long); + + if((phys_addr < 0x48000000) || (phys_addr > 0x4bffffff)) + return __ioremap(phys_addr, size, flags); + + return (void *)phys_addr; +} + +static inline void +__arch_iounmap(void *addr) +{ + extern void __iounmap(void *); + + if(((u32)addr < 0x48000000) || ((u32)addr > 0x4bffffff)) + __iounmap(addr); +} + + + +#endif // __ASM_ARM_ARCH_IO_H + diff -Nru a/include/asm-arm/arch-ixp425/irq.h b/include/asm-arm/arch-ixp425/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/irq.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,13 @@ +/* + * irq.h + * + * Copyright (C) 2002 Intel 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. + * + */ + +#define fixup_irq(irq) (irq) + diff -Nru a/include/asm-arm/arch-ixp425/irqs.h b/include/asm-arm/arch-ixp425/irqs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/irqs.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,77 @@ +/* + * include/asm-arm/arch-ixp425/irqs.h + * + * IRQ definitions for IXP425 based systems + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003 MontaVista Software, Inc. + * + * 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 _ARCH_IXP425_IRQS_H_ +#define _ARCH_IXP425_IRQS_H_ + +#define NR_IRQS 32 + +#define IRQ_IXP425_NPEA 0 +#define IRQ_IXP425_NPEB 1 +#define IRQ_IXP425_NPEC 2 +#define IRQ_IXP425_QM1 3 +#define IRQ_IXP425_QM2 4 +#define IRQ_IXP425_TIMER1 5 +#define IRQ_IXP425_GPIO0 6 +#define IRQ_IXP425_GPIO1 7 +#define IRQ_IXP425_PCI_INT 8 +#define IRQ_IXP425_PCI_DMA1 9 +#define IRQ_IXP425_PCI_DMA2 10 +#define IRQ_IXP425_TIMER2 11 +#define IRQ_IXP425_USB 12 +#define IRQ_IXP425_UART2 13 +#define IRQ_IXP425_TIMESTAMP 14 +#define IRQ_IXP425_UART1 15 +#define IRQ_IXP425_WDOG 16 +#define IRQ_IXP425_AHB_PMU 17 +#define IRQ_IXP425_XSCALE_PMU 18 +#define IRQ_IXP425_GPIO2 19 +#define IRQ_IXP425_GPIO3 20 +#define IRQ_IXP425_GPIO4 21 +#define IRQ_IXP425_GPIO5 22 +#define IRQ_IXP425_GPIO6 23 +#define IRQ_IXP425_GPIO7 24 +#define IRQ_IXP425_GPIO8 25 +#define IRQ_IXP425_GPIO9 26 +#define IRQ_IXP425_GPIO10 27 +#define IRQ_IXP425_GPIO11 28 +#define IRQ_IXP425_GPIO12 29 +#define IRQ_IXP425_SW_INT1 30 +#define IRQ_IXP425_SW_INT2 31 + +#define XSCALE_PMU_IRQ (IRQ_IXP425_XSCALE_PMU) + +/* + * IXDP425 Board IRQs + */ +#define IRQ_IXDP425_PCI_INTA IRQ_IXP425_GPIO11 +#define IRQ_IXDP425_PCI_INTB IRQ_IXP425_GPIO10 +#define IRQ_IXDP425_PCI_INTC IRQ_IXP425_GPIO9 +#define IRQ_IXDP425_PCI_INTD IRQ_IXP425_GPIO8 + +/* + * PrPMC1100 Board IRQs + */ +#define IRQ_PRPMC1100_PCI_INTA IRQ_IXP425_GPIO11 +#define IRQ_PRPMC1100_PCI_INTB IRQ_IXP425_GPIO10 +#define IRQ_PRPMC1100_PCI_INTC IRQ_IXP425_GPIO9 +#define IRQ_PRPMC1100_PCI_INTD IRQ_IXP425_GPIO8 + +/* + * ADI Coyote Board IRQs + */ +#define IRQ_COYOTE_PCI_INTA IRQ_IXP425_GPIO11 +#define IRQ_COYOTE_PCI_INTB IRQ_IXP425_GPIO6 + +#endif diff -Nru a/include/asm-arm/arch-ixp425/ixp425.h b/include/asm-arm/arch-ixp425/ixp425.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/ixp425.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,422 @@ +/* + * include/asm-arm/arch-ixp425/ixp425.h + * + * Register definitions for IXP425 + * + * Copyright (C) 2002 Intel Corporation. + * + * Maintainer: Deepak Saxena + * + * 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 __ASM_ARCH_HARDWARE_H__ +#error "Do not include this directly, please #include " +#endif + +#ifndef _ASM_ARM_IXP425_H_ +#define _ASM_ARM_IXP425_H_ + +#ifndef BIT +#define BIT(bit) (1 << (bit)) +#endif + + +/* + * + * IXP425 Memory map: + * + * Phy Phy Size Map Size Virt Description + * ========================================================================= + * + * 0x00000000 0x10000000 SDRAM 1 + * + * 0x10000000 0x10000000 SDRAM 2 + * + * 0x20000000 0x10000000 SDRAM 3 + * + * 0x30000000 0x10000000 SDRAM 4 + * + * The above four are aliases to the same memory location (0x00000000) + * + * 0x48000000 0x4000000 PCI Memory + * + * 0x50000000 0x10000000 Not Mapped EXP BUS + * + * 0x6000000 0x00004000 0x4000 0xFFFEB000 QMgr + * + * 0xC0000000 0x100 0x1000 0xFFFDD000 PCI CFG + * + * 0xC4000000 0x100 0x1000 0xFFFDE000 EXP CFG + * + * 0xC8000000 0xC000 0xC000 0xFFFDF000 PERIPHERAL + * + * 0xCC000000 0x100 0x1000 Not Mapped SDRAM CFG + */ + + +/* + * PCI Configuration space + */ +#define IXP425_PCI_CFG_BASE_PHYS (0xC0000000) +#define IXP425_PCI_CFG_BASE_VIRT (0xFF00C000) +#define IXP425_PCI_CFG_REGION_SIZE (0x00001000) + +/* + * Expansion BUS Configuration registers + */ +#define IXP425_EXP_CFG_BASE_PHYS (0xC4000000) +#define IXP425_EXP_CFG_BASE_VIRT (0xFF00D000) +#define IXP425_EXP_CFG_REGION_SIZE (0x00001000) + +/* + * Peripheral space + */ +#define IXP425_PERIPHERAL_BASE_PHYS (0xC8000000) +#define IXP425_PERIPHERAL_BASE_VIRT (0xFF000000) +#define IXP425_PERIPHERAL_REGION_SIZE (0x0000C000) + +/* + * Q Manager space .. not static mapped + */ +#define IXP425_QMGR_BASE_PHYS (0x60000000) +#define IXP425_QMGR_BASE_VIRT (0xFF00F000) +#define IXP425_QMGR_REGION_SIZE (0x00004000) + +/* + * Expansion BUS + * + * Expansion Bus 'lives' at either base1 or base 2 depending on the value of + * Exp Bus config registers: + * + * Setting bit 31 of IXP425_EXP_CFG0 puts SDRAM at zero, + * and The expansion bus to IXP425_EXP_BUS_BASE2 + */ +#define IXP425_EXP_BUS_BASE1_PHYS (0x00000000) +#define IXP425_EXP_BUS_BASE2_PHYS (0x50000000) +#define IXP425_EXP_BUS_BASE2_VIRT (0xF0000000) + +#define IXP425_EXP_BUS_BASE_PHYS IXP425_EXP_BUS_BASE2_PHYS +#define IXP425_EXP_BUS_BASE_VIRT IXP425_EXP_BUS_BASE2_VIRT + +#define IXP425_EXP_BUS_REGION_SIZE (0x08000000) +#define IXP425_EXP_BUS_CSX_REGION_SIZE (0x01000000) + +#define IXP425_EXP_BUS_CS0_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x00000000) +#define IXP425_EXP_BUS_CS1_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x01000000) +#define IXP425_EXP_BUS_CS2_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x02000000) +#define IXP425_EXP_BUS_CS3_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x03000000) +#define IXP425_EXP_BUS_CS4_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x04000000) +#define IXP425_EXP_BUS_CS5_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x05000000) +#define IXP425_EXP_BUS_CS6_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x06000000) +#define IXP425_EXP_BUS_CS7_BASE_PHYS (IXP425_EXP_BUS_BASE2_PHYS + 0x07000000) + +#define IXP425_EXP_BUS_CS0_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x00000000) +#define IXP425_EXP_BUS_CS1_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x01000000) +#define IXP425_EXP_BUS_CS2_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x02000000) +#define IXP425_EXP_BUS_CS3_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x03000000) +#define IXP425_EXP_BUS_CS4_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x04000000) +#define IXP425_EXP_BUS_CS5_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x05000000) +#define IXP425_EXP_BUS_CS6_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x06000000) +#define IXP425_EXP_BUS_CS7_BASE_VIRT (IXP425_EXP_BUS_BASE2_VIRT + 0x07000000) + +#define IXP425_FLASH_WRITABLE (0x2) +#define IXP425_FLASH_DEFAULT (0xbcd23c40) +#define IXP425_FLASH_WRITE (0xbcd23c42) + + +#define IXP425_EXP_CS0_OFFSET 0x00 +#define IXP425_EXP_CS1_OFFSET 0x04 +#define IXP425_EXP_CS2_OFFSET 0x08 +#define IXP425_EXP_CS3_OFFSET 0x0C +#define IXP425_EXP_CS4_OFFSET 0x10 +#define IXP425_EXP_CS5_OFFSET 0x14 +#define IXP425_EXP_CS6_OFFSET 0x18 +#define IXP425_EXP_CS7_OFFSET 0x1C +#define IXP425_EXP_CFG0_OFFSET 0x20 +#define IXP425_EXP_CFG1_OFFSET 0x24 +#define IXP425_EXP_CFG2_OFFSET 0x28 +#define IXP425_EXP_CFG3_OFFSET 0x2C + +/* + * Expansion Bus Controller registers. + */ +#define IXP425_EXP_REG(x) ((volatile u32 *)(IXP425_EXP_CFG_BASE_VIRT+(x))) + +#define IXP425_EXP_CS0 IXP425_EXP_REG(IXP425_EXP_CS0_OFFSET) +#define IXP425_EXP_CS1 IXP425_EXP_REG(IXP425_EXP_CS1_OFFSET) +#define IXP425_EXP_CS2 IXP425_EXP_REG(IXP425_EXP_CS2_OFFSET) +#define IXP425_EXP_CS3 IXP425_EXP_REG(IXP425_EXP_CS3_OFFSET) +#define IXP425_EXP_CS4 IXP425_EXP_REG(IXP425_EXP_CS4_OFFSET) +#define IXP425_EXP_CS5 IXP425_EXP_REG(IXP425_EXP_CS5_OFFSET) +#define IXP425_EXP_CS6 IXP425_EXP_REG(IXP425_EXP_CS6_OFFSET) +#define IXP425_EXP_CS7 IXP425_EXP_REG(IXP425_EXP_CS7_OFFSET) + +#define IXP425_EXP_CFG0 IXP425_EXP_REG(IXP425_EXP_CFG0_OFFSET) +#define IXP425_EXP_CFG1 IXP425_EXP_REG(IXP425_EXP_CFG1_OFFSET) +#define IXP425_EXP_CFG2 IXP425_EXP_REG(IXP425_EXP_CFG2_OFFSET) +#define IXP425_EXP_CFG3 IXP425_EXP_REG(IXP425_EXP_CFG3_OFFSET) + + +#define IXP425_CONSOLE_UART_BASE_VIRT IXP425_UART1_BASE_VIRT +#define IXP425_CONSOLE_UART_BASE_PHYS IXP425_UART1_BASE_PHYS +/* + * Peripheral Space Registers + */ +#define IXP425_UART1_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x0000) +#define IXP425_UART2_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x1000) +#define IXP425_PMU_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x2000) +#define IXP425_INTC_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x3000) +#define IXP425_GPIO_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x4000) +#define IXP425_TIMER_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x5000) +#define IXP425_NPEA_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x6000) +#define IXP425_NPEB_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x7000) +#define IXP425_NPEC_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x8000) +#define IXP425_EthA_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0x9000) +#define IXP425_EthB_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0xA000) +#define IXP425_USB_BASE_PHYS (IXP425_PERIPHERAL_BASE_PHYS + 0xB000) + +#define IXP425_UART1_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x0000) +#define IXP425_UART2_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x1000) +#define IXP425_PMU_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x2000) +#define IXP425_INTC_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x3000) +#define IXP425_GPIO_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x4000) +#define IXP425_TIMER_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x5000) +#define IXP425_NPEA_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x6000) +#define IXP425_NPEB_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x7000) +#define IXP425_NPEC_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x8000) +#define IXP425_EthA_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0x9000) +#define IXP425_EthB_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0xA000) +#define IXP425_USB_BASE_VIRT (IXP425_PERIPHERAL_BASE_VIRT + 0xB000) + + +/* + * UART Register Definitions , Offsets only as there are 2 UARTS. + * IXP425_UART1_BASE , IXP425_UART2_BASE. + */ + +#undef UART_NO_RX_INTERRUPT + +#define IXP425_UART_XTAL 14745600 + +/* + * Constants to make it easy to access Interrupt Controller registers + */ +#define IXP425_ICPR_OFFSET 0x00 /* Interrupt Status */ +#define IXP425_ICMR_OFFSET 0x04 /* Interrupt Enable */ +#define IXP425_ICLR_OFFSET 0x08 /* Interrupt IRQ/FIQ Select */ +#define IXP425_ICIP_OFFSET 0x0C /* IRQ Status */ +#define IXP425_ICFP_OFFSET 0x10 /* FIQ Status */ +#define IXP425_ICHR_OFFSET 0x14 /* Interrupt Priority */ +#define IXP425_ICIH_OFFSET 0x18 /* IRQ Highest Pri Int */ +#define IXP425_ICFH_OFFSET 0x1C /* FIQ Highest Pri Int */ + +/* + * Interrupt Controller Register Definitions. + */ +#define IXP425_INTC_REG(x) ((volatile u32 *)(IXP425_INTC_BASE_VIRT+(x))) + +#define IXP425_ICPR IXP425_INTC_REG(IXP425_ICPR_OFFSET) +#define IXP425_ICMR IXP425_INTC_REG(IXP425_ICMR_OFFSET) +#define IXP425_ICLR IXP425_INTC_REG(IXP425_ICLR_OFFSET) +#define IXP425_ICIP IXP425_INTC_REG(IXP425_ICIP_OFFSET) +#define IXP425_ICFP IXP425_INTC_REG(IXP425_ICFP_OFFSET) +#define IXP425_ICHR IXP425_INTC_REG(IXP425_ICHR_OFFSET) +#define IXP425_ICIH IXP425_INTC_REG(IXP425_ICIH_OFFSET) +#define IXP425_ICFH IXP425_INTC_REG(IXP425_ICFH_OFFSET) + +/* + * Constants to make it easy to access GPIO registers + */ +#define IXP425_GPIO_GPOUTR_OFFSET 0x00 +#define IXP425_GPIO_GPOER_OFFSET 0x04 +#define IXP425_GPIO_GPINR_OFFSET 0x08 +#define IXP425_GPIO_GPISR_OFFSET 0x0C +#define IXP425_GPIO_GPIT1R_OFFSET 0x10 +#define IXP425_GPIO_GPIT2R_OFFSET 0x14 +#define IXP425_GPIO_GPCLKR_OFFSET 0x18 +#define IXP425_GPIO_GPDBSELR_OFFSET 0x1C + +/* + * GPIO Register Definitions. + * [Only perform 32bit reads/writes] + */ +#define IXP425_GPIO_REG(x) ((volatile u32 *)(IXP425_GPIO_BASE_VIRT+(x))) + +#define IXP425_GPIO_GPOUTR IXP425_GPIO_REG(IXP425_GPIO_GPOUTR_OFFSET) +#define IXP425_GPIO_GPOER IXP425_GPIO_REG(IXP425_GPIO_GPOER_OFFSET) +#define IXP425_GPIO_GPINR IXP425_GPIO_REG(IXP425_GPIO_GPINR_OFFSET) +#define IXP425_GPIO_GPISR IXP425_GPIO_REG(IXP425_GPIO_GPISR_OFFSET) +#define IXP425_GPIO_GPIT1R IXP425_GPIO_REG(IXP425_GPIO_GPIT1R_OFFSET) +#define IXP425_GPIO_GPIT2R IXP425_GPIO_REG(IXP425_GPIO_GPIT2R_OFFSET) +#define IXP425_GPIO_GPCLKR IXP425_GPIO_REG(IXP425_GPIO_GPCLKR_OFFSET) +#define IXP425_GPIO_GPDBSELR IXP425_GPIO_REG(IXP425_GPIO_GPDBSELR_OFFSET) + +/* + * Constants to make it easy to access Timer Control/Status registers + */ +#define IXP425_OSTS_OFFSET 0x00 /* Continious TimeStamp */ +#define IXP425_OST1_OFFSET 0x04 /* Timer 1 Timestamp */ +#define IXP425_OSRT1_OFFSET 0x08 /* Timer 1 Reload */ +#define IXP425_OST2_OFFSET 0x0C /* Timer 2 Timestamp */ +#define IXP425_OSRT2_OFFSET 0x10 /* Timer 2 Reload */ +#define IXP425_OSWT_OFFSET 0x14 /* Watchdog Timer */ +#define IXP425_OSWE_OFFSET 0x18 /* Watchdog Enable */ +#define IXP425_OSWK_OFFSET 0x1C /* Watchdog Key */ +#define IXP425_OSST_OFFSET 0x20 /* Timer Status */ + +/* + * Operating System Timer Register Definitions. + */ + +#define IXP425_TIMER_REG(x) ((volatile u32 *)(IXP425_TIMER_BASE_VIRT+(x))) + +#define IXP425_OSTS IXP425_TIMER_REG(IXP425_OSTS_OFFSET) +#define IXP425_OST1 IXP425_TIMER_REG(IXP425_OST1_OFFSET) +#define IXP425_OSRT1 IXP425_TIMER_REG(IXP425_OSRT1_OFFSET) +#define IXP425_OST2 IXP425_TIMER_REG(IXP425_OST2_OFFSET) +#define IXP425_OSRT2 IXP425_TIMER_REG(IXP425_OSRT2_OFFSET) +#define IXP425_OSWT IXP425_TIMER_REG(IXP425_OSWT_OFFSET) +#define IXP425_OSWE IXP425_TIMER_REG(IXP425_OSWE_OFFSET) +#define IXP425_OSWK IXP425_TIMER_REG(IXP425_OSWK_OFFSET) +#define IXP425_OSST IXP425_TIMER_REG(IXP425_OSST_OFFSET) + +/* + * Timer register values and bit definitions + */ +#define IXP425_OST_ENABLE BIT(0) +#define IXP425_OST_ONE_SHOT BIT(1) +/* Low order bits of reload value ignored */ +#define IXP425_OST_RELOAD_MASK (0x3) +#define IXP425_OST_DISABLED (0x0) +#define IXP425_OSST_TIMER_1_PEND BIT(0) +#define IXP425_OSST_TIMER_2_PEND BIT(1) +#define IXP425_OSST_TIMER_TS_PEND BIT(2) +#define IXP425_OSST_TIMER_WDOG_PEND BIT(3) +#define IXP425_OSST_TIMER_WARM_RESET BIT(4) + +/* + * Constants to make it easy to access PCI Control/Status registers + */ +#define PCI_NP_AD_OFFSET 0x00 +#define PCI_NP_CBE_OFFSET 0x04 +#define PCI_NP_WDATA_OFFSET 0x08 +#define PCI_NP_RDATA_OFFSET 0x0c +#define PCI_CRP_AD_CBE_OFFSET 0x10 +#define PCI_CRP_WDATA_OFFSET 0x14 +#define PCI_CRP_RDATA_OFFSET 0x18 +#define PCI_CSR_OFFSET 0x1c +#define PCI_ISR_OFFSET 0x20 +#define PCI_INTEN_OFFSET 0x24 +#define PCI_DMACTRL_OFFSET 0x28 +#define PCI_AHBMEMBASE_OFFSET 0x2c +#define PCI_AHBIOBASE_OFFSET 0x30 +#define PCI_PCIMEMBASE_OFFSET 0x34 +#define PCI_AHBDOORBELL_OFFSET 0x38 +#define PCI_PCIDOORBELL_OFFSET 0x3C +#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40 +#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44 +#define PCI_ATPDMA0_LENADDR_OFFSET 0x48 +#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C +#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50 +#define PCI_ATPDMA1_LENADDR_OFFSET 0x54 + +/* + * PCI Control/Status Registers + */ +#define IXP425_PCI_CSR(x) ((volatile u32 *)(IXP425_PCI_CFG_BASE_VIRT+(x))) + +#define PCI_NP_AD IXP425_PCI_CSR(PCI_NP_AD_OFFSET) +#define PCI_NP_CBE IXP425_PCI_CSR(PCI_NP_CBE_OFFSET) +#define PCI_NP_WDATA IXP425_PCI_CSR(PCI_NP_WDATA_OFFSET) +#define PCI_NP_RDATA IXP425_PCI_CSR(PCI_NP_RDATA_OFFSET) +#define PCI_CRP_AD_CBE IXP425_PCI_CSR(PCI_CRP_AD_CBE_OFFSET) +#define PCI_CRP_WDATA IXP425_PCI_CSR(PCI_CRP_WDATA_OFFSET) +#define PCI_CRP_RDATA IXP425_PCI_CSR(PCI_CRP_RDATA_OFFSET) +#define PCI_CSR IXP425_PCI_CSR(PCI_CSR_OFFSET) +#define PCI_ISR IXP425_PCI_CSR(PCI_ISR_OFFSET) +#define PCI_INTEN IXP425_PCI_CSR(PCI_INTEN_OFFSET) +#define PCI_DMACTRL IXP425_PCI_CSR(PCI_DMACTRL_OFFSET) +#define PCI_AHBMEMBASE IXP425_PCI_CSR(PCI_AHBMEMBASE_OFFSET) +#define PCI_AHBIOBASE IXP425_PCI_CSR(PCI_AHBIOBASE_OFFSET) +#define PCI_PCIMEMBASE IXP425_PCI_CSR(PCI_PCIMEMBASE_OFFSET) +#define PCI_AHBDOORBELL IXP425_PCI_CSR(PCI_AHBDOORBELL_OFFSET) +#define PCI_PCIDOORBELL IXP425_PCI_CSR(PCI_PCIDOORBELL_OFFSET) +#define PCI_ATPDMA0_AHBADDR IXP425_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET) +#define PCI_ATPDMA0_PCIADDR IXP425_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET) +#define PCI_ATPDMA0_LENADDR IXP425_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET) +#define PCI_ATPDMA1_AHBADDR IXP425_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET) +#define PCI_ATPDMA1_PCIADDR IXP425_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET) +#define PCI_ATPDMA1_LENADDR IXP425_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET) + +/* + * PCI register values and bit definitions + */ + +/* CSR bit definitions */ +#define PCI_CSR_HOST BIT(0) +#define PCI_CSR_ARBEN BIT(1) +#define PCI_CSR_ADS BIT(2) +#define PCI_CSR_PDS BIT(3) +#define PCI_CSR_ABE BIT(4) +#define PCI_CSR_DBT BIT(5) +#define PCI_CSR_ASE BIT(8) +#define PCI_CSR_IC BIT(15) + +/* ISR (Interrupt status) Register bit definitions */ +#define PCI_ISR_PSE BIT(0) +#define PCI_ISR_PFE BIT(1) +#define PCI_ISR_PPE BIT(2) +#define PCI_ISR_AHBE BIT(3) +#define PCI_ISR_APDC BIT(4) +#define PCI_ISR_PADC BIT(5) +#define PCI_ISR_ADB BIT(6) +#define PCI_ISR_PDB BIT(7) + +/* INTEN (Interrupt Enable) Register bit definitions */ +#define PCI_INTEN_PSE BIT(0) +#define PCI_INTEN_PFE BIT(1) +#define PCI_INTEN_PPE BIT(2) +#define PCI_INTEN_AHBE BIT(3) +#define PCI_INTEN_APDC BIT(4) +#define PCI_INTEN_PADC BIT(5) +#define PCI_INTEN_ADB BIT(6) +#define PCI_INTEN_PDB BIT(7) + +/* + * Shift value for byte enable on NP cmd/byte enable register + */ +#define IXP425_PCI_NP_CBE_BESL 4 + +/* + * PCI commands supported by NP access unit + */ +#define NP_CMD_IOREAD 0x2 +#define NP_CMD_IOWRITE 0x3 +#define NP_CMD_CONFIGREAD 0xa +#define NP_CMD_CONFIGWRITE 0xb +#define NP_CMD_MEMREAD 0x6 +#define NP_CMD_MEMWRITE 0x7 + +#ifndef __ASSEMBLY__ +extern int (*ixp425_pci_read)(u32 addr, u32 cmd, u32* data); +extern int ixp425_pci_write(u32 addr, u32 cmd, u32 data); +extern void ixp425_pci_init(void *); +#endif + +/* + * Constants for CRP access into local config space + */ +#define CRP_AD_CBE_BESL 20 +#define CRP_AD_CBE_WRITE BIT(16) + +/* + * Clock Speed Definitions. + */ +#define IXP425_PERIPHERAL_BUS_CLOCK (66) /* 66Mhzi APB BUS */ + + +#endif diff -Nru a/include/asm-arm/arch-ixp425/memory.h b/include/asm-arm/arch-ixp425/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/memory.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-ixp425/memory.h + * + * Copyright (c) 2001 MontaVista Software, Inc. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + + +#define PAGE_OFFSET ((unsigned long)(CONFIG_KERNEL_START & 0xffc00000)) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0x00000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + * + * These are dummies for now. + */ +#define __virt_to_bus__is_a_macro +#define __bus_to_virt__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff -Nru a/include/asm-arm/arch-ixp425/param.h b/include/asm-arm/arch-ixp425/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/param.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-ixp425/param.h + */ diff -Nru a/include/asm-arm/arch-ixp425/pci-bridge.h b/include/asm-arm/arch-ixp425/pci-bridge.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/pci-bridge.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,65 @@ +/* + * include/asm-arm/arch-iop310/pci-bridge.h + * + * Generic PCI hose support for Xscale/ARM. To eventually be + * moved to a more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 __KERNEL__ +#ifndef _ASM_PCI_BRIDGE_H +#define _ASM_PCI_BRIDGE_H + +struct device_node; +struct pci_controller; + +/* Get the PCI host controller for a bus */ +extern struct pci_controller* pci_bus_to_hose(int bus); + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; + struct pci_controller *next; + struct pci_bus *bus; + void *arch_data; + + int first_busno; + int last_busno; + + struct pci_ops *ops; + volatile unsigned int *cfg_addr; + volatile unsigned char *cfg_data; + + /* Currently, we limit ourselves to 1 IO range and 3 mem + * ranges since the common pci_bus structure can't handle more + */ + struct resource io_resource; + struct resource mem_resources[3]; + int mem_resource_count; + + /* Host bridge I/O and Memory space + * Used for BAR placement algorithms + */ + struct resource io_space; + struct resource mem_space; +}; + +/* These are used for config access before all the PCI probing + has been done. */ +int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 *val); +int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 *val); +int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 *val); +int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn, int where, u8 val); +int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val); +int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val); +#endif +#endif /* __KERNEL__ */ diff -Nru a/include/asm-arm/arch-ixp425/pci.h b/include/asm-arm/arch-ixp425/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/pci.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,36 @@ +/* + * include/asm-arm/arch-xscale/pci.h + * + * Generic PCI support for Xscale/ARM. To eventually be moved to a + * more generic location. + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ASM_ARCH_PCI_H +#define _ASM_ARCH_PCI_H + +extern struct pci_controller* pcibios_alloc_controller(void); +extern void pcibios_allocate_resources(void); +extern void pci_exclude_device(unsigned char, unsigned char); +extern struct pci_dev * fake_pci_dev(struct pci_controller *, int, int); +extern u8 common_swizzle(struct pci_dev *, u8 *); + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. + */ +#define PCI_IRQ_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ + _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ + _ctl_; }) + +#endif /* _ASM_ARCH_PCI_H */ diff -Nru a/include/asm-arm/arch-ixp425/pci_auto.h b/include/asm-arm/arch-ixp425/pci_auto.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/pci_auto.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-iop310/pci_auto.h + * + * PCI autoconfiguration library definitions + * + * Matt Porter + * + * Copyright 2001 MontaVista Software Inc. + * + * 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 _ARM_MACH_XSCALE_PCI_AUTO_H +#define _ARM_MACH_XSCALE_PCI_AUTO_H + +#include "pci-bridge.h" + +extern int pciauto_bus_scan(struct pci_controller *, int); + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#endif /* _ARM_MACH_XSCALE_PCI_AUTO_H */ diff -Nru a/include/asm-arm/arch-ixp425/serial.h b/include/asm-arm/arch-ixp425/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/serial.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,53 @@ +/* + * include/asm-arm/arch-ixp425/serial.h + * + * Author: Deepak Saxena + * Modified for ixp425 offsets pbarry-intel + * + * Copyright (c) 2001 MontaVista Software, Inc. + * + * 2002: Modified for IXP425 by Intel Corporation. + * + */ + +#ifndef _ARCH_SERIAL_H_ +#define _ARCH_SERIAL_H_ + + +/* Standard COM flags */ +#define STD_COM_FLAGS ( ASYNC_SKIP_TEST) + +#undef BASE_BAUD + +/* + * IXP425 uses 15.6MHz clock for uart + */ +#define BASE_BAUD ( IXP425_UART_XTAL / 16 ) + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + { \ + type: PORT_XSCALE, \ + xmit_fifo_size: 32, \ + baud_base: BASE_BAUD, \ + irq: IRQ_IXP425_UART1, \ + flags: STD_COM_FLAGS, \ + iomem_base: (IXP425_UART1_BASE_VIRT+3), \ + io_type: SERIAL_IO_MEM, \ + iomem_reg_shift: 2 \ + }, /* ttyS0 */ \ + { \ + type: PORT_XSCALE, \ + xmit_fifo_size: 32, \ + baud_base: BASE_BAUD, \ + irq: IRQ_IXP425_UART2, \ + flags: STD_COM_FLAGS, \ + iomem_base: (IXP425_UART2_BASE_VIRT+3), \ + io_type: SERIAL_IO_MEM, \ + iomem_reg_shift: 2 \ + } /* ttyS1 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif // _ARCH_SERIAL_H_ diff -Nru a/include/asm-arm/arch-ixp425/system.h b/include/asm-arm/arch-ixp425/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/system.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,43 @@ +/* + * system.h + * + * Copyright (C) 2002 Intel 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 + +static inline void arch_idle(void) +{ +#if 0 + if (!hlt_counter) + cpu_do_idle(0); +#endif +} + + +static inline void arch_reset(char mode) +{ + if ( 1 && mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + /* Use on-chip reset capability */ + + /* set the "key" register to enable access to + * "timer" and "enable" registers + */ + *IXP425_OSWK = 0x482e; + + /* write 0 to the timer register for an immidiate reset */ + *IXP425_OSWT = 0; + + /* disable watchdog interrupt, enable reset, enable count */ + *IXP425_OSWE = 0x3; + } +} + diff -Nru a/include/asm-arm/arch-ixp425/time.h b/include/asm-arm/arch-ixp425/time.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/time.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,5 @@ +/* + * linux/include/asm-arm/arch-ixp425/time.h + * + */ + diff -Nru a/include/asm-arm/arch-ixp425/timex.h b/include/asm-arm/arch-ixp425/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/timex.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,11 @@ +/* + * linux/include/asm-arm/arch-ixp425/timex.h + * + * XScale architecture timex specifications + */ + +/* + * We use IXP425 General purpose timer for our timer needs, it runs at 66 MHz + */ +#define CLOCK_TICK_RATE (IXP425_PERIPHERAL_BUS_CLOCK * 1000000) + diff -Nru a/include/asm-arm/arch-ixp425/uncompress.h b/include/asm-arm/arch-ixp425/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/uncompress.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,57 @@ +/* + * uncompress.h + * + * Copyright (C) 2002 Intel 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. + * + */ + +#ifndef _ARCH_UNCOMPRESS_H_ +#define _ARCH_UNCOMPRESS_H_ + +#include +#include +#include + +static volatile u32* UART_BASE; +#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE) + +static __inline__ void putc(char c) +{ + /* Check THRE and TEMT bits before we transmit the character. + */ + while ((UART_BASE[UART_LSR] & TX_DONE) != TX_DONE); + *UART_BASE = c; +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) + { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +static __inline__ void arch_decomp_setup(void) +{ + unsigned long mach_type; + + asm("mov %0, r7" : "=r" (mach_type) ); + if(mach_type == MACH_TYPE_ADI_COYOTE) + UART_BASE = IXP425_UART2_BASE_PHYS; + else + UART_BASE = IXP425_UART1_BASE_PHYS; +} + +#define arch_decomp_wdog() + +#endif diff -Nru a/include/asm-arm/arch-ixp425/vmalloc.h b/include/asm-arm/arch-ixp425/vmalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/arch-ixp425/vmalloc.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-ixp425/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (0xFF000000) diff -Nru a/include/asm-arm/assembler.h b/include/asm-arm/assembler.h --- a/include/asm-arm/assembler.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/assembler.h Thu Dec 4 16:24:25 2003 @@ -13,3 +13,17 @@ #include #include + +/* + * Endian independent macros for shifting bytes within registers. + */ +#ifndef __ARMEB__ +#define pull lsr +#define push lsl +#define byte(x) (x*8) +#else +#define pull lsl +#define push lsr +#define byte(x) ((3-x)*8) +#endif + diff -Nru a/include/asm-arm/bitfield.h b/include/asm-arm/bitfield.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/bitfield.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,123 @@ +/* + * FILE bitfield.h + * + * Version 1.1 + * Author Copyright (c) Marc A. Viredaz, 1998 + * DEC Western Research Laboratory, Palo Alto, CA + * Date April 1998 (April 1997) + * System Advanced RISC Machine (ARM) + * Language C or ARM Assembly + * Purpose Definition of macros to operate on bit fields. + */ + + + +#ifndef BITFIELD +#define BITFIELD + +#ifndef LANGUAGE +#define LANGUAGE C +#endif /* !defined (LANGUAGE) */ + +#define C 0 +#define Assembly 1 + +#if LANGUAGE == C +#define UData(Data) ((unsigned int) (Data)) +#elif LANGUAGE == Assembly +#define UData(Data) (Data) +#endif /* LANGUAGE == C || LANGUAGE == Assembly */ + + +/* + * MACRO: Fld + * + * Purpose + * The macro "Fld" encodes a bit field, given its size and its shift value + * with respect to bit 0. + * + * Note + * A more intuitive way to encode bit fields would have been to use their + * mask. However, extracting size and shift value information from a bit + * field's mask is cumbersome and might break the assembler (255-character + * line-size limit). + * + * Input + * Size Size of the bit field, in number of bits. + * Shft Shift value of the bit field with respect to bit 0. + * + * Output + * Fld Encoded bit field. + */ + +#define Fld(Size, Shft) (((Size) << 16) + (Shft)) + + +/* + * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit + * + * Purpose + * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return + * the size, shift value, mask, aligned mask, and first bit of a + * bit field. + * + * Input + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FSize Size of the bit field, in number of bits. + * FShft Shift value of the bit field with respect to bit 0. + * FMsk Mask for the bit field. + * FAlnMsk Mask for the bit field, aligned on bit 0. + * F1stBit First bit of the bit field. + */ + +#define FSize(Field) ((Field) >> 16) +#define FShft(Field) ((Field) & 0x0000FFFF) +#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) +#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) +#define F1stBit(Field) (UData (1) << FShft (Field)) + + +/* + * MACRO: FInsrt + * + * Purpose + * The macro "FInsrt" inserts a value into a bit field by shifting the + * former appropriately. + * + * Input + * Value Bit-field value. + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FInsrt Bit-field value positioned appropriately. + */ + +#define FInsrt(Value, Field) \ + (UData (Value) << FShft (Field)) + + +/* + * MACRO: FExtr + * + * Purpose + * The macro "FExtr" extracts the value of a bit field by masking and + * shifting it appropriately. + * + * Input + * Data Data containing the bit-field to be extracted. + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FExtr Bit-field value. + */ + +#define FExtr(Data, Field) \ + ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) + + +#undef C +#undef Assembly + +#endif /* !defined (BITFIELD) */ diff -Nru a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h --- a/include/asm-arm/bitops.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/bitops.h Thu Dec 4 16:24:25 2003 @@ -23,30 +23,50 @@ /* * Function prototypes to keep gcc -Wall happy. */ -extern void set_bit(int nr, volatile void * addr); +extern void _set_bit_le(int nr, volatile void * addr); +extern void _set_bit_be(int nr, volatile void * addr); -static inline void __set_bit(int nr, volatile void *addr) +static inline void ___set_bit_le(int nr, volatile void *addr) { ((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7)); } -extern void clear_bit(int nr, volatile void * addr); +static inline void ___set_bit_be(int nr, volatile void *addr) +{ + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] |= (1U << (nr & 7)); +} -static inline void __clear_bit(int nr, volatile void *addr) +extern void _clear_bit_le(int nr, volatile void * addr); +extern void _clear_bit_be(int nr, volatile void * addr); + +static inline void ___clear_bit_le(int nr, volatile void *addr) { ((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7)); } -extern void change_bit(int nr, volatile void * addr); +static inline void ___clear_bit_be(int nr, volatile void *addr) +{ + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] &= ~(1U << (nr & 7)); +} + + +extern void _change_bit_le(int nr, volatile void * addr); +extern void _change_bit_be(int nr, volatile void * addr); -static inline void __change_bit(int nr, volatile void *addr) +static inline void ___change_bit_le(int nr, volatile void *addr) { ((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7)); } -extern int test_and_set_bit(int nr, volatile void * addr); +static inline void ___change_bit_be(int nr, volatile void *addr) +{ + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] ^= (1U << (nr & 7)); +} + +extern int _test_and_set_bit_le(int nr, volatile void * addr); +extern int _test_and_set_bit_be(int nr, volatile void * addr); -static inline int __test_and_set_bit(int nr, volatile void *addr) +static inline int ___test_and_set_bit_le(int nr, volatile void *addr) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; @@ -56,9 +76,20 @@ return oldval & mask; } -extern int test_and_clear_bit(int nr, volatile void * addr); +static inline int ___test_and_set_bit_be(int nr, volatile void *addr) +{ + unsigned int mask = 1 << (nr & 7); + unsigned int oldval; -static inline int __test_and_clear_bit(int nr, volatile void *addr) + oldval = ((unsigned char *) addr)[(nr ^ 0x18) >> 3]; + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] = oldval | mask; + return oldval & mask; +} + +extern int _test_and_clear_bit_le(int nr, volatile void * addr); +extern int _test_and_clear_bit_be(int nr, volatile void * addr); + +static inline int ___test_and_clear_bit_le(int nr, volatile void *addr) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; @@ -68,9 +99,20 @@ return oldval & mask; } -extern int test_and_change_bit(int nr, volatile void * addr); +static inline int ___test_and_clear_bit_be(int nr, volatile void *addr) +{ + unsigned int mask = 1 << (nr & 7); + unsigned int oldval; + + oldval = ((unsigned char *) addr)[(nr ^ 0x18) >> 3]; + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] = oldval & ~mask; + return oldval & mask; +} + +extern int _test_and_change_bit_le(int nr, volatile void * addr); +extern int _test_and_change_bit_be(int nr, volatile void * addr); -static inline int __test_and_change_bit(int nr, volatile void *addr) +static inline int ___test_and_change_bit_le(int nr, volatile void *addr) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; @@ -80,18 +122,86 @@ return oldval & mask; } -extern int find_first_zero_bit(void * addr, unsigned size); -extern int find_next_zero_bit(void * addr, int size, int offset); +static inline int ___test_and_change_bit_be(int nr, volatile void *addr) +{ + unsigned int mask = 1 << (nr & 7); + unsigned int oldval; -/* - * This routine doesn't need to be atomic. - */ -static inline int test_bit(int nr, const void * addr) + oldval = ((unsigned char *) addr)[(nr ^ 0x18) >> 3]; + ((unsigned char *) addr)[(nr ^ 0x18) >> 3] = oldval ^ mask; + return oldval & mask; +} + +extern int _find_first_zero_bit_le(void * addr, unsigned size); +extern int _find_next_zero_bit_le(void * addr, int size, int offset); +extern int _find_first_zero_bit_be(void * addr, unsigned size); +extern int _find_next_zero_bit_be(void * addr, int size, int offset); + + /* + * This routine doesn't need to be atomic. + */ +extern __inline__ int _test_bit_le(int nr, const void * addr) + { + return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7)); + } + +static __inline__ int _test_bit_be(int nr, const void * addr) { - return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1; + return ((unsigned char *) addr)[(nr ^ 0x18) >> 3] & (1U << (nr & 7)); } /* + * Definitions according to our current endianness. + */ + +#ifndef __ARMEB__ + +#define set_bit _set_bit_le +#define clear_bit _clear_bit_le +#define change_bit _change_bit_le +#define test_bit _test_bit_le + +#define test_and_set_bit _test_and_set_bit_le +#define test_and_clear_bit _test_and_clear_bit_le +#define test_and_change_bit _test_and_change_bit_le + +#define find_first_zero_bit _find_first_zero_bit_le +#define find_next_zero_bit _find_next_zero_bit_le + +#define __set_bit ___set_bit_le +#define __clear_bit ___clear_bit_le +#define __change_bit ___change_bit_le + +#define __test_and_set_bit ___test_and_set_bit_le +#define __test_and_clear_bit ___test_and_clear_bit_le +#define __test_and_change_bit ___test_and_change_bit_le + +#else + +#define set_bit _set_bit_be +#define clear_bit _clear_bit_be +#define change_bit _change_bit_be +#define test_bit _test_bit_be + +#define test_and_set_bit _test_and_set_bit_be +#define test_and_clear_bit _test_and_clear_bit_be +#define test_and_change_bit _test_and_change_bit_be + +#define find_first_zero_bit _find_first_zero_bit_be +#define find_next_zero_bit _find_next_zero_bit_be + +#define __set_bit ___set_bit_be +#define __clear_bit ___clear_bit_be +#define __change_bit ___change_bit_be + +#define __test_and_set_bit ___test_and_set_bit_be +#define __test_and_clear_bit ___test_and_clear_bit_be +#define __test_and_change_bit ___test_and_change_bit_be + +#endif + + +/* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ @@ -126,18 +236,18 @@ #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) -#define ext2_set_bit test_and_set_bit -#define ext2_clear_bit test_and_clear_bit -#define ext2_test_bit test_bit -#define ext2_find_first_zero_bit find_first_zero_bit -#define ext2_find_next_zero_bit find_next_zero_bit +#define ext2_set_bit _test_and_set_bit_le +#define ext2_clear_bit _test_and_clear_bit_le +#define ext2_test_bit _test_bit_le +#define ext2_find_first_zero_bit _find_first_zero_bit_le +#define ext2_find_next_zero_bit _find_next_zero_bit_le /* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) -#define minix_test_bit(nr,addr) test_bit(nr,addr) -#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) +#define minix_test_and_set_bit(nr,addr) _test_and_set_bit_le(nr,addr) +#define minix_set_bit(nr,addr) _set_bit_le(nr,addr) +#define minix_test_and_clear_bit(nr,addr) _test_and_clear_bit_le(nr,addr) +#define minix_test_bit(nr,addr) _test_bit_le(nr,addr) +#define minix_find_first_zero_bit(addr,size) _find_first_zero_bit_le(addr,size) #endif /* __KERNEL__ */ diff -Nru a/include/asm-arm/checksum.h b/include/asm-arm/checksum.h --- a/include/asm-arm/checksum.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/checksum.h Thu Dec 4 16:24:25 2003 @@ -105,7 +105,11 @@ adcs %0, %0, %5 \n\ adc %0, %0, #0" : "=&r"(sum) +#ifndef __ARMEB__ : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8) +#else + : "r" (sum), "r" (daddr), "r" (saddr), "r" (len), "Ir" (proto) +#endif : "cc"); return sum; } @@ -127,7 +131,11 @@ addcs %0, %0, #0x10000 \n\ mvn %0, %0" : "=&r"(sum) +#ifndef __ARMEB__ : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8) +#else + : "r" (sum), "r" (daddr), "r" (saddr), "r" (len), "Ir" (proto) +#endif : "cc"); return sum >> 16; } diff -Nru a/include/asm-arm/io.h b/include/asm-arm/io.h --- a/include/asm-arm/io.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/io.h Thu Dec 4 16:24:25 2003 @@ -25,6 +25,7 @@ #include #include #include +#include #include /* diff -Nru a/include/asm-arm/kgdb.h b/include/asm-arm/kgdb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/kgdb.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,97 @@ +/* + * include/asm-arm/kgdb.h + * + * ARM KGDB support + * + * Author: Deepak Saxena + * + * Copyright (C) 2002 MontaVista Software Inc. + * + */ + +#ifndef __ASM_KGDB_H__ +#define __ASM_KGDB_H__ + + +#ifdef CONFIG_KGDB + +/* + * Generic kgdb entry point + * + * This is called by various trap handlers when all else fails + * and a kernel excpetion has occured. + */ +void do_kgdb(struct pt_regs *, unsigned char); + + +/* + * Determine if KGDB is running or not + */ +int kgdb_active(void); + +/* + * Are we connected to a remote client? + */ +int kgdb_connected(void); + +/* + * kgdb_handle_bus_error() is used to recover from bus errors + * which may occur during kgdb memory read/write operations. + * Before performing a memory read/write operation, we set + * the kgdb_fault_expected flag, call setjmp to save the + * current machine context, and then perform the read/write + * operation. If an error occurs, kgdb_handle_bus_error is + * invoked from do_page_fault and we call longjmp to restore + * the machine state and return to kgdb at the setjmp return + * address. Both setjmp and longjmp return a flag which is + * tested upon return to determine if all is well. Upon the + * initial call to setjmp, the machine context is saved and + * a return value of zero indicates all is well. Next, we + * perform the read/write operation. Now, if an error occurs, + * longjmp will return to the setjmp == 0 test case. But + * this time, non-zero status is returned. In which case, + * we return an error status message to the gdb host. Else, + * if the read/write operation succeeds, we return the usual + * status message to the gdb host. + */ +extern void kgdb_handle_bus_error(void); +extern int kgdb_setjmp(int *machine_context); +extern int kgdb_longjmp(int *machine_context, int flag); +extern int kgdb_fault_expected; + +/* + * breakpoint() is used by the kernel at initialization to force + * a sync with the GDB on the host side. + */ +#define breakpoint() asm (".word 0xe7ffdeff") + +extern void kgdb_get_packet(unsigned char *, int); +extern void kgdb_put_packet(unsigned char *); + +extern int kgdb_io_init(void); + +#ifdef CONFIG_KGDB_SERIAL + +extern unsigned char kgdb_serial_getchar(void); +extern void kgdb_serial_putchar(unsigned char); + +extern void kgdb_serial_init(void); + +#endif + +#ifdef CONFIG_KGDB_UDP + +extern unsigned kgdb_net_rx(unsigned char *); +extern unsigned kgdb_net_tx(unsigned char *); + +#endif + +#else // NO KGDB + +#define kgdb_active() 0 + +#define breakpoint() + +#endif + +#endif // __ASM_KGDB_H__ diff -Nru a/include/asm-arm/mach/pci.h b/include/asm-arm/mach/pci.h --- a/include/asm-arm/mach/pci.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/mach/pci.h Thu Dec 4 16:24:25 2003 @@ -27,6 +27,17 @@ int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); }; +struct pci_sys_data { + /* + * The hardware we are attached to + */ + struct hw_pci *hw; + unsigned long mem_offset; + /* + * These are the resources for the root bus. + */ + struct resource *resource[3]; +}; extern u8 no_swizzle(struct pci_dev *dev, u8 *pin); extern void __init dc21285_setup_resources(struct resource **resource); extern void __init dc21285_init(void *sysdata); diff -Nru a/include/asm-arm/memory.h b/include/asm-arm/memory.h --- a/include/asm-arm/memory.h Thu Dec 4 16:24:26 2003 +++ b/include/asm-arm/memory.h Thu Dec 4 16:24:26 2003 @@ -49,6 +49,10 @@ #define virt_to_bus(x) (__virt_to_bus((unsigned long)(x))) #define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x)))) + +/* We want large page mappings */ +#define VMALLOC_ALIGN 0x10000 + /* * Conversion between a struct page and a physical address. * diff -Nru a/include/asm-arm/pci.h b/include/asm-arm/pci.h --- a/include/asm-arm/pci.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/pci.h Thu Dec 4 16:24:25 2003 @@ -53,6 +53,10 @@ /* We don't do dynamic PCI IRQ allocation */ } +#include +#include +#include + struct pci_dev; /* Allocate and map kernel buffer using consistent mode DMA for a device. @@ -88,6 +92,10 @@ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { +#ifdef CONFIG_ARCH_IXP425 + extern dma_addr_t ixp425_map_single(void *, size_t, int); + return ixp425_map_single(ptr, size, direction); +#endif if (dev_is_sa1111(hwdev)) return sa1111_map_single(ptr, size, direction); @@ -95,6 +103,14 @@ return virt_to_bus(ptr); } +static inline dma_addr_t +pci_map_page(struct pci_dev *hwdev, struct page *page, unsigned long offset, size_t size, int dir) +{ + void *vaddr = (void*) page_address(page); + return pci_map_single(hwdev, vaddr + offset, size, dir); +} + + /* Unmap a single streaming mode DMA translation. The dma_addr and size * must match what was provided for in a previous pci_map_single call. All * other usages are undefined. @@ -103,14 +119,26 @@ * whatever the device wrote there. */ static inline void -pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, + size_t size, int direction) { +#ifdef CONFIG_ARCH_IXP425 + extern void ixp425_unmap_single(dma_addr_t, size_t, int); + ixp425_unmap_single(dma_addr, size, direction); +#endif if (dev_is_sa1111(hwdev)) sa1111_unmap_single(dma_addr, size, direction); /* nothing to do */ } +static inline void +pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_addr, + size_t size, int direction) +{ + pci_unmap_single(hwdev, dma_addr, size, direction); +} + /* Whether pci_unmap_{single,page} is a nop depends upon the * configuration. */ @@ -165,8 +193,8 @@ if (!vaddr) vaddr = ((char *)page_address(sg->page)) + sg->offset; - consistent_sync(vaddr, sg->length, direction); - sg->dma_address = virt_to_bus(vaddr); + sg->dma_address = + pci_map_single(hwdev, vaddr, sg->length, direction); } return nents; @@ -179,11 +207,18 @@ static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + int i; + if (dev_is_sa1111(hwdev)) { sa1111_unmap_sg(sg, nents, direction); return; } + for (i = 0; i < nents; i++, sg++) { + pci_unmap_single(hwdev, sg->dma_address, sg->length, direction); + sg->dma_address = 0; + } + /* nothing to do */ } @@ -199,6 +234,12 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { +#ifdef CONFIG_ARCH_IXP425 + extern void ixp425_sync_single(dma_addr_t, size_t, int); + ixp425_sync_single(dma_handle, size, direction); + return; +#endif + if (dev_is_sa1111(hwdev)) { sa1111_dma_sync_single(dma_handle, size, direction); return; @@ -224,7 +265,7 @@ } for (i = 0; i < nelems; i++, sg++) - consistent_sync(sg->address, sg->length, direction); + pci_dma_sync_single(hwdev, sg->dma_address, sg->length, direction); } /* Return whether the given PCI device DMA address mask can diff -Nru a/include/asm-arm/proc-armv/pgtable.h b/include/asm-arm/proc-armv/pgtable.h --- a/include/asm-arm/proc-armv/pgtable.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/proc-armv/pgtable.h Thu Dec 4 16:24:25 2003 @@ -15,9 +15,6 @@ #ifndef __ASM_PROC_PGTABLE_H #define __ASM_PROC_PGTABLE_H -#include -#include - /* * entries per page directory level: they are two-level, so * we don't really have any PMD directory. @@ -26,27 +23,92 @@ #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 4096 -/**************** -* PMD functions * -****************/ - -/* PMD types (actually level 1 descriptor) */ -#define PMD_TYPE_MASK 0x0003 -#define PMD_TYPE_FAULT 0x0000 -#define PMD_TYPE_TABLE 0x0001 -#define PMD_TYPE_SECT 0x0002 -#define PMD_UPDATABLE 0x0010 -#define PMD_SECT_CACHEABLE 0x0008 -#define PMD_SECT_BUFFERABLE 0x0004 -#define PMD_SECT_AP_WRITE 0x0400 -#define PMD_SECT_AP_READ 0x0800 +/* + * Hardware page table definitions. + * + * + Level 1 descriptor (PMD) + * - common + */ +#define PMD_TYPE_MASK (3 << 0) +#define PMD_TYPE_FAULT (0 << 0) +#define PMD_TYPE_TABLE (1 << 0) +#define PMD_TYPE_SECT (2 << 0) +#define PMD_UPDATABLE (1 << 4) #define PMD_DOMAIN(x) ((x) << 5) +#define PMD_PROTECTION (1 << 9) /* v5 */ +/* + * - section + */ +#define PMD_SECT_BUFFERABLE (1 << 2) +#define PMD_SECT_CACHEABLE (1 << 3) +#define PMD_SECT_AP_WRITE (1 << 10) +#define PMD_SECT_AP_READ (1 << 11) +#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */ +/* + * - coarse table + */ + +/* + * + Level 2 descriptor (PTE) + * - common + */ +#define PTE_TYPE_MASK (3 << 0) +#define PTE_TYPE_FAULT (0 << 0) +#define PTE_TYPE_LARGE (1 << 0) +#define PTE_TYPE_SMALL (2 << 0) +#define PTE_TYPE_EXT (3 << 0) /* v5 */ +#define PTE_BUFFERABLE (1 << 2) +#define PTE_CACHEABLE (1 << 3) + +/* + * - extended small page/tiny page + */ +#define PTE_EXT_AP_UNO_SRO (0 << 4) +#define PTE_EXT_AP_UNO_SRW (1 << 4) +#define PTE_EXT_AP_URO_SRW (2 << 4) +#define PTE_EXT_AP_URW_SRW (3 << 4) +#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */ + +/* + * - small page + */ +#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) +#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) +#define PTE_SMALL_AP_URO_SRW (0xaa << 4) +#define PTE_SMALL_AP_URW_SRW (0xff << 4) +#define PTE_AP_READ PTE_SMALL_AP_URO_SRW +#define PTE_AP_WRITE PTE_SMALL_AP_UNO_SRW + +/* + * "Linux" PTE definitions. + * + * We keep two sets of PTEs - the hardware and the linux version. + * This allows greater flexibility in the way we map the Linux bits + * onto the hardware tables, and allows us to have YOUNG and DIRTY + * bits. + * + * The PTE table pointer refers to the hardware entries; the "Linux" + * entries are stored 1024 bytes below. + */ +#define L_PTE_PRESENT (1 << 0) +#define L_PTE_YOUNG (1 << 1) +#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ +#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ +#define L_PTE_USER (1 << 4) +#define L_PTE_WRITE (1 << 5) +#define L_PTE_EXEC (1 << 6) +#define L_PTE_DIRTY (1 << 7) + +#ifndef __ASSEMBLY__ + +#include +#include #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER)) #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL)) #define pmd_bad(pmd) (pmd_val(pmd) & 2) -#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) +#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp, pmd) static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { @@ -75,49 +137,8 @@ return __phys_to_virt(ptr); } -/**************** -* PTE functions * -****************/ - -/* PTE types (actually level 2 descriptor) */ -#define PTE_TYPE_MASK 0x0003 -#define PTE_TYPE_FAULT 0x0000 -#define PTE_TYPE_LARGE 0x0001 -#define PTE_TYPE_SMALL 0x0002 -#define PTE_AP_READ 0x0aa0 -#define PTE_AP_WRITE 0x0550 -#define PTE_CACHEABLE 0x0008 -#define PTE_BUFFERABLE 0x0004 - #define set_pte(ptep, pte) cpu_set_pte(ptep,pte) -/* We now keep two sets of ptes - the physical and the linux version. - * This gives us many advantages, and allows us greater flexibility. - * - * The Linux pte's contain: - * bit meaning - * 0 page present - * 1 young - * 2 bufferable - matches physical pte - * 3 cacheable - matches physical pte - * 4 user - * 5 write - * 6 execute - * 7 dirty - * 8-11 unused - * 12-31 virtual page address - * - * These are stored at the pte pointer; the physical PTE is at -1024bytes - */ -#define L_PTE_PRESENT (1 << 0) -#define L_PTE_YOUNG (1 << 1) -#define L_PTE_BUFFERABLE (1 << 2) -#define L_PTE_CACHEABLE (1 << 3) -#define L_PTE_USER (1 << 4) -#define L_PTE_WRITE (1 << 5) -#define L_PTE_EXEC (1 << 6) -#define L_PTE_DIRTY (1 << 7) - /* * The following macros handle the cache and bufferable bits... */ @@ -162,5 +183,7 @@ * Mark the prot value as uncacheable and unbufferable. */ #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) + +#endif /* __ASSEMBLY__ */ #endif /* __ASM_PROC_PGTABLE_H */ diff -Nru a/include/asm-arm/proc-armv/processor.h b/include/asm-arm/proc-armv/processor.h --- a/include/asm-arm/proc-armv/processor.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/proc-armv/processor.h Thu Dec 4 16:24:25 2003 @@ -23,6 +23,9 @@ #define KERNEL_STACK_SIZE PAGE_SIZE struct context_save_struct { +#ifdef CONFIG_CPU_XSCALE + long long acc0; +#endif unsigned long cpsr; unsigned long r4; unsigned long r5; @@ -35,7 +38,11 @@ unsigned long pc; }; +#ifdef CONFIG_CPU_XSCALE +#define INIT_CSS (struct context_save_struct){ 0, SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#else #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#endif #define EXTRA_THREAD_STRUCT \ unsigned int domain; diff -Nru a/include/asm-arm/proc-armv/uaccess.h b/include/asm-arm/proc-armv/uaccess.h --- a/include/asm-arm/proc-armv/uaccess.h Thu Dec 4 16:24:26 2003 +++ b/include/asm-arm/proc-armv/uaccess.h Thu Dec 4 16:24:26 2003 @@ -54,6 +54,7 @@ : "=r" (err) \ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) +#ifndef __ARMEB__ #define __put_user_asm_half(x,addr,err) \ ({ \ unsigned long __temp = (unsigned long)(x); \ @@ -61,6 +62,14 @@ __put_user_asm_byte(__temp, __ptr, err); \ __put_user_asm_byte(__temp >> 8, __ptr + 1, err); \ }) +#else +#define __put_user_asm_half(x,addr,err) \ +({ \ + unsigned long __temp = (unsigned long)(x); \ + __put_user_asm_byte(__temp >> 8, addr, err); \ + __put_user_asm_byte(__temp, (int)(addr) + 1, err); \ +}) +#endif #define __put_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ @@ -95,6 +104,7 @@ : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) +#ifndef __ARMEB__ #define __get_user_asm_half(x,addr,err) \ ({ \ unsigned long __b1, __b2, __ptr = (unsigned long)addr; \ @@ -102,7 +112,15 @@ __get_user_asm_byte(__b2, __ptr + 1, err); \ (x) = __b1 | (__b2 << 8); \ }) - +#else +#define __get_user_asm_half(x,addr,err) \ +({ \ + unsigned long __b1, __b2; \ + __get_user_asm_byte(__b1, addr, err); \ + __get_user_asm_byte(__b2, (int)(addr) + 1, err); \ + (x) = (__b1 << 8) | __b2; \ +}) +#endif #define __get_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ diff -Nru a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h --- a/include/asm-arm/proc-fns.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/proc-fns.h Thu Dec 4 16:24:25 2003 @@ -100,6 +100,14 @@ # define CPU_NAME sa1100 # endif # endif +# ifdef CONFIG_CPU_XSCALE +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME xscale +# endif +# endif #endif #ifndef MULTI_CPU diff -Nru a/include/asm-arm/stat.h b/include/asm-arm/stat.h --- a/include/asm-arm/stat.h Thu Dec 4 16:24:26 2003 +++ b/include/asm-arm/stat.h Thu Dec 4 16:24:26 2003 @@ -44,8 +44,14 @@ * in the hope that the kernel has stretched to using larger sizes. */ struct stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; +#if defined(__ARMEB__) + unsigned char __pad0b[6]; + unsigned short st_dev; +#else + unsigned short st_dev; + unsigned char __pad0b[6]; +#endif + unsigned char __pad0[4]; #define STAT64_HAS_BROKEN_ST_INO 1 unsigned long __st_ino; @@ -55,14 +61,25 @@ unsigned long st_uid; unsigned long st_gid; - unsigned short st_rdev; - unsigned char __pad3[10]; +#if defined(__ARMEB__) + unsigned char __pad3b[6]; + unsigned short st_rdev; +#else /* Must be little */ + unsigned short st_rdev; + unsigned char __pad3b[6]; +#endif + unsigned char __pad3[4]; long long st_size; unsigned long st_blksize; - unsigned long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __pad4; /* future possible st_blocks high bits */ +#if defined(__ARMEB__) + unsigned long __pad4; /* Future possible st_blocks hi bits */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ +#else /* Must be little */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* Future possible st_blocks hi bits */ +#endif unsigned long st_atime; unsigned long __pad5; diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h --- a/include/asm-arm/uaccess.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/uaccess.h Thu Dec 4 16:24:25 2003 @@ -86,7 +86,7 @@ __get_user_x(__r1, __p, __e, 1, "lr"); \ break; \ case 2: \ - __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + __get_user_x(__r1, __p, __e, 2, "ip", "lr"); \ break; \ case 4: \ __get_user_x(__r1, __p, __e, 4, "lr"); \ @@ -122,13 +122,13 @@ register int __e asm("r0"); \ switch (sizeof(*(p))) { \ case 1: \ - __put_user_x(__r1, __p, __e, 1, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 1, "ip", "lr"); \ break; \ case 2: \ - __put_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 2, "ip", "lr"); \ break; \ case 4: \ - __put_user_x(__r1, __p, __e, 4, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 4, "ip", "lr"); \ break; \ case 8: \ __put_user_x(__r1, __p, __e, 8, "ip", "lr"); \ diff -Nru a/include/asm-arm/unaligned.h b/include/asm-arm/unaligned.h --- a/include/asm-arm/unaligned.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/unaligned.h Thu Dec 4 16:24:25 2003 @@ -39,24 +39,30 @@ * out of long long >> 32, or the low word from long long << 32 */ -#define __get_unaligned_2(__p) \ +#define __get_unaligned_2_le(__p) \ (__p[0] | __p[1] << 8) -#define __get_unaligned_4(__p) \ +#define __get_unaligned_2_be(__p) \ + (__p[0] << 8 | __p[1]) + +#define __get_unaligned_4_le(__p) \ (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) -#define get_unaligned(ptr) \ +#define __get_unaligned_4_be(__p) \ + (__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3]) + +#define __get_unaligned_le(ptr) \ ({ \ __typeof__(*(ptr)) __v; \ __u8 *__p = (__u8 *)(ptr); \ switch (sizeof(*(ptr))) { \ case 1: __v = *(ptr); break; \ - case 2: __v = __get_unaligned_2(__p); break; \ - case 4: __v = __get_unaligned_4(__p); break; \ + case 2: __v = __get_unaligned_2_le(__p); break; \ + case 4: __v = __get_unaligned_4_le(__p); break; \ case 8: { \ unsigned int __v1, __v2; \ - __v2 = __get_unaligned_4((__p+4)); \ - __v1 = __get_unaligned_4(__p); \ + __v2 = __get_unaligned_4_le((__p+4)); \ + __v1 = __get_unaligned_4_le(__p); \ __v = ((unsigned long long)__v2 << 32 | __v1); \ } \ break; \ @@ -65,44 +71,105 @@ __v; \ }) +#define __get_unaligned_be(ptr) \ + ({ \ + __typeof__(*(ptr)) __v; \ + __u8 *__p = (__u8 *)(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __v = *(ptr); break; \ + case 2: __v = __get_unaligned_2_be(__p); break; \ + case 4: __v = __get_unaligned_4_be(__p); break; \ + case 8: { \ + unsigned int __v1, __v2; \ + __v2 = __get_unaligned_4_be(__p); \ + __v1 = __get_unaligned_4_be((__p+4)); \ + __v = ((unsigned long long)__v2 << 32 | __v1); \ + } \ + break; \ + default: __v = __bug_unaligned_x(__p); break; \ + } \ + __v; \ + }) -static inline void __put_unaligned_2(__u32 __v, register __u8 *__p) + +static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p) { *__p++ = __v; *__p++ = __v >> 8; } -static inline void __put_unaligned_4(__u32 __v, register __u8 *__p) +static inline void __put_unaligned_2_be(__u32 __v, register __u8 *__p) +{ + *__p++ = __v >> 8; + *__p++ = __v; +} + +static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p) +{ + __put_unaligned_2_le(__v >> 16, __p + 2); + __put_unaligned_2_le(__v, __p); +} + +static inline void __put_unaligned_4_be(__u32 __v, register __u8 *__p) { - __put_unaligned_2(__v >> 16, __p + 2); - __put_unaligned_2(__v, __p); + __put_unaligned_2_be(__v >> 16, __p); + __put_unaligned_2_be(__v, __p + 2); } -static inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p) +static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p) { /* * tradeoff: 8 bytes of stack for all unaligned puts (2 * instructions), or an extra register in the long long * case - go for the extra register. */ - __put_unaligned_4(__v >> 32, __p+4); - __put_unaligned_4(__v, __p); + __put_unaligned_4_le(__v >> 32, __p+4); + __put_unaligned_4_le(__v, __p); +} + +static inline void __put_unaligned_8_be(const unsigned long long __v, register __u8 *__p) +{ + /* + * tradeoff: 8 bytes of stack for all unaligned puts (2 + * instructions), or an extra register in the long long + * case - go for the extra register. + */ + __put_unaligned_4_be(__v >> 32, __p); + __put_unaligned_4_be(__v, __p+4); } /* * Try to store an unaligned value as efficiently as possible. */ -#define put_unaligned(val,ptr) \ +#define __put_unaligned_le(val,ptr) \ + ({ \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(ptr) = (val); \ + break; \ + case 2: __put_unaligned_2_le((val),(__u8 *)(ptr)); \ + break; \ + case 4: __put_unaligned_4_le((val),(__u8 *)(ptr)); \ + break; \ + case 8: __put_unaligned_8_le((val),(__u8 *)(ptr)); \ + break; \ + default: __bug_unaligned_x(ptr); \ + break; \ + } \ + (void) 0; \ + }) + +#define __put_unaligned_be(val,ptr) \ ({ \ switch (sizeof(*(ptr))) { \ case 1: \ *(ptr) = (val); \ break; \ - case 2: __put_unaligned_2((val),(__u8 *)(ptr)); \ + case 2: __put_unaligned_2_be((val),(__u8 *)(ptr)); \ break; \ - case 4: __put_unaligned_4((val),(__u8 *)(ptr)); \ + case 4: __put_unaligned_4_be((val),(__u8 *)(ptr)); \ break; \ - case 8: __put_unaligned_8((val),(__u8 *)(ptr)); \ + case 8: __put_unaligned_8_be((val),(__u8 *)(ptr)); \ break; \ default: __bug_unaligned_x(ptr); \ break; \ @@ -110,5 +177,15 @@ (void) 0; \ }) +/* + * Select endianness + */ +#ifndef __ARMEB__ +#define get_unaligned __get_unaligned_le +#define put_unaligned __put_unaligned_le +#else +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be +#endif #endif diff -Nru a/include/asm-arm/xor.h b/include/asm-arm/xor.h --- a/include/asm-arm/xor.h Thu Dec 4 16:24:25 2003 +++ b/include/asm-arm/xor.h Thu Dec 4 16:24:25 2003 @@ -132,6 +132,7 @@ .do_5 = xor_arm4regs_5, }; + #undef XOR_TRY_TEMPLATES #define XOR_TRY_TEMPLATES \ do { \ @@ -139,3 +140,25 @@ xor_speed(&xor_block_8regs); \ xor_speed(&xor_block_32regs); \ } while (0) + + +#ifdef CONFIG_IOP3XX_AAU + +#include + +static struct xor_block_template xor_block_iop3xx_aau = +{ + .name = "iop3xx_aau", + .do_2 = xor_iop3xxaau_2, + .do_3 = xor_iop3xxaau_3, + .do_4 = xor_iop3xxaau_4, + .do_5 = xor_iop3xxaau_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_iop3xx_aau); \ + } while (0) +#endif + diff -Nru a/include/asm-arm/xscale-lock.h b/include/asm-arm/xscale-lock.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/xscale-lock.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,76 @@ +/* + * xscale-lock.h + * + * Header file for XScale cache and TLB locking API + * See Documentation/arm/xscale/cache-lock.txt tlb-lock.txt for API docs + * + * Author: Deepak Saxena + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 SOFTWARE IS PROVIDED ``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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _XSCALE_LOCK_H_ +#define _XSCALE_LOCK_H_ + +#include + +struct cache_capabilities +{ + u32 flags; /* Flags defining capabilities */ + u32 cache_size; /* Cache size in K (1024 bytes) */ + u32 max_lock; /* Maximum lockable region in K */ +}; + +/* + * Flags + */ + +/* + * Bit 0: Cache lockability + * Bits 1-31: Reserved for future use + */ +#define CACHE_LOCKABLE 0x00000001 /* Cache can be locked */ + +/* + * Cache Types + */ +#define ICACHE 0x00 +#define DCACHE 0x01 + + +int cache_query(u8, struct cache_capabilities *); +int cache_lock(void *, u32, u8, const char *); +int cache_unlock(void *); +int cache_lock_init(void); + + +/* + * TLB Types + */ +#define ITLB 0x00 +#define DTLB 0x01 + +int xscale_tlb_lock(u8, u32); +int xscale_tlb_unlock(u8, u32); + +#endif // _XSCALE_LOCK_H_ diff -Nru a/include/asm-arm/xscale-pmu.h b/include/asm-arm/xscale-pmu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/xscale-pmu.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,86 @@ +/* + * pmu.h + * + * This file contains the low level constants needed to access the + * performance monitoring unit on Intel's XScale Microarchitecture + * processors. + * + * For details on how to use the perfmon unit from an application or + * from the kernel, see Documentation/arm/XScale/perfmon.txt + * + * Author: Deepak Saxena + * + * Copyright 2000-2001 MontaVista Software Inc. + * + * 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 SOFTWARE IS PROVIDED ``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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PMU_H_ +#define _PMU_H_ + +#include + +/* + * Different types of events that can be counted by the XScale PMU + */ + +#define EVT_ICACHE_MISS 0x00 +#define EVT_ICACHE_NO_DELIVER 0x01 +#define EVT_DATA_STALL 0x02 +#define EVT_ITLB_MISS 0x03 +#define EVT_DTLB_MISS 0x04 +#define EVT_BRANCH 0x05 +#define EVT_BRANCH_MISS 0x06 +#define EVT_INSTRUCTION 0x07 +#define EVT_DCACHE_FULL_STALL 0x08 +#define EVT_DCACHE_FULL_STALL_CONTIG 0x09 +#define EVT_DCACHE_ACCESS 0x0A +#define EVT_DCACHE_MISS 0x0B +#define EVT_DCACE_WRITE_BACK 0x0C +#define EVT_PC_CHANGED 0x0D +#define EVT_BCU_REQUEST 0x10 +#define EVT_BCU_FULL 0x11 +#define EVT_BCU_DRAIN 0x12 +#define EVT_BCU_ECC_NO_ELOG 0x14 +#define EVT_BCU_1_BIT_ERR 0x15 +#define EVT_RMW 0x16 + + +struct pmu_results +{ + u32 ccnt_of; + u32 ccnt; /* Clock Counter Register */ + u32 pmn0_of; + u32 pmn0; /* Performance Counter Register 0 */ + u32 pmn1_of; + u32 pmn1; /* Performance Counter Register 1 */ +}; + +extern struct pmu_results results; + +int pmu_claim(void); /* Claim PMU for usage */ +int pmu_start(u32, u32); /* Start PMU execution */ +int pmu_stop(struct pmu_results *); /* Stop perfmon unit */ +int pmu_release(int); /* Release PMU */ + +#endif _PMU_H_ + + diff -Nru a/include/linux/crc32.h b/include/linux/crc32.h --- a/include/linux/crc32.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/crc32.h Thu Dec 4 16:24:25 2003 @@ -46,4 +46,25 @@ return crc; } -#endif /* _LINUX_CRC32_H */ +#ifndef CRC32_H +#define CRC32_H + +/* $Id: crc32.h,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */ + +#include + +extern const uint32_t crc32_table[256]; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +static inline uint32_t +crc32(uint32_t val, const void *ss, int len) +{ + const unsigned char *s = ss; + while (--len >= 0) + val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + return val; +} + +#endif +#endif diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/fs.h Thu Dec 4 16:24:25 2003 @@ -1376,6 +1376,7 @@ extern void iput(struct inode *); extern void force_delete(struct inode *); extern struct inode * igrab(struct inode *); +extern struct inode * ilookup(struct super_block *, unsigned long); extern ino_t iunique(struct super_block *, ino_t); typedef int (*find_inode_t)(struct inode *, unsigned long, void *); diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h --- a/include/linux/i2c-id.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/i2c-id.h Thu Dec 4 16:24:25 2003 @@ -96,7 +96,7 @@ #define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ #define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ #define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ - +#define I2C_DRIVERID_M41ST85W 52 /* ST M41ST85W RTC */ #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ @@ -165,6 +165,7 @@ #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ +#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XScale IOP3XX On-chip I2C alg */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -199,6 +200,8 @@ #define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ #define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface */ #define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */ +#define I2C_HW_B_IXP2000 0x16 /* IXP2000-style adapter */ +#define I2C_HW_B_IXP425 0x17 /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x00 /* Parallel port interface */ @@ -217,6 +220,8 @@ /* --- PowerPC on-chip adapters */ #define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ +/* --- XScale IOP3xx on-chip adapters */ +#define I2C_HW_IOP321 0x00 /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 diff -Nru a/include/linux/jffs2.h b/include/linux/jffs2.h --- a/include/linux/jffs2.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/jffs2.h Thu Dec 4 16:24:25 2003 @@ -1,50 +1,30 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: jffs2.h,v 1.19 2001/10/09 13:20:23 dwmw2 Exp $ + * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $ * */ #ifndef __LINUX_JFFS2_H__ #define __LINUX_JFFS2_H__ -#include +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + #define JFFS2_SUPER_MAGIC 0x72b6 /* Values we may expect to find in the 'magic' field */ #define JFFS2_OLD_MAGIC_BITMASK 0x1984 #define JFFS2_MAGIC_BITMASK 0x1985 -#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */ +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000 @@ -78,16 +58,12 @@ #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) // Maybe later... //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) -/* Same as the non_ECC versions, but with extra space for real - * ECC instead of just the checksum. For use on NAND flash - */ -//#define JFFS2_NODETYPE_DIRENT_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5) -//#define JFFS2_NODETYPE_INODE_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 6) #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at mount time, don't wait for it to @@ -96,31 +72,79 @@ compression type */ +/* These can go once we've made sure we've caught all uses without + byteswapping */ + +typedef struct { + uint32_t v32; +} __attribute__((packed)) jint32_t; + +typedef struct { + uint32_t m; +} __attribute__((packed)) jmode_t; + +typedef struct { + uint16_t v16; +} __attribute__((packed)) jint16_t; + +#define JFFS2_NATIVE_ENDIAN + +/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from + whatever OS we're actually running on here too. */ + +#if defined(JFFS2_NATIVE_ENDIAN) +#define cpu_to_je16(x) ((jint16_t){x}) +#define cpu_to_je32(x) ((jint32_t){x}) +#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) +#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) +#elif defined(JFFS2_BIG_ENDIAN) +#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)}) +#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) +#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) + +#define je16_to_cpu(x) (be16_to_cpu(x.v16)) +#define je32_to_cpu(x) (be32_to_cpu(x.v32)) +#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) +#elif defined(JFFS2_LITTLE_ENDIAN) +#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)}) +#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) +#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) + +#define je16_to_cpu(x) (le16_to_cpu(x.v16)) +#define je32_to_cpu(x) (le32_to_cpu(x.v32)) +#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) +#else +#error wibble +#endif + struct jffs2_unknown_node { /* All start like this */ - __u16 magic; - __u16 nodetype; - __u32 totlen; /* So we can skip over nodes we don't grok */ - __u32 hdr_crc; + jint16_t magic; + jint16_t nodetype; + jint32_t totlen; /* So we can skip over nodes we don't grok */ + jint32_t hdr_crc; } __attribute__((packed)); struct jffs2_raw_dirent { - __u16 magic; - __u16 nodetype; /* == JFFS_NODETYPE_DIRENT */ - __u32 totlen; - __u32 hdr_crc; - __u32 pino; - __u32 version; - __u32 ino; /* == zero for unlink */ - __u32 mctime; - __u8 nsize; - __u8 type; - __u8 unused[2]; - __u32 node_crc; - __u32 name_crc; - __u8 name[0]; + jint16_t magic; + jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t pino; + jint32_t version; + jint32_t ino; /* == zero for unlink */ + jint32_t mctime; + uint8_t nsize; + uint8_t type; + uint8_t unused[2]; + jint32_t node_crc; + jint32_t name_crc; + uint8_t name[0]; } __attribute__((packed)); /* The JFFS2 raw inode structure: Used for storage on physical media. */ @@ -131,28 +155,28 @@ */ struct jffs2_raw_inode { - __u16 magic; /* A constant magic number. */ - __u16 nodetype; /* == JFFS_NODETYPE_INODE */ - __u32 totlen; /* Total length of this node (inc data, etc.) */ - __u32 hdr_crc; - __u32 ino; /* Inode number. */ - __u32 version; /* Version number. */ - __u32 mode; /* The file's type or mode. */ - __u16 uid; /* The file's owner. */ - __u16 gid; /* The file's group. */ - __u32 isize; /* Total resultant size of this inode (used for truncations) */ - __u32 atime; /* Last access time. */ - __u32 mtime; /* Last modification time. */ - __u32 ctime; /* Change time. */ - __u32 offset; /* Where to begin to write. */ - __u32 csize; /* (Compressed) data size */ - __u32 dsize; /* Size of the node's data. (after decompression) */ - __u8 compr; /* Compression algorithm used */ - __u8 usercompr; /* Compression algorithm requested by the user */ - __u16 flags; /* See JFFS2_INO_FLAG_* */ - __u32 data_crc; /* CRC for the (compressed) data. */ - __u32 node_crc; /* CRC for the raw inode (excluding data) */ -// __u8 data[dsize]; + jint16_t magic; /* A constant magic number. */ + jint16_t nodetype; /* == JFFS_NODETYPE_INODE */ + jint32_t totlen; /* Total length of this node (inc data, etc.) */ + jint32_t hdr_crc; + jint32_t ino; /* Inode number. */ + jint32_t version; /* Version number. */ + jmode_t mode; /* The file's type or mode. */ + jint16_t uid; /* The file's owner. */ + jint16_t gid; /* The file's group. */ + jint32_t isize; /* Total resultant size of this inode (used for truncations) */ + jint32_t atime; /* Last access time. */ + jint32_t mtime; /* Last modification time. */ + jint32_t ctime; /* Change time. */ + jint32_t offset; /* Where to begin to write. */ + jint32_t csize; /* (Compressed) data size */ + jint32_t dsize; /* Size of the node's data. (after decompression) */ + uint8_t compr; /* Compression algorithm used */ + uint8_t usercompr; /* Compression algorithm requested by the user */ + jint16_t flags; /* See JFFS2_INO_FLAG_* */ + jint32_t data_crc; /* CRC for the (compressed) data. */ + jint32_t node_crc; /* CRC for the raw inode (excluding data) */ + uint8_t data[0]; } __attribute__((packed)); union jffs2_node_union { diff -Nru a/include/linux/jffs2_fs_i.h b/include/linux/jffs2_fs_i.h --- a/include/linux/jffs2_fs_i.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/jffs2_fs_i.h Thu Dec 4 16:24:25 2003 @@ -1,22 +1,12 @@ -/* $Id: jffs2_fs_i.h,v 1.8 2001/04/18 13:05:28 dwmw2 Exp $ */ +/* $Id: jffs2_fs_i.h,v 1.16 2003/01/09 14:03:21 dwmw2 Exp $ */ #ifndef _JFFS2_FS_I #define _JFFS2_FS_I -/* Include the pipe_inode_info at the beginning so that we can still - use the storage space in the inode when we have a pipe inode. - This sucks. -*/ - -#undef THISSUCKS /* Only for 2.2 */ -#ifdef THISSUCKS -#include -#endif +#include +#include struct jffs2_inode_info { -#ifdef THISSUCKS - struct pipe_inode_info pipecrap; -#endif /* We need an internal semaphore similar to inode->i_sem. Unfortunately, we can't used the existing one, because either the GC would deadlock, or we'd have to release it @@ -26,10 +16,10 @@ struct semaphore sem; /* The highest (datanode) version number used for this ino */ - __u32 highest_version; + uint32_t highest_version; /* List of data fragments which make up the file */ - struct jffs2_node_frag *fraglist; + struct rb_root fragtree; /* There may be one datanode which isn't referenced by any of the above fragments, if it contains a metadata update but no actual @@ -44,19 +34,13 @@ /* Some stuff we just have to keep in-core at all times, for each inode. */ struct jffs2_inode_cache *inocache; - /* Keep a pointer to the last physical node in the list. We don't - use the doubly-linked lists because we don't want to increase - the memory usage that much. This is simpler */ - // struct jffs2_raw_node_ref *lastnode; - __u16 flags; - __u8 usercompr; -}; - -#ifdef JFFS2_OUT_OF_KERNEL -#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u) -#else -#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i) + uint16_t flags; + uint8_t usercompr; +#if !defined (__ECOS) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) + struct inode vfs_inode; #endif +#endif +}; #endif /* _JFFS2_FS_I */ - diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h --- a/include/linux/jffs2_fs_sb.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/jffs2_fs_sb.h Thu Dec 4 16:24:25 2003 @@ -1,19 +1,22 @@ -/* $Id: jffs2_fs_sb.h,v 1.16.2.1 2002/02/23 14:13:34 dwmw2 Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.45 2003/10/08 11:46:27 dwmw2 Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB #include #include +#include #include #include +#include +#include #include -#define INOCACHE_HASHSIZE 1 - #define JFFS2_SB_FLAG_RO 1 #define JFFS2_SB_FLAG_MOUNTING 2 +struct jffs2_inodirty; + /* A struct for the overall file system control. Pointers to jffs2_sb_info structs are named `c' in the source code. Nee jffs_control @@ -21,36 +24,46 @@ struct jffs2_sb_info { struct mtd_info *mtd; - __u32 highest_ino; + uint32_t highest_ino; + uint32_t checked_ino; + unsigned int flags; - spinlock_t nodelist_lock; - // pid_t thread_pid; /* GC thread's PID */ struct task_struct *gc_task; /* GC task struct */ struct semaphore gc_thread_start; /* GC thread start mutex */ struct completion gc_thread_exit; /* GC thread exit completion port */ - // __u32 gc_minfree_threshold; /* GC trigger thresholds */ - // __u32 gc_maxdirty_threshold; struct semaphore alloc_sem; /* Used to protect all the following fields, and also to protect against out-of-order writing of nodes. And GC. */ - __u32 flash_size; - __u32 used_size; - __u32 dirty_size; - __u32 free_size; - __u32 erasing_size; - __u32 bad_size; - __u32 sector_size; - // __u32 min_free_size; - // __u32 max_chunk_size; + uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER + (i.e. zero for OOB CLEANMARKER */ + + uint32_t flash_size; + uint32_t used_size; + uint32_t dirty_size; + uint32_t wasted_size; + uint32_t free_size; + uint32_t erasing_size; + uint32_t bad_size; + uint32_t sector_size; + uint32_t unchecked_size; + + uint32_t nr_free_blocks; + uint32_t nr_erasing_blocks; + + /* Number of free blocks there must be before we... */ + uint8_t resv_blocks_write; /* ... allow a normal filesystem write */ + uint8_t resv_blocks_deletion; /* ... allow a normal filesystem deletion */ + uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ + uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ + uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ - __u32 nr_free_blocks; - __u32 nr_erasing_blocks; + uint32_t nospc_dirty_size; - __u32 nr_blocks; + uint32_t nr_blocks; struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks * from the offset (blocks[ofs / sector_size]) */ struct jffs2_eraseblock *nextblock; /* The block we're currently filling */ @@ -58,9 +71,12 @@ struct jffs2_eraseblock *gcblock; /* The block we're currently garbage-collecting */ struct list_head clean_list; /* Blocks 100% full of clean data */ + struct list_head very_dirty_list; /* Blocks with lots of dirty space */ struct list_head dirty_list; /* Blocks with some dirty space */ + struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ + struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ struct list_head erasing_list; /* Blocks which are currently erasing */ - struct list_head erase_pending_list; /* Blocks which need erasing */ + struct list_head erase_pending_list; /* Blocks which need erasing now */ struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ struct list_head free_list; /* Blocks which are free and ready to be used */ struct list_head bad_list; /* Bad blocks. */ @@ -69,16 +85,33 @@ spinlock_t erase_completion_lock; /* Protect free_list and erasing_list against erase completion handler */ wait_queue_head_t erase_wait; /* For waiting for erases to complete */ - struct jffs2_inode_cache *inocache_list[INOCACHE_HASHSIZE]; - spinlock_t inocache_lock; -}; -#ifdef JFFS2_OUT_OF_KERNEL -#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u) -#else -#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb) + wait_queue_head_t inocache_wq; + struct jffs2_inode_cache **inocache_list; + spinlock_t inocache_lock; + + /* Sem to allow jffs2_garbage_collect_deletion_dirent to + drop the erase_completion_lock while it's holding a pointer + to an obsoleted node. I don't like this. Alternatives welcomed. */ + struct semaphore erase_free_sem; + +#ifdef CONFIG_JFFS2_FS_NAND + /* Write-behind buffer for NAND flash */ + unsigned char *wbuf; + uint32_t wbuf_ofs; + uint32_t wbuf_len; + uint32_t wbuf_pagesize; + struct jffs2_inodirty *wbuf_inodes; + + /* Information about out-of-band area usage... */ + struct nand_oobinfo *oobinfo; + uint32_t badblock_pos; + uint32_t fsdata_pos; + uint32_t fsdata_len; #endif -#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) + /* OS-private pointer for getting back to master superblock info */ + void *os_priv; +}; #endif /* _JFFS2_FB_SB */ diff -Nru a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h --- a/include/linux/mtd/cfi.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/cfi.h Thu Dec 4 16:24:25 2003 @@ -1,13 +1,14 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.32 2002/09/05 05:15:32 acurtis Exp $ + * $Id: cfi.h,v 1.38 2003/11/08 00:51:21 dsaxena Exp $ */ #ifndef __MTD_CFI_H__ #define __MTD_CFI_H__ #include +#include #include #include #include @@ -260,7 +261,8 @@ __u8 pri[3]; __u8 MajorVersion; __u8 MinorVersion; - __u32 FeatureSupport; + __u32 FeatureSupport; /* if bit 31 is set then an additional __u32 feature + block follows - FIXME - not currently supported */ __u8 SuspendCmdSupport; __u16 BlkStatusRegMask; __u8 VccOptimal; @@ -271,6 +273,25 @@ __u8 UserProtRegSize; } __attribute__((packed)); +/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ + +struct cfi_pri_amdstd { + __u8 pri[3]; + __u8 MajorVersion; + __u8 MinorVersion; + __u8 SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ + __u8 EraseSuspend; + __u8 BlkProt; + __u8 TmpBlkUnprotect; + __u8 BlkProtUnprot; + __u8 SimultaneousOps; + __u8 BurstMode; + __u8 PageMode; + __u8 VppMin; + __u8 VppMax; + __u8 TopBottom; +} __attribute__((packed)); + struct cfi_pri_query { __u8 NumFields; __u32 ProtField[1]; /* Not host ordered */ @@ -314,8 +335,6 @@ struct flchip chips[0]; /* per-chip data structure for each chip */ }; -#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */ - /* * Returns the command address according to the given geometry. */ @@ -387,13 +406,13 @@ static inline cfi_word cfi_read(struct map_info *map, __u32 addr) { if (cfi_buswidth_is_1()) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (cfi_buswidth_is_2()) { - return map->read16(map, addr); + return map_read16(map, addr); } else if (cfi_buswidth_is_4()) { - return map->read32(map, addr); + return map_read32(map, addr); } else if (cfi_buswidth_is_8()) { - return map->read64(map, addr); + return map_read64(map, addr); } else { return 0; } @@ -406,13 +425,13 @@ static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr) { if (cfi_buswidth_is_1()) { - map->write8(map, val, addr); + map_write8(map, val, addr); } else if (cfi_buswidth_is_2()) { - map->write16(map, val, addr); + map_write16(map, val, addr); } else if (cfi_buswidth_is_4()) { - map->write32(map, val, addr); + map_write32(map, val, addr); } else if (cfi_buswidth_is_8()) { - map->write64(map, val, addr); + map_write64(map, val, addr); } } @@ -443,13 +462,13 @@ static inline __u8 cfi_read_query(struct map_info *map, __u32 addr) { if (cfi_buswidth_is_1()) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (cfi_buswidth_is_2()) { - return cfi16_to_cpu(map->read16(map, addr)); + return cfi16_to_cpu(map_read16(map, addr)); } else if (cfi_buswidth_is_4()) { - return cfi32_to_cpu(map->read32(map, addr)); + return cfi32_to_cpu(map_read32(map, addr)); } else if (cfi_buswidth_is_8()) { - return cfi64_to_cpu(map->read64(map, addr)); + return cfi64_to_cpu(map_read64(map, addr)); } else { return 0; } @@ -479,5 +498,19 @@ spin_unlock_bh(mutex); } +struct cfi_extquery *cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, + const char* name); + +struct cfi_fixup { + __u16 mfr; + __u16 id; + void (*fixup)(struct map_info *map, void* param); + void* param; +}; + +#define CFI_MFR_ANY 0xffff +#define CFI_ID_ANY 0xffff + +void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups); #endif /* __MTD_CFI_H__ */ diff -Nru a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h --- a/include/linux/mtd/compatmac.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/compatmac.h Thu Dec 4 16:24:25 2003 @@ -1,571 +1,150 @@ - /* - * mtd/include/compatmac.h - * - * $Id: compatmac.h,v 1.45 2003/01/24 15:50:57 dwmw2 Exp $ + * $Id: compatmac.h,v 1.63 2003/11/14 19:50:04 thayne Exp $ * * Extensions and omissions from the normal 'linux/compatmac.h' * files. hopefully this will end up empty as the 'real' one * becomes fully-featured. */ - -/* First, include the parts which the kernel is good enough to provide - * to us - */ - #ifndef __LINUX_MTD_COMPATMAC_H__ #define __LINUX_MTD_COMPATMAC_H__ -#include -#include -#ifndef LINUX_VERSION_CODE #include -#endif - -#ifndef VERSION_CODE -# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) ) -#endif -#ifndef KERNEL_VERSION -# define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c) -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0) -# error "This kernel is too old: not supported by this file" -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) -#include /* used later in this header */ - -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -typedef struct wait_queue * wait_queue_head_t; - -#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL} -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL -#define init_waitqueue_head init_waitqueue -#define DECLARE_MUTEX(x) struct semaphore x = MUTEX -#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED - -/* from sysdep-2.1.h */ -# include -# define access_ok(t,a,sz) (verify_area((t),(a),(sz)) ? 0 : 1) -# define verify_area_20 verify_area -# define copy_to_user(t,f,n) (memcpy_tofs(t,f,n), 0) -# define __copy_to_user(t,f,n) copy_to_user((t),(f),(n)) -# define copy_to_user_ret(t,f,n,r) copy_to_user((t),(f),(n)) -# define copy_from_user(t,f,n) (memcpy_fromfs((t),(f),(n)), 0) -# define __copy_from_user(t,f,n) copy_from_user((t),(f),(n)) -# define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n)) -//xxx # define PUT_USER(val,add) (put_user((val),(add)), 0) -# define Put_user(val,add) (put_user((val),(add)), 0) -# define __PUT_USER(val,add) PUT_USER((val),(add)) -# define PUT_USER_RET(val,add,ret) PUT_USER((val),(add)) -# define GET_USER(dest,add) ((dest)=get_user((add)), 0) -# define __GET_USER(dest,add) GET_USER((dest),(add)) -# define GET_USER_RET(dest,add,ret) GET_USER((dest),(add)) - -#define ioremap(offset,size) vremap(offset,size) -#define iounmap(adr) /* */ - -#define EXPORT_SYMBOL(s) /* */ -#define EXPORT_SYMBOL_NOVERS(s) /* */ - -/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */ - -#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10) - -# include -# ifdef __LITTLE_ENDIAN -# define cpu_to_le16(x) (x) -# define cpu_to_le32(x) (x) -# define cpu_to_be16(x) htons((x)) -# define cpu_to_be32(x) htonl((x)) -# else -# define cpu_to_be16(x) (x) -# define cpu_to_be32(x) (x) - extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);} - extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) | - ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));} -# endif - -# define le16_to_cpu(x) cpu_to_le16(x) -# define le32_to_cpu(x) cpu_to_le32(x) -# define be16_to_cpu(x) cpu_to_be16(x) -# define be32_to_cpu(x) cpu_to_be32(x) - -#endif - -#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43) -# define cpu_to_le16p(addr) (cpu_to_le16(*(addr))) -# define cpu_to_le32p(addr) (cpu_to_le32(*(addr))) -# define cpu_to_be16p(addr) (cpu_to_be16(*(addr))) -# define cpu_to_be32p(addr) (cpu_to_be32(*(addr))) - - extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);} - extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);} - extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);} - extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);} - -# define le16_to_cpup(x) cpu_to_le16p(x) -# define le32_to_cpup(x) cpu_to_le32p(x) -# define be16_to_cpup(x) cpu_to_be16p(x) -# define be32_to_cpup(x) cpu_to_be32p(x) - -# define le16_to_cpus(x) cpu_to_le16s(x) -# define le32_to_cpus(x) cpu_to_le32s(x) -# define be16_to_cpus(x) cpu_to_be16s(x) -# define be32_to_cpus(x) cpu_to_be32s(x) -#endif - -// from 2.2, linux/types.h -#ifndef __BIT_TYPES_DEFINED__ -#define __BIT_TYPES_DEFINED__ - -typedef __u8 u_int8_t; -typedef __s8 int8_t; -typedef __u16 u_int16_t; -typedef __s16 int16_t; -typedef __u32 u_int32_t; -typedef __s32 int32_t; - -#endif /* !(__BIT_TYPES_DEFINED__) */ - -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { } -#else - typedef struct { int gcc_is_buggy; } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } -#endif - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() - -#define spin_lock_irqsave(lock, flags) \ - do { save_flags(flags); cli(); } while (0) -#define spin_unlock_irqrestore(lock, flags) \ - restore_flags(flags) - -// Doesn't work when tqueue.h is included. -// #define queue_task queue_task_irq_off -#define tty_flip_buffer_push(tty) queue_task_irq_off(&tty->flip.tqueue, &tq_timer) -#define signal_pending(current) (current->signal & ~current->blocked) -#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) -#define time_after(t1,t2) (((long)t1-t2) > 0) - -#else - #include -#endif // LINUX_VERSION_CODE < 0x020100 - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include -#endif - -/* Modularization issues */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18) -# define __USE_OLD_SYMTAB__ -# define EXPORT_NO_SYMBOLS register_symtab(NULL); -# define REGISTER_SYMTAB(tab) register_symtab(tab) -#else -# define REGISTER_SYMTAB(tab) /* nothing */ -#endif - -#ifdef __USE_OLD_SYMTAB__ -# define __MODULE_STRING(s) /* nothing */ -# define MODULE_PARM(v,t) /* nothing */ -# define MODULE_PARM_DESC(v,t) /* nothing */ -# define MODULE_AUTHOR(n) /* nothing */ -# define MODULE_DESCRIPTION(d) /* nothing */ -# define MODULE_SUPPORTED_DEVICE(n) /* nothing */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +#error "This kernel is too old: not supported by this file" #endif -/* - * "select" changed in 2.1.23. The implementation is twin, but this - * header is new - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22) -# include -#else -# define __USE_OLD_SELECT__ -#endif + /* O(1) scheduler stuff. */ -/* Other change in the fops are solved using pseudo-types */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -# define lseek_t long long -# define lseek_off_t long long -#else -# define lseek_t int -# define lseek_off_t off_t -#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__) +#include +static inline void __recalc_sigpending(void) +{ + recalc_sigpending(current); +} +#undef recalc_sigpending +#define recalc_sigpending() __recalc_sigpending () -/* changed the prototype of read/write */ +#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__) -# define count_t unsigned long -# define read_write_t long -#else -# define count_t int -# define read_write_t int #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31) -# define release_t void -# define release_return(x) return -#else -# define release_t int -# define release_return(x) return (x) -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#define __exit -#endif -#if LINUX_VERSION_CODE < 0x20200 -#define __init -#else -#include -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) -#define init_MUTEX(x) do {*(x) = MUTEX;} while (0) -#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0) -#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define RQFUNC_ARG void -#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) -#else -#define RQFUNC_ARG request_queue_t *q +#ifndef yield +#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32) -#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0) -#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn) -#define blk_init_queue(q, rq) do {q = rq;} while(0) +#ifndef minor +#define major(d) (MAJOR(to_kdev_t(d))) +#define minor(d) (MINOR(to_kdev_t(d))) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) -#ifdef CONFIG_MODULES -#define __MOD_INC_USE_COUNT(mod) \ - (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE) -#define __MOD_DEC_USE_COUNT(mod) \ - (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED) -#else -#define __MOD_INC_USE_COUNT(mod) -#define __MOD_DEC_USE_COUNT(mod) -#endif +#ifndef mk_kdev +#define mk_kdev(ma,mi) MKDEV(ma,mi) +#define kdev_t_to_nr(x) (x) #endif +#define need_resched() (current->need_resched) +#define cond_resched() do { if need_resched() { yield(); } } while(0) -#ifndef HAVE_INTER_MODULE -static inline void *inter_module_get(char *x) {return NULL;} -static inline void *inter_module_get_request(char *x, char *y) {return NULL;} -static inline void inter_module_put(const char *x) {} -static inline void inter_module_register(const char *x, struct module *y, const void *z) {} -static inline void inter_module_unregister(const char *x) {} +#endif /* < 2.4.20 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) +#define iminor(i) minor((i)->i_rdev) +#define imajor(i) major((i)->i_rdev) +#define old_encode_dev(d) ( (major(d)<<8) | minor(d) ) +#define old_decode_dev(rdev) (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff))) +#define old_valid_dev(d) (1) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL -#define init_waitqueue_head init_waitqueue +#include +#ifdef __rh_config_h__ +#define sigmask_lock sighand->siglock +#define sig sighand #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - -static inline int try_inc_mod_count(struct module *mod) +static inline void __daemonize_modvers(void) { -#ifdef CONFIG_MODULES - if (mod) - __MOD_INC_USE_COUNT(mod); -#endif - return 1; -} -#endif - - -/* Yes, I'm aware that it's a fairly ugly hack. - Until the __constant_* macros appear in Linus' own kernels, this is - the way it has to be done. - DW 19/1/00 - */ - -#include - -#ifndef __constant_cpu_to_le16 - -#ifdef __BIG_ENDIAN -#define __constant_cpu_to_le64(x) ___swab64((x)) -#define __constant_le64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_le32(x) ___swab32((x)) -#define __constant_le32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_le16(x) ___swab16((x)) -#define __constant_le16_to_cpu(x) ___swab16((x)) -#define __constant_cpu_to_be64(x) ((__u64)(x)) -#define __constant_be64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_be32(x) ((__u32)(x)) -#define __constant_be32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_be16(x) ((__u16)(x)) -#define __constant_be16_to_cpu(x) ((__u16)(x)) -#else -#ifdef __LITTLE_ENDIAN -#define __constant_cpu_to_le64(x) ((__u64)(x)) -#define __constant_le64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_le32(x) ((__u32)(x)) -#define __constant_le32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_le16(x) ((__u16)(x)) -#define __constant_le16_to_cpu(x) ((__u16)(x)) -#define __constant_cpu_to_be64(x) ___swab64((x)) -#define __constant_be64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_be32(x) ___swab32((x)) -#define __constant_be32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_be16(x) ___swab16((x)) -#define __constant_be16_to_cpu(x) ___swab16((x)) -#else -#error No (recognised) endianness defined (unless it,s PDP) -#endif /* __LITTLE_ENDIAN */ -#endif /* __BIG_ENDIAN */ - -#endif /* ifndef __constant_cpu_to_le16 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - #define mod_init_t int __init - #define mod_exit_t void -#else - #define mod_init_t static int __init - #define mod_exit_t static void __exit -#endif - -#ifndef THIS_MODULE -#ifdef MODULE -#define THIS_MODULE (&__this_module) -#else -#define THIS_MODULE (NULL) -#endif -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#include -#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0) -#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0) -#else -#include -#include -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) -#define set_current_state(state_value) \ - do { current->state = (state_value); } while (0) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) -static inline int invalidate_device(kdev_t dev, int do_sync) { - - if (do_sync) - fsync_dev(dev); - - invalidate_buffers(dev); - return 0; -} -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) -static inline int invalidate_device(kdev_t dev, int do_sync) { - struct super_block *sb = get_super(dev); - int res = 0; - - if (do_sync) - fsync_dev(dev); - - if (sb) - res = invalidate_inodes(sb); - - invalidate_buffers(dev); - return res; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) -#undef min -#undef max -#undef min_t -#undef max_t -/* - * min()/max() macros that also do - * strict type-checking.. See the - * "unnecessary" pointer comparison. - */ -#define min(x,y) ({ \ - const typeof(x) _x = (x); \ - const typeof(y) _y = (y); \ - (void) (&_x == &_y); \ - _x < _y ? _x : _y; }) - -#define max(x,y) ({ \ - const typeof(x) _x = (x); \ - const typeof(y) _y = (y); \ - (void) (&_x == &_y); \ - _x > _y ? _x : _y; }) - -/* - * ..and if you can't take the strict - * types, you can specify one yourself. - * - * Or not use min/max at all, of course. - */ -#define min_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) -#define max_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7) -struct completion { - struct semaphore s; -}; - -#define complete(c) up(&(c)->s) -#define wait_for_completion(c) down(&(c)->s) -#define init_completion(c) init_MUTEX_LOCKED(&(c)->s); + daemonize(); -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) -/* This came later */ -#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0) -#endif + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); +} +#undef daemonize +#define daemonize(fmt, ...) do { \ + snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__); \ + __daemonize_modvers(); \ + } while(0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__)) +static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) +{ + unsigned long flags; + unsigned long ret; -#include + spin_lock_irqsave(¤t->sigmask_lock, flags); + ret = dequeue_signal(mask, info); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); -static inline void add_gendisk(struct gendisk *gp) -{ - gp->next = gendisk_head; - gendisk_head = gp; + return ret; } -static inline void del_gendisk(struct gendisk *gp) +static inline int allow_signal(int sig) { - struct gendisk *gd, **gdp; + if (sig < 1 || sig > _NSIG) + return -EINVAL; - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == gp) { - gd = *gdp; *gdp = gd->next; - break; - } + spin_lock_irq(¤t->sigmask_lock); + sigdelset(¤t->blocked, sig); + recalc_sigpending(); + /* Make sure the kernel neither eats it now converts to SIGKILL */ + current->sig->action[sig-1].sa.sa_handler = (void *)2; + spin_unlock_irq(¤t->sigmask_lock); + return 0; } -#endif +static inline int disallow_signal(int sig) +{ + if (sig < 1 || sig > _NSIG) + return -EINVAL; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE) + spin_lock_irq(¤t->sigmask_lock); + sigaddset(¤t->blocked, sig); + recalc_sigpending(); -#define module_init(func) \ -mod_init_t init_module(void) { \ - return func(); \ + current->sig->action[sig-1].sa.sa_handler = SIG_DFL; + spin_unlock_irq(¤t->sigmask_lock); + return 0; } -#define module_exit(func) \ -mod_exit_t cleanup_module(void) { \ - return func(); \ -} -#endif +#undef sighand +#undef sigmask_lock -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \ - (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__)) -#define MODULE_LICENSE(x) /* */ +#define PF_FREEZE 0 +#define refrigerator(x) do { ; } while(0) #endif -/* Removed for 2.4.21 kernel. This really should have been renamed - when it was changed -- this is a PITA */ -#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) -#include -static inline void __recalc_sigpending(void) -{ - recalc_sigpending(current); -} -#undef recalc_sigpending -#define recalc_sigpending() __recalc_sigpending () -#endif + /* Module bits */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) -#define parent_ino(d) ((d)->d_parent->d_inode->i_ino) -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3) -#define need_resched() (current->need_resched) -#define cond_resched() do { if need_resched() schedule(); } while(0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) +#define try_module_get(m) try_inc_mod_count(m) +#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0) +#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0) +#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) -#ifndef yield -#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0) -#endif -#ifndef minor -#define major(d) (MAJOR(to_kdev_t(d))) -#define minor(d) (MINOR(to_kdev_t(d))) -#endif -#ifndef mk_kdev -#define mk_kdev(ma,mi) MKDEV(ma,mi) -#define kdev_t_to_nr(x) (x) -#endif -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - /* Is this right? */ -#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL) -#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) -#define rq_data_dir(x) ((x)->cmd) -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + /* Random filesystem stuff, only for JFFS2 really */ -#define IS_REQ_CMD(req) (1) - -#define QUEUE_LOCK(q) (&io_request_lock) - -#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req)) - -#else /* > 2.5.0 */ - -#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD) - -#define QUEUE_LOCK(q) ((q)->queue_lock) - -#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock)) - -#endif - -/* Removed cos it broke stuff. Where is this required anyway? - * #ifndef QUEUE_EMPTY - * #define QUEUE_EMPTY (!CURRENT) - * #endif - */ -#if LINUX_VERSION_CODE < 0x20300 -#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) -#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si) -#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) -#else -#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE)) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) -#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT -#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define BLK_INC_USE_COUNT do {} while(0) -#define BLK_DEC_USE_COUNT do {} while(0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) +#define parent_ino(d) ((d)->d_parent->d_inode->i_ino) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12) @@ -578,6 +157,33 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53) #define generic_file_readonly_mmap generic_file_mmap +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70) + +#include +#include + +static inline char *strlcpy(char *dest, const char *src, int len) +{ + dest[len-1] = 0; + return strncpy(dest, src, len-1); +} + +static inline int do_old_request_module(const char *mod) +{ + return request_module(mod); +} +#undef request_module +#define request_module(fmt, ...) \ + ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); }) + +#endif /* 2.5.70 */ + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) #endif #endif /* __LINUX_MTD_COMPATMAC_H__ */ diff -Nru a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h --- a/include/linux/mtd/doc2000.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/doc2000.h Thu Dec 4 16:24:25 2003 @@ -1,13 +1,21 @@ - -/* Linux driver for Disk-On-Chip 2000 */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse */ -/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */ +/* + * Linux driver for Disk-On-Chip devices + * + * Copyright (C) 1999 Machine Vision Holdings, Inc. + * Copyright (C) 2001-2003 David Woodhouse + * Copyright (C) 2002-2003 Greg Ungerer + * Copyright (C) 2002-2003 SnapGear Inc + * + * $Id: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $ + * + * Released under GPL + */ #ifndef __MTD_DOC2000_H__ #define __MTD_DOC2000_H__ #include +#include #define DoC_Sig1 0 #define DoC_Sig2 1 @@ -38,18 +46,47 @@ #define DoC_Mil_CDSN_IO 0x0800 #define DoC_2k_CDSN_IO 0x1800 +#define DoC_Mplus_NOP 0x1002 +#define DoC_Mplus_AliasResolution 0x1004 +#define DoC_Mplus_DOCControl 0x1006 +#define DoC_Mplus_AccessStatus 0x1008 +#define DoC_Mplus_DeviceSelect 0x1008 +#define DoC_Mplus_Configuration 0x100a +#define DoC_Mplus_OutputControl 0x100c +#define DoC_Mplus_FlashControl 0x1020 +#define DoC_Mplus_FlashSelect 0x1022 +#define DoC_Mplus_FlashCmd 0x1024 +#define DoC_Mplus_FlashAddress 0x1026 +#define DoC_Mplus_FlashData0 0x1028 +#define DoC_Mplus_FlashData1 0x1029 +#define DoC_Mplus_ReadPipeInit 0x102a +#define DoC_Mplus_LastDataRead 0x102c +#define DoC_Mplus_LastDataRead1 0x102d +#define DoC_Mplus_WritePipeTerm 0x102e +#define DoC_Mplus_ECCSyndrome0 0x1040 +#define DoC_Mplus_ECCSyndrome1 0x1041 +#define DoC_Mplus_ECCSyndrome2 0x1042 +#define DoC_Mplus_ECCSyndrome3 0x1043 +#define DoC_Mplus_ECCSyndrome4 0x1044 +#define DoC_Mplus_ECCSyndrome5 0x1045 +#define DoC_Mplus_ECCConf 0x1046 +#define DoC_Mplus_Toggle 0x1046 +#define DoC_Mplus_DownloadStatus 0x1074 +#define DoC_Mplus_CtrlConfirm 0x1076 +#define DoC_Mplus_Power 0x1fff + /* How to access the device? * On ARM, it'll be mmap'd directly with 32-bit wide accesses. * On PPC, it's mmap'd and 16-bit wide. * Others use readb/writeb */ #if defined(__arm__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2)))) -#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) +#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) +#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x8000 #elif defined(__ppc__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1)))) -#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) +#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) +#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x4000 #else #define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg)) @@ -71,13 +108,21 @@ #define DOC_MODE_RESERVED1 2 #define DOC_MODE_RESERVED2 3 -#define DOC_MODE_MDWREN 4 #define DOC_MODE_CLR_ERR 0x80 +#define DOC_MODE_RST_LAT 0x10 +#define DOC_MODE_BDECT 0x08 +#define DOC_MODE_MDWREN 0x04 #define DOC_ChipID_Doc2k 0x20 +#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */ #define DOC_ChipID_DocMil 0x30 +#define DOC_ChipID_DocMilPlus32 0x40 +#define DOC_ChipID_DocMilPlus16 0x41 #define CDSN_CTRL_FR_B 0x80 +#define CDSN_CTRL_FR_B0 0x40 +#define CDSN_CTRL_FR_B1 0x80 + #define CDSN_CTRL_ECC_IO 0x20 #define CDSN_CTRL_FLASH_IO 0x10 #define CDSN_CTRL_WP 0x08 @@ -93,6 +138,10 @@ #define DOC_ECC_RESV 0x02 #define DOC_ECC_IGNORE 0x01 +#define DOC_FLASH_CE 0x80 +#define DOC_FLASH_WP 0x40 +#define DOC_FLASH_BANK 0x02 + /* We have to also set the reserved bit 1 for enable */ #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) #define DOC_ECC_DIS (DOC_ECC_RESV) @@ -107,9 +156,12 @@ #define MAX_FLOORS 4 #define MAX_CHIPS 4 -#define MAX_FLOORS_MIL 4 +#define MAX_FLOORS_MIL 1 #define MAX_CHIPS_MIL 1 +#define MAX_FLOORS_MPLUS 2 +#define MAX_CHIPS_MPLUS 1 + #define ADDR_COLUMN 1 #define ADDR_PAGE 2 #define ADDR_COLUMN_PAGE 3 @@ -118,7 +170,7 @@ unsigned long physadr; unsigned long virtadr; unsigned long totlen; - char ChipID; /* Type of DiskOnChip */ + unsigned char ChipID; /* Type of DiskOnChip */ int ioreg; unsigned long mfr; /* Flash IDs - only one type of flash per device */ @@ -126,6 +178,7 @@ int chipshift; char page256; char pageadrlen; + char interleave; /* Internal interleaving - Millennium Plus style */ unsigned long erasesize; int curfloor; diff -Nru a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h --- a/include/linux/mtd/flashchip.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/flashchip.h Thu Dec 4 16:24:25 2003 @@ -6,7 +6,7 @@ * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.8 2002/10/21 13:20:52 jocke Exp $ + * $Id: flashchip.h,v 1.9 2003/04/30 11:15:22 dwmw2 Exp $ * */ @@ -58,6 +58,10 @@ int ref_point_counter; flstate_t state; flstate_t oldstate; + + int write_suspended:1; + int erase_suspended:1; + spinlock_t *mutex; spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */ wait_queue_head_t wq; /* Wait on here when we're waiting for the chip diff -Nru a/include/linux/mtd/gen_probe.h b/include/linux/mtd/gen_probe.h --- a/include/linux/mtd/gen_probe.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/gen_probe.h Thu Dec 4 16:24:25 2003 @@ -1,7 +1,7 @@ /* * (C) 2001, 2001 Red Hat, Inc. * GPL'd - * $Id: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $ + * $Id: gen_probe.h,v 1.2 2003/11/08 00:51:21 dsaxena Exp $ */ #ifndef __LINUX_MTD_GEN_PROBE_H__ @@ -10,12 +10,12 @@ #include #include #include +#include struct chip_probe { char *name; int (*probe_chip)(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi); - + unsigned long *chip_map, struct cfi_private *cfi); }; struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp); diff -Nru a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h --- a/include/linux/mtd/jedec.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/jedec.h Thu Dec 4 16:24:25 2003 @@ -7,14 +7,13 @@ * * See the AMD flash databook for information on how to operate the interface. * - * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $ + * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $ */ #ifndef __LINUX_MTD_JEDEC_H__ #define __LINUX_MTD_JEDEC_H__ #include -#include #define MAX_JEDEC_CHIPS 16 diff -Nru a/include/linux/mtd/map.h b/include/linux/mtd/map.h --- a/include/linux/mtd/map.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/map.h Thu Dec 4 16:24:25 2003 @@ -1,14 +1,15 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.29 2002/10/21 13:20:52 jocke Exp $ */ +/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ #include #include -#include -#include +#include +#include +#include /* The map stuff is very simple. You fill in your struct map_info with a handful of routines for accessing the device, making sure they handle @@ -29,39 +30,44 @@ struct map_info { char *name; unsigned long size; + unsigned long phys; +#define NO_XIP (-1UL) + + unsigned long virt; + void *cached; + int buswidth; /* in octets */ - __u8 (*read8)(struct map_info *, unsigned long); - __u16 (*read16)(struct map_info *, unsigned long); - __u32 (*read32)(struct map_info *, unsigned long); - __u64 (*read64)(struct map_info *, unsigned long); + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS + u8 (*read8)(struct map_info *, unsigned long); + u16 (*read16)(struct map_info *, unsigned long); + u32 (*read32)(struct map_info *, unsigned long); + u64 (*read64)(struct map_info *, unsigned long); /* If it returned a 'long' I'd call it readl. * It doesn't. * I won't. * dwmw2 */ void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); - void (*write8)(struct map_info *, __u8, unsigned long); - void (*write16)(struct map_info *, __u16, unsigned long); - void (*write32)(struct map_info *, __u32, unsigned long); - void (*write64)(struct map_info *, __u64, unsigned long); + void (*write8)(struct map_info *, u8, unsigned long); + void (*write16)(struct map_info *, u16, unsigned long); + void (*write32)(struct map_info *, u32, unsigned long); + void (*write64)(struct map_info *, u64, unsigned long); void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); - u_char * (*point) (struct map_info *, loff_t, size_t); - void (*unpoint) (struct map_info *, u_char *, loff_t, size_t); - + /* We can perhaps put in 'point' and 'unpoint' methods, if we really + want to enable XIP for non-linear mappings. Not yet though. */ +#endif + /* set_vpp() must handle being reentered -- enable, enable, disable + must leave it enabled. */ void (*set_vpp)(struct map_info *, int); - /* We put these two here rather than a single void *map_priv, - because we want mappers to be able to have quickly-accessible - cache for the 'currently-mapped page' without the _extra_ - redirection that would be necessary. If you need more than - two longs, turn the second into a pointer. dwmw2 */ + unsigned long map_priv_1; unsigned long map_priv_2; void *fldrv_priv; struct mtd_chip_driver *fldrv; }; - struct mtd_chip_driver { struct mtd_info *(*probe)(struct map_info *map); void (*destroy)(struct mtd_info *); @@ -74,26 +80,93 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *); struct mtd_info *do_map_probe(const char *name, struct map_info *map); +void map_destroy(struct mtd_info *mtd); + +#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) +#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS +#define map_read8(map, ofs) (map)->read8(map, ofs) +#define map_read16(map, ofs) (map)->read16(map, ofs) +#define map_read32(map, ofs) (map)->read32(map, ofs) +#define map_read64(map, ofs) (map)->read64(map, ofs) +#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) +#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs) +#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs) +#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs) +#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs) +#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) +extern void simple_map_init(struct map_info *); +#define map_is_linear(map) (map->phys != NO_XIP) -/* - * Destroy an MTD device which was created for a map device. - * Make sure the MTD device is already unregistered before calling this - */ -static inline void map_destroy(struct mtd_info *mtd) -{ - struct map_info *map = mtd->priv; - - if (map->fldrv->destroy) - map->fldrv->destroy(mtd); -#ifdef CONFIG_MODULES - if (map->fldrv->module) - __MOD_DEC_USE_COUNT(map->fldrv->module); +#else +static inline u8 map_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->virt + ofs); +} + +static inline u16 map_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->virt + ofs); +} + +static inline u32 map_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->virt + ofs); +} + +static inline u64 map_read64(struct map_info *map, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); + return 0; +#else + return __raw_readll(map->virt + ofs); #endif - kfree(mtd); } -#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) -#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) +static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs) +{ + __raw_writeb(datum, map->virt + ofs); + mb(); +} + +static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs) +{ + __raw_writew(datum, map->virt + ofs); + mb(); +} + +static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs) +{ + __raw_writel(datum, map->virt + ofs); + mb(); +} + +static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); +#else + __raw_writell(datum, map->virt + ofs); + mb(); +#endif /* CFI_B8 */ +} + +static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->virt + from, len); +} + +static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->virt + to, from, len); +} + +#define simple_map_init(map) do { } while (0) +#define map_is_linear(map) (1) + +#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ #endif /* __LINUX_MTD_MAP_H__ */ diff -Nru a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h --- a/include/linux/mtd/mtd.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/mtd.h Thu Dec 4 16:24:25 2003 @@ -1,5 +1,10 @@ - -/* $Id: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */ +/* + * $Id: mtd.h,v 1.46 2003/07/11 07:36:21 dwmw2 Exp $ + * + * Copyright (C) 1999-2003 David Woodhouse et al. + * + * Released under GPL + */ #ifndef __MTD_MTD_H__ #define __MTD_MTD_H__ @@ -9,7 +14,6 @@ #include #include #include -#include #include #include @@ -26,7 +30,6 @@ unsigned char *ptr; }; - #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 #define MAX_MTD_DEVICES 16 @@ -93,18 +96,23 @@ #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) #define MEMGETREGIONCOUNT _IOR('M', 7, int) #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -#define MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf) -#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf) +#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) + +struct nand_oobinfo { + int useecc; + int eccpos[6]; +}; + #ifndef __KERNEL__ typedef struct mtd_info_user mtd_info_t; typedef struct erase_info_user erase_info_t; typedef struct region_info_user region_info_t; +typedef struct nand_oobinfo nand_oobinfo_t; /* User-space ioctl definitions */ - #else /* __KERNEL__ */ @@ -149,11 +157,15 @@ u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) u_int32_t ecctype; u_int32_t eccsize; + // Kernel-only stuff starts here. char *name; int index; + // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) + struct nand_oobinfo oobinfo; + /* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. */ @@ -163,7 +175,6 @@ /* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; - struct module *module; int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* This stuff for eXecute-In-Place */ @@ -176,8 +187,8 @@ int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); - int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); + int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); + int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); @@ -201,10 +212,10 @@ */ int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen); int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, - size_t *retlen, u_char *eccbuf, int oobsel); + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen); int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, - size_t *retlen, u_char *eccbuf, int oobsel); + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); /* Sync */ void (*sync) (struct mtd_info *mtd); @@ -218,6 +229,9 @@ void (*resume) (struct mtd_info *mtd); void *priv; + + struct module *owner; + int usecount; }; @@ -226,31 +240,15 @@ extern int add_mtd_device(struct mtd_info *mtd); extern int del_mtd_device (struct mtd_info *mtd); -extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num); - -static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) -{ - struct mtd_info *ret; - - ret = __get_mtd_device(mtd, num); +extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); - if (ret && ret->module && !try_inc_mod_count(ret->module)) - return NULL; - - return ret; -} - -static inline void put_mtd_device(struct mtd_info *mtd) -{ - if (mtd->module) - __MOD_DEC_USE_COUNT(mtd->module); -} +extern void put_mtd_device(struct mtd_info *mtd); struct mtd_notifier { void (*add)(struct mtd_info *mtd); void (*remove)(struct mtd_info *mtd); - struct mtd_notifier *next; + struct list_head list; }; @@ -263,7 +261,6 @@ int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen); -#ifndef MTDC #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) @@ -276,7 +273,6 @@ #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) -#endif /* MTDC */ /* * Debugging macro and defines @@ -287,12 +283,14 @@ #define MTD_DEBUG_LEVEL3 (3) /* Noisy */ #ifdef CONFIG_MTD_DEBUG -#define DEBUG(n, args...) \ - if (n <= CONFIG_MTD_DEBUG_VERBOSE) { \ - printk(KERN_INFO args); \ - } +#define DEBUG(n, args...) \ + do { \ + if (n <= CONFIG_MTD_DEBUG_VERBOSE) \ + printk(KERN_INFO args); \ + } while(0) #else /* CONFIG_MTD_DEBUG */ -#define DEBUG(n, args...) +#define DEBUG(n, args...) do { } while(0) + #endif /* CONFIG_MTD_DEBUG */ #endif /* __KERNEL__ */ diff -Nru a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h --- a/include/linux/mtd/nand.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/nand.h Thu Dec 4 16:24:25 2003 @@ -2,10 +2,10 @@ * linux/include/linux/mtd/nand.h * * Copyright (c) 2000 David Woodhouse - * Steven J. Hill + * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.19 2002/12/02 21:48:17 gleixner Exp $ + * $Id: nand.h,v 1.31 2003/07/11 15:07:02 dwmw2 Exp $ * * 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 @@ -49,12 +49,14 @@ #define __LINUX_MTD_NAND_H #include -#include +#include +#include +struct mtd_info; /* * Searches for a NAND device */ -extern int nand_scan (struct mtd_info *mtd); +extern int nand_scan (struct mtd_info *mtd, int max_chips); /* * Constants for hardware specific CLE/ALE/NCE function @@ -65,6 +67,8 @@ #define NAND_CTL_CLRCLE 4 #define NAND_CTL_SETALE 5 #define NAND_CTL_CLRALE 6 +#define NAND_CTL_SETWP 7 +#define NAND_CTL_CLRWP 8 /* * Standard NAND flash commands @@ -160,24 +164,33 @@ struct nand_chip { unsigned long IO_ADDR_R; unsigned long IO_ADDR_W; - void (*hwcontrol)(int cmd); - int (*dev_ready)(void); + + u_char (*read_byte)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, u_char byte); + + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); + int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*select_chip)(struct mtd_info *mtd, int chip); + int (*block_bad)(struct mtd_info *mtd, unsigned long pos); + void (*hwcontrol)(struct mtd_info *mtd, int cmd); + int (*dev_ready)(struct mtd_info *mtd); void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); - void (*calculate_ecc)(const u_char *dat, u_char *ecc_code); - int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc); - void (*enable_hwecc)(int mode); + void (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); + int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + void (*enable_hwecc)(struct mtd_info *mtd, int mode); int eccmode; int eccsize; int chip_delay; - spinlock_t chip_lock; + int chipshift; + spinlock_t chip_lock; wait_queue_head_t wq; nand_state_t state; int page_shift; u_char *data_buf; u_char *data_poi; - u_char *data_cache; - int cache_page; + void *priv; }; /* @@ -240,35 +253,5 @@ * Constants for oob configuration */ #define NAND_BADBLOCK_POS 5 - -#define NAND_NONE_OOB 0 -#define NAND_JFFS2_OOB 1 -#define NAND_YAFFS_OOB 2 - -#define NAND_NOOB_ECCPOS0 0 -#define NAND_NOOB_ECCPOS1 1 -#define NAND_NOOB_ECCPOS2 2 -#define NAND_NOOB_ECCPOS3 3 -#define NAND_NOOB_ECCPOS4 6 -#define NAND_NOOB_ECCPOS5 7 - -#define NAND_JFFS2_OOB_ECCPOS0 0 -#define NAND_JFFS2_OOB_ECCPOS1 1 -#define NAND_JFFS2_OOB_ECCPOS2 2 -#define NAND_JFFS2_OOB_ECCPOS3 3 -#define NAND_JFFS2_OOB_ECCPOS4 6 -#define NAND_JFFS2_OOB_ECCPOS5 7 - -#define NAND_YAFFS_OOB_ECCPOS0 8 -#define NAND_YAFFS_OOB_ECCPOS1 9 -#define NAND_YAFFS_OOB_ECCPOS2 10 -#define NAND_YAFFS_OOB_ECCPOS3 13 -#define NAND_YAFFS_OOB_ECCPOS4 14 -#define NAND_YAFFS_OOB_ECCPOS5 15 - -#define NAND_JFFS2_OOB8_FSDAPOS 6 -#define NAND_JFFS2_OOB16_FSDAPOS 8 -#define NAND_JFFS2_OOB8_FSDALEN 2 -#define NAND_JFFS2_OOB16_FSDALEN 8 #endif /* __LINUX_MTD_NAND_H */ diff -Nru a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h --- a/include/linux/mtd/nand_ecc.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/mtd/nand_ecc.h Thu Dec 4 16:24:25 2003 @@ -1,9 +1,9 @@ /* * drivers/mtd/nand_ecc.h * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $ + * $Id: nand_ecc.h,v 1.3 2003/07/01 23:31:15 dwmw2 Exp $ * * 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 @@ -12,17 +12,19 @@ * This file is the header for the ECC algorithm. */ -/* - * Creates non-inverted ECC code from line parity - */ -void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code); +#ifndef __MTD_NAND_ECC_H__ +#define __MTD_NAND_ECC_H__ + +struct mtd_info; /* * Calculate 3 byte ECC code for 256 byte block */ -void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); +void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); /* * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); +int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + +#endif /* __MTD_NAND_ECC_H__ */ diff -Nru a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h --- a/include/linux/mtd/nftl.h Thu Dec 4 16:24:26 2003 +++ b/include/linux/mtd/nftl.h Thu Dec 4 16:24:26 2003 @@ -1,15 +1,14 @@ - -/* Defines for NAND Flash Translation Layer */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse */ -/* $Id: nftl.h,v 1.11 2002/06/18 13:54:24 dwmw2 Exp $ */ +/* + * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $ + * + * (C) 1999-2003 David Woodhouse + */ #ifndef __MTD_NFTL_H__ #define __MTD_NFTL_H__ -#ifndef __BOOT__ #include -#endif +#include /* Block Control Information */ @@ -84,8 +83,7 @@ #define BLOCK_RESERVED 0xfffc /* bios block or bad block */ struct NFTLrecord { - struct mtd_info *mtd; - struct semaphore mutex; + struct mtd_blktrans_dev mbd; __u16 MediaUnit, SpareMediaUnit; __u32 EraseSize; struct NFTLMediaHeader MediaHdr; @@ -97,7 +95,6 @@ __u16 lastEUN; /* should be suppressed */ __u16 numfreeEUNs; __u16 LastFreeEUN; /* To speed up finding a free EUN */ - __u32 nr_sects; int head,sect,cyl; __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ @@ -114,7 +111,7 @@ #endif #define MAX_NFTLS 16 -#define MAX_SECTORS_PER_UNIT 32 +#define MAX_SECTORS_PER_UNIT 64 #define NFTL_PARTN_BITS 4 #endif /* __KERNEL__ */ diff -Nru a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h Thu Dec 4 16:24:26 2003 +++ b/include/linux/mtd/partitions.h Thu Dec 4 16:24:26 2003 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $ + * $Id: partitions.h,v 1.15 2003/07/09 11:15:43 dwmw2 Exp $ */ #ifndef MTD_PARTITIONS_H @@ -37,11 +37,12 @@ */ struct mtd_partition { - char *name; /* identifier string */ - u_int32_t size; /* partition size */ + char *name; /* identifier string */ + u_int32_t size; /* partition size */ u_int32_t offset; /* offset within the master MTD space */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ - struct mtd_info **mtdp; /* pointer to store the MTD object */ + u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/ + struct mtd_info **mtdp; /* pointer to store the MTD object */ }; #define MTDPART_OFS_NXTBLK (-2) @@ -49,8 +50,27 @@ #define MTDPART_SIZ_FULL (0) -int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int); +int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); + +/* + * Functions dealing with the various ways of partitioning the space + */ + +struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); +}; + +extern struct mtd_part_parser *get_partition_parser(const char *name); +extern int register_mtd_parser(struct mtd_part_parser *parser); +extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, unsigned long origin); + +#define put_partition_parser(p) do { module_put((p)->owner); } while(0) #endif diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/pci_ids.h Thu Dec 4 16:24:25 2003 @@ -1685,9 +1685,9 @@ #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 #define PCI_DEVICE_ID_INTEL_82562ET 0x1031 - #define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 - +#define PCI_DEVICE_ID_INTEL_80200BECC 0x1162 +#define PCI_DEVICE_ID_INTEL_IXP1200 0x1200 #define PCI_DEVICE_ID_INTEL_82559ER 0x1209 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 #define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 @@ -1799,6 +1799,7 @@ #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca #define PCI_DEVICE_ID_INTEL_82454NX 0x84cb +#define PCI_DEVICE_ID_INTEL_IXP2000 0x9001 #define PCI_VENDOR_ID_COMPUTONE 0x8e0e #define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291 diff -Nru a/include/linux/rbtree-24.h b/include/linux/rbtree-24.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/rbtree-24.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,133 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + rb_node_t * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + rb_node_t * node) +{ + rb_node_t ** p = &inode->i_rb_page_cache.rb_node; + rb_node_t * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + rb_node_t * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include +#include + +typedef struct rb_node_s +{ + struct rb_node_s * rb_parent; + int rb_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node_s * rb_right; + struct rb_node_s * rb_left; +} +rb_node_t; + +typedef struct rb_root_s +{ + struct rb_node_s * rb_node; +} +rb_root_t; + +#define RB_ROOT (rb_root_t) { NULL, } +#define rb_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +extern void rb_insert_color(rb_node_t *, rb_root_t *); +extern void rb_erase(rb_node_t *, rb_root_t *); + +static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) +{ + node->rb_parent = parent; + node->rb_color = RB_RED; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff -Nru a/include/linux/rbtree.h b/include/linux/rbtree.h --- a/include/linux/rbtree.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/rbtree.h Thu Dec 4 16:24:25 2003 @@ -1,133 +1,25 @@ /* - Red Black Trees - (C) 1999 Andrea Arcangeli - - 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 - - linux/include/linux/rbtree.h - - To use rbtrees you'll have to implement your own insert and search cores. - This will avoid us to use callbacks and to drop drammatically performances. - I know it's not the cleaner way, but in C (not in C++) to get - performances and genericity... - - Some example of insert and search follows here. The search is a plain - normal search over an ordered tree. The insert instead must be implemented - int two steps: as first thing the code must insert the element in - order as a red leaf in the tree, then the support library function - rb_insert_color() must be called. Such function will do the - not trivial work to rebalance the rbtree if necessary. - ------------------------------------------------------------------------ -static inline struct page * rb_search_page_cache(struct inode * inode, - unsigned long offset) -{ - rb_node_t * n = inode->i_rb_page_cache.rb_node; - struct page * page; - - while (n) - { - page = rb_entry(n, struct page, rb_page_cache); - - if (offset < page->offset) - n = n->rb_left; - else if (offset > page->offset) - n = n->rb_right; - else - return page; - } - return NULL; -} - -static inline struct page * __rb_insert_page_cache(struct inode * inode, - unsigned long offset, - rb_node_t * node) -{ - rb_node_t ** p = &inode->i_rb_page_cache.rb_node; - rb_node_t * parent = NULL; - struct page * page; - - while (*p) - { - parent = *p; - page = rb_entry(parent, struct page, rb_page_cache); - - if (offset < page->offset) - p = &(*p)->rb_left; - else if (offset > page->offset) - p = &(*p)->rb_right; - else - return page; - } - - rb_link_node(node, parent, p); - - return NULL; -} - -static inline struct page * rb_insert_page_cache(struct inode * inode, - unsigned long offset, - rb_node_t * node) -{ - struct page * ret; - if ((ret = __rb_insert_page_cache(inode, offset, node))) - goto out; - rb_insert_color(node, &inode->i_rb_page_cache); - out: - return ret; -} ------------------------------------------------------------------------ -*/ - -#ifndef _LINUX_RBTREE_H -#define _LINUX_RBTREE_H - -#include -#include - -typedef struct rb_node_s -{ - struct rb_node_s * rb_parent; - int rb_color; -#define RB_RED 0 -#define RB_BLACK 1 - struct rb_node_s * rb_right; - struct rb_node_s * rb_left; -} -rb_node_t; - -typedef struct rb_root_s -{ - struct rb_node_s * rb_node; -} -rb_root_t; - -#define RB_ROOT (rb_root_t) { NULL, } -#define rb_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) - -extern void rb_insert_color(rb_node_t *, rb_root_t *); -extern void rb_erase(rb_node_t *, rb_root_t *); - -static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) -{ - node->rb_parent = parent; - node->rb_color = RB_RED; - node->rb_left = node->rb_right = NULL; + * 2.5 compatibility + * $Id: rbtree.h,v 1.3 2003/01/14 13:56:05 dwmw2 Exp $ + */ + +#ifndef __MTD_COMPAT_RBTREE_H__ +#define __MTD_COMPAT_RBTREE_H__ + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40) +#include_next +#else +#define rb_node_s rb_node +#define rb_root_s rb_root + +#include + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); +#endif - *rb_link = node; -} - -#endif /* _LINUX_RBTREE_H */ +#endif /* __MTD_COMPAT_RBTREE_H__ */ diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/sched.h Thu Dec 4 16:24:25 2003 @@ -91,6 +91,7 @@ #define TASK_UNINTERRUPTIBLE 2 #define TASK_ZOMBIE 4 #define TASK_STOPPED 8 +#define PREEMPT_ACTIVE 0x4000000 #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) @@ -853,6 +854,37 @@ int __ret = 0; \ if (!(condition)) \ __wait_event_interruptible(wq, condition, __ret); \ + __ret; \ +}) + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ __ret; \ }) diff -Nru a/include/linux/serial.h b/include/linux/serial.h --- a/include/linux/serial.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/serial.h Thu Dec 4 16:24:25 2003 @@ -76,7 +76,8 @@ #define PORT_16654 11 #define PORT_16850 12 #define PORT_RSA 13 /* RSA-DV II/S card */ -#define PORT_MAX 13 +#define PORT_XSCALE 14 +#define PORT_MAX 14 #define SERIAL_IO_PORT 0 #define SERIAL_IO_HUB6 1 diff -Nru a/include/linux/serial_core.h b/include/linux/serial_core.h --- a/include/linux/serial_core.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/serial_core.h Thu Dec 4 16:24:25 2003 @@ -73,7 +73,6 @@ #define PORT_OMAHA 48 #define PORT_AT91RM9200 49 - #ifdef __KERNEL__ #include diff -Nru a/include/linux/serial_reg.h b/include/linux/serial_reg.h --- a/include/linux/serial_reg.h Thu Dec 4 16:24:25 2003 +++ b/include/linux/serial_reg.h Thu Dec 4 16:24:25 2003 @@ -119,6 +119,14 @@ #define UART_IERX_SLEEP 0x10 /* Enable sleep mode */ /* + * The Intel PXA250/210 & IXP425 chips define these bits + */ +#define UART_IER_DMAE 0x80 /* DMA Requests Enable */ +#define UART_IER_UUE 0x40 /* UART Unit Enable */ +#define UART_IER_NRZE 0x20 /* NRZ coding Enable */ +#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ + +/* * These are the definitions for the Modem Control Register */ #define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */ diff -Nru a/include/linux/workqueue.h b/include/linux/workqueue.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/workqueue.h Thu Dec 4 16:24:26 2003 @@ -0,0 +1,21 @@ +/* + * 2.5 compatibility + * $Id: workqueue.h,v 1.1 2002/11/11 16:39:10 dwmw2 Exp $ + */ + +#ifndef __MTD_COMPAT_WORKQUEUE_H__ +#define __MTD_COMPAT_WORKQUEUE_H__ + +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40) +#include_next +#else +#include +#define work_struct tq_struct +#define schedule_work(x) schedule_task(x) +#define flush_scheduled_work flush_scheduled_tasks +#define INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z) +#endif + +#endif /* __MTD_COMPAT_WORKQUEUE_H__ */ diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Thu Dec 4 16:24:26 2003 +++ b/init/main.c Thu Dec 4 16:24:26 2003 @@ -69,6 +69,8 @@ #include #endif +#include + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -116,6 +118,10 @@ extern void time_init(void); extern void softirq_init(void); +#ifdef CONFIG_CPU_XSCALE +extern void xscale_locking_init(void); +#endif + int rows, cols; char *execute_command; @@ -398,6 +404,21 @@ kmem_cache_sizes_init(); pgtable_cache_init(); +#ifdef CONFIG_PERFMON + perfmon_init(); +#endif + + /* + * This is done early on to allow it to be used by drivers + * + * HACK HACK HACK + * + * TODO: Replace this with __cachelocked(X) method for 2.5 + */ +#ifdef CONFIG_CPU_XSCALE + xscale_locking_init(); +#endif + /* * For architectures that have highmem, num_mappedpages represents * the amount of memory the kernel can use. For other architectures @@ -409,6 +430,7 @@ num_mappedpages = num_physpages; fork_init(num_mappedpages); + proc_caches_init(); vfs_caches_init(num_physpages); buffer_init(num_physpages); diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Thu Dec 4 16:24:25 2003 +++ b/kernel/ksyms.c Thu Dec 4 16:24:25 2003 @@ -141,6 +141,7 @@ EXPORT_SYMBOL(fget); EXPORT_SYMBOL(igrab); EXPORT_SYMBOL(iunique); +EXPORT_SYMBOL(ilookup); EXPORT_SYMBOL(iget4); EXPORT_SYMBOL(iput); EXPORT_SYMBOL(inode_init_once); diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c --- a/mm/vmalloc.c Thu Dec 4 16:24:25 2003 +++ b/mm/vmalloc.c Thu Dec 4 16:24:25 2003 @@ -183,6 +183,9 @@ return NULL; size += PAGE_SIZE; +#ifdef VMALLOC_ALIGN + size = (size + VMALLOC_ALIGN - 1) & ~(VMALLOC_ALIGN - 1); +#endif if (!size) { kfree (area); return NULL;