aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/pci_link.c3
-rw-r--r--drivers/acpi/processor_perflib.c5
-rw-r--r--drivers/base/class.c32
-rw-r--r--drivers/base/firmware_class.c39
-rw-r--r--drivers/base/power/suspend.c5
-rw-r--r--drivers/base/topology.c2
-rw-r--r--drivers/block/aoe/aoenet.c3
-rw-r--r--drivers/block/floppy.c2
-rw-r--r--drivers/block/ub.c18
-rw-r--r--drivers/cdrom/cdrom.c6
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/Kconfig2
-rw-r--r--drivers/char/agp/alpha-agp.c15
-rw-r--r--drivers/char/agp/amd64-agp.c3
-rw-r--r--drivers/char/agp/generic.c4
-rw-r--r--drivers/char/agp/intel-agp.c2
-rw-r--r--drivers/char/agp/uninorth-agp.c4
-rw-r--r--drivers/char/agp/via-agp.c7
-rw-r--r--drivers/char/drm/drmP.h1
-rw-r--r--drivers/char/drm/drm_agpsupport.c2
-rw-r--r--drivers/char/drm/drm_bufs.c5
-rw-r--r--drivers/char/drm/drm_stub.c2
-rw-r--r--drivers/char/drm/r300_cmdbuf.c2
-rw-r--r--drivers/char/genrtc.c8
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c38
-rw-r--r--drivers/char/keyboard.c38
-rw-r--r--drivers/char/mem.c14
-rw-r--r--drivers/char/mwave/mwavedd.c2
-rw-r--r--drivers/char/n_tty.c4
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c12
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c11
-rw-r--r--drivers/char/rio/host.h9
-rw-r--r--drivers/char/rio/rioboot.c1
-rw-r--r--drivers/char/rio/rioctrl.c43
-rw-r--r--drivers/char/rio/rioioctl.h56
-rw-r--r--drivers/char/snsc.c3
-rw-r--r--drivers/char/tipar.c2
-rw-r--r--drivers/char/tpm/Kconfig11
-rw-r--r--drivers/char/tpm/Makefile1
-rw-r--r--drivers/char/tpm/tpm.c786
-rw-r--r--drivers/char/tpm/tpm.h39
-rw-r--r--drivers/char/tpm/tpm_atmel.c58
-rw-r--r--drivers/char/tpm/tpm_atmel.h25
-rw-r--r--drivers/char/tpm/tpm_bios.c137
-rw-r--r--drivers/char/tpm/tpm_infineon.c61
-rw-r--r--drivers/char/tpm/tpm_nsc.c49
-rw-r--r--drivers/char/tpm/tpm_tis.c665
-rw-r--r--drivers/char/tty_io.c2
-rw-r--r--drivers/char/vt.c8
-rw-r--r--drivers/char/watchdog/i8xx_tco.c16
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c6
-rw-r--r--drivers/char/watchdog/sc1200wdt.c2
-rw-r--r--drivers/connector/cn_queue.c2
-rw-r--r--drivers/cpufreq/cpufreq.c10
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c28
-rw-r--r--drivers/cpufreq/cpufreq_stats.c6
-rw-r--r--drivers/cpufreq/freq_table.c16
-rw-r--r--drivers/dma/Kconfig34
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/dmaengine.c408
-rw-r--r--drivers/dma/ioatdma.c840
-rw-r--r--drivers/dma/ioatdma.h125
-rw-r--r--drivers/dma/ioatdma_hw.h52
-rw-r--r--drivers/dma/ioatdma_io.h118
-rw-r--r--drivers/dma/ioatdma_registers.h126
-rw-r--r--drivers/dma/iovlock.c301
-rw-r--r--drivers/edac/e752x_edac.c17
-rw-r--r--drivers/i2c/busses/scx200_acb.c18
-rw-r--r--drivers/ide/legacy/ide-cs.c1
-rw-r--r--drivers/ide/pci/sgiioc4.c16
-rw-r--r--drivers/ide/ppc/pmac.c2
-rw-r--r--drivers/ieee1394/ohci1394.c2
-rw-r--r--drivers/ieee1394/sbp2.c211
-rw-r--r--drivers/ieee1394/sbp2.h18
-rw-r--r--drivers/infiniband/Kconfig5
-rw-r--r--drivers/infiniband/core/Makefile11
-rw-r--r--drivers/infiniband/core/addr.c367
-rw-r--r--drivers/infiniband/core/cache.c30
-rw-r--r--drivers/infiniband/core/cm.c131
-rw-r--r--drivers/infiniband/core/cma.c1927
-rw-r--r--drivers/infiniband/core/fmr_pool.c30
-rw-r--r--drivers/infiniband/core/mad.c144
-rw-r--r--drivers/infiniband/core/mad_priv.h7
-rw-r--r--drivers/infiniband/core/mad_rmpp.c20
-rw-r--r--drivers/infiniband/core/sa_query.c31
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/infiniband/core/ucm.c195
-rw-r--r--drivers/infiniband/core/uverbs.h4
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c971
-rw-r--r--drivers/infiniband/core/uverbs_main.c35
-rw-r--r--drivers/infiniband/core/uverbs_marshall.c138
-rw-r--r--drivers/infiniband/core/uverbs_mem.c4
-rw-r--r--drivers/infiniband/core/verbs.c44
-rw-r--r--drivers/infiniband/hw/ipath/ipath_debug.h15
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c47
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ht400.c21
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c37
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c21
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h12
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.c18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c42
-rw-r--r--drivers/infiniband/hw/ipath/ipath_pe800.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c64
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c15
-rw-r--r--drivers/infiniband/hw/ipath/ipath_registers.h31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c17
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c14
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c44
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h3
-rw-r--r--drivers/infiniband/hw/ipath/ips_common.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c25
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c53
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c15
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c35
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h25
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c106
-rw-r--r--drivers/infiniband/hw/mthca/mthca_reset.c59
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c69
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h34
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c28
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c28
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c17
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c4
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c659
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h37
-rw-r--r--drivers/input/evdev.c21
-rw-r--r--drivers/input/input.c11
-rw-r--r--drivers/input/joystick/sidewinder.c11
-rw-r--r--drivers/input/keyboard/corgikbd.c12
-rw-r--r--drivers/input/keyboard/hil_kbd.c2
-rw-r--r--drivers/input/keyboard/spitzkbd.c16
-rw-r--r--drivers/input/misc/wistron_btns.c49
-rw-r--r--drivers/input/mouse/alps.c4
-rw-r--r--drivers/input/mouse/lifebook.c24
-rw-r--r--drivers/input/mouse/logips2pp.c6
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/serio/i8042-io.h4
-rw-r--r--drivers/input/touchscreen/ads7846.c445
-rw-r--r--drivers/input/touchscreen/corgi_ts.c2
-rw-r--r--drivers/isdn/capi/capi.c1
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c597
-rw-r--r--drivers/isdn/gigaset/common.c3
-rw-r--r--drivers/isdn/gigaset/ev-layer.c3
-rw-r--r--drivers/isdn/gigaset/gigaset.h7
-rw-r--r--drivers/isdn/gigaset/i4l.c2
-rw-r--r--drivers/isdn/gigaset/isocdata.c10
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c4
-rw-r--r--drivers/isdn/i4l/isdn_tty.c2
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/led-class.c9
-rw-r--r--drivers/leds/ledtrig-timer.c17
-rw-r--r--drivers/macintosh/therm_adt746x.c4
-rw-r--r--drivers/md/md.c17
-rw-r--r--drivers/md/raid0.c5
-rw-r--r--drivers/md/raid1.c29
-rw-r--r--drivers/md/raid10.c46
-rw-r--r--drivers/media/Kconfig45
-rw-r--r--drivers/media/common/Kconfig3
-rw-r--r--drivers/media/dvb/Kconfig10
-rw-r--r--drivers/media/dvb/b2c2/Kconfig6
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig3
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c6
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c4
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c17
-rw-r--r--drivers/media/dvb/frontends/cx24123.c565
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c4
-rw-r--r--drivers/media/dvb/pluto2/Kconfig3
-rw-r--r--drivers/media/dvb/pluto2/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig12
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c105
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c6
-rw-r--r--drivers/media/radio/Kconfig30
-rw-r--r--drivers/media/video/Kconfig79
-rw-r--r--drivers/media/video/Makefile10
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/Makefile2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c4
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c14
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c49
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/video/cx88/cx88-cards.c2
-rw-r--r--drivers/media/video/cx88/cx88-core.c16
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/video/cx88/cx88-video.c2
-rw-r--r--drivers/media/video/em28xx/Kconfig2
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c10
-rw-r--r--drivers/media/video/et61x251/Kconfig2
-rw-r--r--drivers/media/video/pwc/Kconfig2
-rw-r--r--drivers/media/video/pwc/Makefile17
-rw-r--r--drivers/media/video/saa7127.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/sn9c102/Kconfig2
-rw-r--r--drivers/media/video/tuner-types.c4
-rw-r--r--drivers/media/video/tveeprom.c2
-rw-r--r--drivers/media/video/usbvideo/Kconfig6
-rw-r--r--drivers/media/video/vivi.c5
-rw-r--r--drivers/media/video/zc0301/Kconfig2
-rw-r--r--drivers/message/fusion/mptbase.c90
-rw-r--r--drivers/message/fusion/mptbase.h10
-rw-r--r--drivers/message/fusion/mptfc.c134
-rw-r--r--drivers/message/fusion/mptsas.c99
-rw-r--r--drivers/message/fusion/mptscsih.c50
-rw-r--r--drivers/message/fusion/mptspi.c70
-rw-r--r--drivers/message/i2o/exec-osm.c72
-rw-r--r--drivers/message/i2o/iop.c4
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/at91_mci.c3
-rw-r--r--drivers/mmc/au1xmmc.c10
-rw-r--r--drivers/mmc/imxmmc.c84
-rw-r--r--drivers/mmc/mmc.c63
-rw-r--r--drivers/mmc/mmc_block.c9
-rw-r--r--drivers/mmc/mmci.c3
-rw-r--r--drivers/mmc/pxamci.c27
-rw-r--r--drivers/mmc/sdhci.c6
-rw-r--r--drivers/mmc/wbsd.c12
-rw-r--r--drivers/mtd/Kconfig4
-rw-r--r--drivers/mtd/chips/Kconfig1
-rw-r--r--drivers/mtd/chips/Makefile7
-rw-r--r--drivers/mtd/chips/amd_flash.c8
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c474
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c22
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c22
-rw-r--r--drivers/mtd/chips/cfi_probe.c8
-rw-r--r--drivers/mtd/chips/gen_probe.c45
-rw-r--r--drivers/mtd/chips/map_ram.c2
-rw-r--r--drivers/mtd/chips/map_rom.c4
-rw-r--r--drivers/mtd/chips/sharp.c1
-rw-r--r--drivers/mtd/devices/Kconfig6
-rw-r--r--drivers/mtd/devices/Makefile7
-rw-r--r--drivers/mtd/devices/block2mtd.c27
-rw-r--r--drivers/mtd/devices/doc2000.c129
-rw-r--r--drivers/mtd/devices/doc2001.c60
-rw-r--r--drivers/mtd/devices/doc2001plus.c60
-rw-r--r--drivers/mtd/devices/docprobe.c26
-rw-r--r--drivers/mtd/devices/lart.c1
-rw-r--r--drivers/mtd/devices/m25p80.c1
-rw-r--r--drivers/mtd/devices/ms02-nv.c2
-rw-r--r--drivers/mtd/devices/mtdram.c1
-rw-r--r--drivers/mtd/devices/phram.c16
-rw-r--r--drivers/mtd/devices/slram.c3
-rw-r--r--drivers/mtd/inftlcore.c192
-rw-r--r--drivers/mtd/inftlmount.c60
-rw-r--r--drivers/mtd/maps/Kconfig11
-rw-r--r--drivers/mtd/maps/cfi_flagadm.c4
-rw-r--r--drivers/mtd/maps/dbox2-flash.c2
-rw-r--r--drivers/mtd/maps/mtx-1_flash.c2
-rw-r--r--drivers/mtd/maps/nettel.c4
-rw-r--r--drivers/mtd/maps/pcmciamtd.c1
-rw-r--r--drivers/mtd/maps/physmap.c255
-rw-r--r--drivers/mtd/mtdblock.c16
-rw-r--r--drivers/mtd/mtdblock_ro.c4
-rw-r--r--drivers/mtd/mtdchar.c327
-rw-r--r--drivers/mtd/mtdconcat.c335
-rw-r--r--drivers/mtd/mtdcore.c33
-rw-r--r--drivers/mtd/mtdpart.c171
-rw-r--r--drivers/mtd/nand/Kconfig57
-rw-r--r--drivers/mtd/nand/Makefile4
-rw-r--r--drivers/mtd/nand/ams-delta.c237
-rw-r--r--drivers/mtd/nand/au1550nd.c321
-rw-r--r--drivers/mtd/nand/autcpu12.c125
-rw-r--r--drivers/mtd/nand/cs553x_nand.c353
-rw-r--r--drivers/mtd/nand/diskonchip.c530
-rw-r--r--drivers/mtd/nand/edb7312.c97
-rw-r--r--drivers/mtd/nand/h1910.c98
-rw-r--r--drivers/mtd/nand/nand_base.c3249
-rw-r--r--drivers/mtd/nand/nand_bbt.c502
-rw-r--r--drivers/mtd/nand/nand_ecc.c227
-rw-r--r--drivers/mtd/nand/nand_ids.c177
-rw-r--r--drivers/mtd/nand/nandsim.c95
-rw-r--r--drivers/mtd/nand/ndfc.c311
-rw-r--r--drivers/mtd/nand/ppchameleonevb.c256
-rw-r--r--drivers/mtd/nand/rtc_from4.c351
-rw-r--r--drivers/mtd/nand/s3c2410.c252
-rw-r--r--drivers/mtd/nand/sharpsl.c146
-rw-r--r--drivers/mtd/nand/spia.c101
-rw-r--r--drivers/mtd/nand/toto.c121
-rw-r--r--drivers/mtd/nand/ts7250.c206
-rw-r--r--drivers/mtd/nftlcore.c221
-rw-r--r--drivers/mtd/nftlmount.c91
-rw-r--r--drivers/mtd/onenand/Kconfig14
-rw-r--r--drivers/mtd/onenand/onenand_base.c718
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c9
-rw-r--r--drivers/mtd/redboot.c18
-rw-r--r--drivers/mtd/rfd_ftl.c48
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c503.c2
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c527.c2
-rw-r--r--drivers/net/8139cp.c14
-rw-r--r--drivers/net/8139too.c14
-rw-r--r--drivers/net/Kconfig36
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/au1000_eth.c1820
-rw-r--r--drivers/net/au1000_eth.h134
-rw-r--r--drivers/net/b44.c28
-rw-r--r--drivers/net/bnx2.c206
-rw-r--r--drivers/net/bnx2.h15
-rw-r--r--drivers/net/bnx2_fw.h5256
-rw-r--r--drivers/net/bonding/bond_main.c9
-rw-r--r--drivers/net/cassini.c9
-rw-r--r--drivers/net/dl2k.c13
-rw-r--r--drivers/net/e100.c75
-rw-r--r--drivers/net/e1000/Makefile3
-rw-r--r--drivers/net/e1000/e1000.h6
-rw-r--r--drivers/net/e1000/e1000_ethtool.c46
-rw-r--r--drivers/net/e1000/e1000_hw.c115
-rw-r--r--drivers/net/e1000/e1000_hw.h7
-rw-r--r--drivers/net/e1000/e1000_main.c402
-rw-r--r--drivers/net/e1000/e1000_osdep.h3
-rw-r--r--drivers/net/e1000/e1000_param.c3
-rw-r--r--drivers/net/epic100.c56
-rw-r--r--drivers/net/forcedeth.c1996
-rw-r--r--drivers/net/gianfar.c56
-rw-r--r--drivers/net/gianfar.h67
-rw-r--r--drivers/net/gianfar_ethtool.c20
-rw-r--r--drivers/net/gianfar_sysfs.c24
-rw-r--r--drivers/net/hamradio/6pack.c8
-rw-r--r--drivers/net/hamradio/dmascc.c1
-rw-r--r--drivers/net/hamradio/mkiss.c8
-rw-r--r--drivers/net/hamradio/scc.c1
-rw-r--r--drivers/net/hamradio/yam.c1
-rw-r--r--drivers/net/hp-plus.c2
-rw-r--r--drivers/net/hp.c4
-rw-r--r--drivers/net/ibmlana.c20
-rw-r--r--drivers/net/ibmlana.h6
-rw-r--r--drivers/net/ibmveth.c291
-rw-r--r--drivers/net/ibmveth.h11
-rw-r--r--drivers/net/ifb.c10
-rw-r--r--drivers/net/irda/Kconfig35
-rw-r--r--drivers/net/irda/Makefile3
-rw-r--r--drivers/net/irda/ali-ircc.c106
-rw-r--r--drivers/net/irda/irda-usb.c329
-rw-r--r--drivers/net/irda/irda-usb.h10
-rw-r--r--drivers/net/irda/mcs7780.c1009
-rw-r--r--drivers/net/irda/mcs7780.h167
-rw-r--r--drivers/net/irda/sir-dev.h13
-rw-r--r--drivers/net/irda/sir_dev.c315
-rw-r--r--drivers/net/irda/sir_kthread.c508
-rw-r--r--drivers/net/irda/smsc-ircc2.c14
-rw-r--r--drivers/net/irda/stir4200.c38
-rw-r--r--drivers/net/irda/vlsi_ir.c2
-rw-r--r--drivers/net/ixgb/Makefile2
-rw-r--r--drivers/net/ixgb/ixgb.h12
-rw-r--r--drivers/net/ixgb/ixgb_ee.c2
-rw-r--r--drivers/net/ixgb/ixgb_ee.h2
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c57
-rw-r--r--drivers/net/ixgb/ixgb_hw.c2
-rw-r--r--drivers/net/ixgb/ixgb_hw.h3
-rw-r--r--drivers/net/ixgb/ixgb_ids.h6
-rw-r--r--drivers/net/ixgb/ixgb_main.c304
-rw-r--r--drivers/net/ixgb/ixgb_osdep.h2
-rw-r--r--drivers/net/ixgb/ixgb_param.c26
-rw-r--r--drivers/net/ixp2000/enp2611.c13
-rw-r--r--drivers/net/ixp2000/pm3386.c30
-rw-r--r--drivers/net/ixp2000/pm3386.h1
-rw-r--r--drivers/net/mv643xx_eth.c4
-rw-r--r--drivers/net/myri10ge/Makefile5
-rw-r--r--drivers/net/myri10ge/myri10ge.c2869
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h205
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp_gen_header.h58
-rw-r--r--drivers/net/natsemi.c4
-rw-r--r--drivers/net/ne.c33
-rw-r--r--drivers/net/ne2.c2
-rw-r--r--drivers/net/netconsole.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c13
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c43
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/mdio_bus.c4
-rw-r--r--drivers/net/phy/smsc.c101
-rw-r--r--drivers/net/ppp_generic.c2
-rw-r--r--drivers/net/pppoe.c3
-rw-r--r--drivers/net/r8169.c1
-rw-r--r--drivers/net/s2io-regs.h32
-rw-r--r--drivers/net/s2io.c1476
-rw-r--r--drivers/net/s2io.h59
-rw-r--r--drivers/net/sis900.c27
-rw-r--r--drivers/net/sis900.h10
-rw-r--r--drivers/net/skge.c238
-rw-r--r--drivers/net/skge.h6
-rw-r--r--drivers/net/sky2.c325
-rw-r--r--drivers/net/sky2.h7
-rw-r--r--drivers/net/smc-ultra.c2
-rw-r--r--drivers/net/smc-ultra32.c2
-rw-r--r--drivers/net/smc911x.c2307
-rw-r--r--drivers/net/smc911x.h835
-rw-r--r--drivers/net/smc9194.c7
-rw-r--r--drivers/net/smc91x.h62
-rw-r--r--drivers/net/spider_net.c12
-rw-r--r--drivers/net/spider_net.h2
-rw-r--r--drivers/net/sungem_phy.c45
-rw-r--r--drivers/net/sungem_phy.h1
-rw-r--r--drivers/net/tg3.c319
-rw-r--r--drivers/net/tg3.h25
-rw-r--r--drivers/net/tulip/de2104x.c58
-rw-r--r--drivers/net/tulip/de4x5.c716
-rw-r--r--drivers/net/tulip/de4x5.h14
-rw-r--r--drivers/net/tulip/dmfe.c2
-rw-r--r--drivers/net/tulip/eeprom.c8
-rw-r--r--drivers/net/tulip/interrupt.c126
-rw-r--r--drivers/net/tulip/media.c2
-rw-r--r--drivers/net/tulip/tulip.h2
-rw-r--r--drivers/net/tulip/tulip_core.c14
-rw-r--r--drivers/net/tulip/uli526x.c80
-rw-r--r--drivers/net/tulip/winbond-840.c37
-rw-r--r--drivers/net/tulip/xircom_cb.c208
-rw-r--r--drivers/net/via-rhine.c40
-rw-r--r--drivers/net/via-velocity.c10
-rw-r--r--drivers/net/via-velocity.h2
-rw-r--r--drivers/net/wan/pci200syn.c27
-rw-r--r--drivers/net/wireless/Kconfig47
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/airo.c271
-rw-r--r--drivers/net/wireless/arlan-main.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c31
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h8
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c99
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c92
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.h16
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c7
-rw-r--r--drivers/net/wireless/hermes.c66
-rw-r--r--drivers/net/wireless/hermes.h43
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c11
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c2
-rw-r--r--drivers/net/wireless/ipw2200.c849
-rw-r--r--drivers/net/wireless/ipw2200.h83
-rw-r--r--drivers/net/wireless/orinoco.c259
-rw-r--r--drivers/net/wireless/orinoco.h19
-rw-r--r--drivers/net/wireless/orinoco_cs.c42
-rw-r--r--drivers/net/wireless/orinoco_nortel.c171
-rw-r--r--drivers/net/wireless/orinoco_pci.c210
-rw-r--r--drivers/net/wireless/orinoco_pci.h104
-rw-r--r--drivers/net/wireless/orinoco_plx.c223
-rw-r--r--drivers/net/wireless/orinoco_tmd.c99
-rw-r--r--drivers/net/wireless/spectrum_cs.c81
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/zd1201.c (renamed from drivers/usb/net/zd1201.c)67
-rw-r--r--drivers/net/wireless/zd1201.h (renamed from drivers/usb/net/zd1201.h)0
-rw-r--r--drivers/parisc/pdc_stable.c2
-rw-r--r--drivers/parisc/sba_iommu.c45
-rw-r--r--drivers/parisc/superio.c4
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/pci/msi.c4
-rw-r--r--drivers/pci/pci-acpi.c60
-rw-r--r--drivers/pci/pci-driver.c13
-rw-r--r--drivers/pci/pci.c21
-rw-r--r--drivers/pci/quirks.c22
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/ds.c22
-rw-r--r--drivers/pcmcia/i82365.c7
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c23
-rw-r--r--drivers/pcmcia/pcmcia_resource.c18
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/rtc/rtc-dev.c23
-rw-r--r--drivers/rtc/rtc-m48t86.c72
-rw-r--r--drivers/rtc/rtc-sa1100.c8
-rw-r--r--drivers/rtc/rtc-test.c2
-rw-r--r--drivers/rtc/rtc-vr41xx.c2
-rw-r--r--drivers/s390/block/dasd.c5
-rw-r--r--drivers/s390/block/dasd_devmap.c102
-rw-r--r--drivers/s390/block/dasd_eckd.c51
-rw-r--r--drivers/s390/block/dasd_eckd.h46
-rw-r--r--drivers/s390/block/dasd_int.h12
-rw-r--r--drivers/s390/char/tape_3590.c22
-rw-r--r--drivers/s390/char/tape_std.h1
-rw-r--r--drivers/s390/cio/chsc.c30
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/qdio.c36
-rw-r--r--drivers/s390/net/Makefile3
-rw-r--r--drivers/s390/net/ctcmain.c71
-rw-r--r--drivers/s390/net/ctcmain.h12
-rw-r--r--drivers/s390/net/ctctty.c1259
-rw-r--r--drivers/s390/net/ctctty.h35
-rw-r--r--drivers/s390/net/cu3088.c10
-rw-r--r--drivers/s390/net/iucv.c36
-rw-r--r--drivers/s390/net/iucv.h622
-rw-r--r--drivers/s390/net/lcs.c347
-rw-r--r--drivers/s390/net/lcs.h14
-rw-r--r--drivers/s390/net/netiucv.c36
-rw-r--r--drivers/s390/net/qeth.h18
-rw-r--r--drivers/s390/net/qeth_eddp.c18
-rw-r--r--drivers/s390/net/qeth_fs.h2
-rw-r--r--drivers/s390/net/qeth_main.c108
-rw-r--r--drivers/s390/net/qeth_mpc.h4
-rw-r--r--drivers/s390/net/qeth_proc.c8
-rw-r--r--drivers/s390/net/qeth_sys.c6
-rw-r--r--drivers/s390/net/qeth_tso.h4
-rw-r--r--drivers/s390/s390mach.c34
-rw-r--r--drivers/sbus/char/openprom.c15
-rw-r--r--drivers/scsi/Kconfig4
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c12
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c30
-rw-r--r--drivers/scsi/libata-core.c13
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c95
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c18
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c22
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c68
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid.c1
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c59
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h7
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c6
-rw-r--r--drivers/scsi/ppa.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c19
-rw-r--r--drivers/scsi/sata_mv.c137
-rw-r--r--drivers/scsi/sata_sil24.c6
-rw-r--r--drivers/scsi/scsi_devinfo.c3
-rw-r--r--drivers/scsi/scsi_lib.c29
-rw-r--r--drivers/scsi/scsi_transport_sas.c4
-rw-r--r--drivers/scsi/sim710.c2
-rw-r--r--drivers/scsi/st.c2
-rw-r--r--drivers/serial/8250.c74
-rw-r--r--drivers/serial/8250_au1x00.c5
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h58
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c309
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c56
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c16
-rw-r--r--drivers/serial/imx.c40
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/serial/serial_core.c123
-rw-r--r--drivers/serial/serial_lh7a40x.c13
-rw-r--r--drivers/serial/sunsu.c1
-rw-r--r--drivers/sn/ioc3.c2
-rw-r--r--drivers/sn/ioc4.c2
-rw-r--r--drivers/spi/Kconfig34
-rw-r--r--drivers/spi/Makefile4
-rw-r--r--drivers/spi/pxa2xx_spi.c1486
-rw-r--r--drivers/spi/spi.c13
-rw-r--r--drivers/spi/spi_bitbang.c104
-rw-r--r--drivers/spi/spi_butterfly.c1
-rw-r--r--drivers/spi/spi_mpc83xx.c483
-rw-r--r--drivers/spi/spi_s3c24xx.c453
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c188
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/atm/usbatm.c8
-rw-r--r--drivers/usb/core/hcd.c13
-rw-r--r--drivers/usb/core/hub.c23
-rw-r--r--drivers/usb/gadget/inode.c1
-rw-r--r--drivers/usb/gadget/net2280.c15
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-pci.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c3
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/input/hid-core.c4
-rw-r--r--drivers/usb/input/hiddev.c1
-rw-r--r--drivers/usb/misc/emi26.c4
-rw-r--r--drivers/usb/misc/emi62.c4
-rw-r--r--drivers/usb/net/Kconfig17
-rw-r--r--drivers/usb/net/Makefile1
-rw-r--r--drivers/usb/net/pegasus.c20
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/airprime.c1
-rw-r--r--drivers/usb/serial/ark3116.c465
-rw-r--r--drivers/usb/serial/ftdi_sio.c5
-rw-r--r--drivers/usb/serial/ftdi_sio.h22
-rw-r--r--drivers/usb/serial/generic.c1
-rw-r--r--drivers/usb/serial/omninet.c12
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h1
-rw-r--r--drivers/usb/serial/usb-serial.c19
-rw-r--r--drivers/usb/serial/whiteheat.c1
-rw-r--r--drivers/usb/storage/unusual_devs.h9
-rw-r--r--drivers/video/Kconfig67
-rw-r--r--drivers/video/au1100fb.c21
-rw-r--r--drivers/video/au1200fb.c1922
-rw-r--r--drivers/video/backlight/backlight.c18
-rw-r--r--drivers/video/backlight/lcd.c32
-rw-r--r--drivers/video/console/fbcon.c4
-rw-r--r--drivers/video/fbsysfs.c92
-rw-r--r--drivers/video/i810/i810_main.c4
-rw-r--r--drivers/video/intelfb/intelfb.h16
-rw-r--r--drivers/video/intelfb/intelfbdrv.c85
-rw-r--r--drivers/video/intelfb/intelfbhw.c494
-rw-r--r--drivers/video/intelfb/intelfbhw.h25
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/matrox/g450_pll.c23
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h2
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/maxinefb.c4
619 files changed, 40628 insertions, 22521 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5c91d6afb117..8b11cebe65df 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -68,10 +68,10 @@ source "drivers/leds/Kconfig"
source "drivers/infiniband/Kconfig"
-source "drivers/sn/Kconfig"
-
source "drivers/edac/Kconfig"
source "drivers/rtc/Kconfig"
+source "drivers/dma/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 447d8e68887a..3c5170310bd0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
+obj-$(CONFIG_DMA_ENGINE) += dma/
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 07bc6dfe662b..8920e8c6e246 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -812,6 +812,9 @@ static int irqrouter_resume(struct sys_device *dev)
ACPI_FUNCTION_TRACE("irqrouter_resume");
+ /* Make sure SCI is enabled again (Apple firmware bug?) */
+ acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+
acpi_in_resume = 1;
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index abbdb37a7f5f..f36db22ce1ae 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -577,6 +577,8 @@ acpi_processor_register_performance(struct acpi_processor_performance
return_VALUE(-EBUSY);
}
+ WARN_ON(!performance);
+
pr->performance = performance;
if (acpi_processor_get_performance_info(pr)) {
@@ -609,7 +611,8 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
return_VOID;
}
- kfree(pr->performance->states);
+ if (pr->performance)
+ kfree(pr->performance->states);
pr->performance = NULL;
acpi_cpufreq_remove_file(pr);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 0e71dff327cd..b1ea4df85c7d 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -456,6 +456,35 @@ static void class_device_remove_attrs(struct class_device * cd)
}
}
+static int class_device_add_groups(struct class_device * cd)
+{
+ int i;
+ int error = 0;
+
+ if (cd->groups) {
+ for (i = 0; cd->groups[i]; i++) {
+ error = sysfs_create_group(&cd->kobj, cd->groups[i]);
+ if (error) {
+ while (--i >= 0)
+ sysfs_remove_group(&cd->kobj, cd->groups[i]);
+ goto out;
+ }
+ }
+ }
+out:
+ return error;
+}
+
+static void class_device_remove_groups(struct class_device * cd)
+{
+ int i;
+ if (cd->groups) {
+ for (i = 0; cd->groups[i]; i++) {
+ sysfs_remove_group(&cd->kobj, cd->groups[i]);
+ }
+ }
+}
+
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
return print_dev_t(buf, class_dev->devt);
@@ -559,6 +588,8 @@ int class_device_add(struct class_device *class_dev)
class_name);
}
+ class_device_add_groups(class_dev);
+
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
/* notify any interfaces this device is now here */
@@ -672,6 +703,7 @@ void class_device_del(struct class_device *class_dev)
if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr);
class_device_remove_attrs(class_dev);
+ class_device_remove_groups(class_dev);
kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
kobject_del(&class_dev->kobj);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 472318205236..0c99ae6a3407 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -86,18 +86,9 @@ firmware_timeout_store(struct class *class, const char *buf, size_t count)
static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
static void fw_class_dev_release(struct class_device *class_dev);
-int firmware_class_uevent(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-static struct class firmware_class = {
- .name = "firmware",
- .uevent = firmware_class_uevent,
- .release = fw_class_dev_release,
-};
-
-int
-firmware_class_uevent(struct class_device *class_dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int firmware_class_uevent(struct class_device *class_dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
int i = 0, len = 0;
@@ -116,6 +107,12 @@ firmware_class_uevent(struct class_device *class_dev, char **envp,
return 0;
}
+static struct class firmware_class = {
+ .name = "firmware",
+ .uevent = firmware_class_uevent,
+ .release = fw_class_dev_release,
+};
+
static ssize_t
firmware_loading_show(struct class_device *class_dev, char *buf)
{
@@ -493,25 +490,6 @@ release_firmware(const struct firmware *fw)
}
}
-/**
- * register_firmware: - provide a firmware image for later usage
- * @name: name of firmware image file
- * @data: buffer pointer for the firmware image
- * @size: size of the data buffer area
- *
- * Make sure that @data will be available by requesting firmware @name.
- *
- * Note: This will not be possible until some kind of persistence
- * is available.
- **/
-void
-register_firmware(const char *name, const u8 *data, size_t size)
-{
- /* This is meaningless without firmware caching, so until we
- * decide if firmware caching is reasonable just leave it as a
- * noop */
-}
-
/* Async support */
struct firmware_work {
struct work_struct work;
@@ -630,4 +608,3 @@ module_exit(firmware_class_exit);
EXPORT_SYMBOL(release_firmware);
EXPORT_SYMBOL(request_firmware);
EXPORT_SYMBOL(request_firmware_nowait);
-EXPORT_SYMBOL(register_firmware);
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 662209d3f42d..2a769cc6f5f9 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/vt_kern.h>
#include <linux/device.h>
#include <linux/kallsyms.h>
#include <linux/pm.h>
@@ -66,6 +65,7 @@ int suspend_device(struct device * dev, pm_message_t state)
return error;
}
+
/**
* device_suspend - Save state and stop all devices in system.
* @state: Power state to put each device in.
@@ -85,9 +85,6 @@ int device_suspend(pm_message_t state)
{
int error = 0;
- if (!is_console_suspend_safe())
- return -EINVAL;
-
down(&dpm_sem);
down(&dpm_list_sem);
while (!list_empty(&dpm_active) && error == 0) {
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 915810f6237e..8c52421cbc54 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
return 0;
}
-static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
+static int topology_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index fdff774b8ab9..c1434ed11880 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -116,8 +116,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
skb = skb_share_check(skb, GFP_ATOMIC);
if (skb == NULL)
return 0;
- if (skb_is_nonlinear(skb))
- if (skb_linearize(skb, GFP_ATOMIC) < 0)
+ if (skb_linearize(skb))
goto exit;
if (!is_aoe_netif(ifp))
goto exit;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index bedb689b051f..dff1e67b1dd4 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4301,7 +4301,7 @@ static int __init floppy_init(void)
}
use_virtual_dma = can_use_virtual_dma & 1;
-#if defined(CONFIG_PPC64)
+#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(FDC1)) {
del_timer(&fd_timeout);
err = -ENODEV;
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index f73446f580df..c688c25992e4 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -536,6 +536,9 @@ static void ub_cleanup(struct ub_dev *sc)
kfree(lun);
}
+ usb_set_intfdata(sc->intf, NULL);
+ usb_put_intf(sc->intf);
+ usb_put_dev(sc->dev);
kfree(sc);
}
@@ -2221,7 +2224,12 @@ static int ub_probe(struct usb_interface *intf,
// sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usb_set_intfdata(intf, sc);
usb_get_dev(sc->dev);
- // usb_get_intf(sc->intf); /* Do we need this? */
+ /*
+ * Since we give the interface struct to the block level through
+ * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent
+ * oopses on close after a disconnect (kernels 2.6.16 and up).
+ */
+ usb_get_intf(sc->intf);
snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
sc->dev->bus->busnum, sc->dev->devnum);
@@ -2286,7 +2294,7 @@ static int ub_probe(struct usb_interface *intf,
err_dev_desc:
usb_set_intfdata(intf, NULL);
- // usb_put_intf(sc->intf);
+ usb_put_intf(sc->intf);
usb_put_dev(sc->dev);
kfree(sc);
err_core:
@@ -2461,12 +2469,6 @@ static void ub_disconnect(struct usb_interface *intf)
* and no URBs left in transit.
*/
- usb_set_intfdata(intf, NULL);
- // usb_put_intf(sc->intf);
- sc->intf = NULL;
- usb_put_dev(sc->dev);
- sc->dev = NULL;
-
ub_put(sc);
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index a59876a0bfa1..3170eaa25087 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1009,9 +1009,9 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
if (fp->f_mode & FMODE_WRITE) {
ret = -EROFS;
if (cdrom_open_write(cdi))
- goto err;
+ goto err_release;
if (!CDROM_CAN(CDC_RAM))
- goto err;
+ goto err_release;
ret = 0;
cdi->media_written = 0;
}
@@ -1026,6 +1026,8 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
not be mounting, but opening with O_NONBLOCK */
check_disk_change(ip->i_bdev);
return 0;
+err_release:
+ cdi->ops->release(cdi);
err:
cdi->use_count--;
return ret;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 402296670d3a..78d928f9d9f1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -291,7 +291,7 @@ config SX
config RIO
tristate "Specialix RIO system support"
- depends on SERIAL_NONSTANDARD && !64BIT
+ depends on SERIAL_NONSTANDARD
help
This is a driver for the Specialix RIO, a smart serial card which
drives an outboard box that can support up to 128 ports. Product
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f5b01c6d498e..fb919bfb2824 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -41,9 +41,9 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
-obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 0b9cf9c59a21..7c88c060a9e6 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -86,7 +86,7 @@ config AGP_NVIDIA
config AGP_SIS
tristate "SiS chipset support"
- depends on AGP && X86_32
+ depends on AGP
help
This option gives you AGP support for the GLX component of
X on Silicon Integrated Systems [SiS] chipsets.
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index 2b5838e64751..b4e00a343da9 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -46,12 +46,6 @@ struct vm_operations_struct alpha_core_agp_vm_ops = {
};
-static int alpha_core_agp_nop(void)
-{
- /* just return success */
- return 0;
-}
-
static int alpha_core_agp_fetch_size(void)
{
return alpha_core_agp_sizes[0].size;
@@ -120,6 +114,11 @@ static int alpha_core_agp_remove_memory(struct agp_memory *mem, off_t pg_start,
return status;
}
+static int alpha_core_agp_create_free_gatt_table(struct agp_bridge_data *a)
+{
+ return 0;
+}
+
struct agp_bridge_driver alpha_core_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = alpha_core_agp_sizes,
@@ -135,8 +134,8 @@ struct agp_bridge_driver alpha_core_agp_driver = {
.tlb_flush = alpha_core_agp_tlbflush,
.mask_memory = agp_generic_mask_memory,
.cache_flush = global_cache_flush,
- .create_gatt_table = alpha_core_agp_nop,
- .free_gatt_table = alpha_core_agp_nop,
+ .create_gatt_table = alpha_core_agp_create_free_gatt_table,
+ .free_gatt_table = alpha_core_agp_create_free_gatt_table,
.insert_memory = alpha_core_agp_insert_memory,
.remove_memory = alpha_core_agp_remove_memory,
.alloc_by_type = agp_generic_alloc_by_type,
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 36517d4d1ad9..ac3c33a2e37d 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -617,6 +617,9 @@ static int agp_amd64_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ if (pdev->vendor == PCI_VENDOR_ID_NVIDIA)
+ nforce3_agp_init(pdev);
+
return amd_8151_configure();
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 4e1891e2c035..a92ab53a1370 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -809,12 +809,10 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
case U32_APER_SIZE:
bridge->current_size = A_IDX32(bridge);
break;
- /* This case will never really happen. */
+ /* These cases will never really happen. */
case FIXED_APER_SIZE:
case LVL2_APER_SIZE:
default:
- bridge->current_size =
- bridge->current_size;
break;
}
temp = bridge->current_size;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index bddcae54b16d..61ac3809f997 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -736,7 +736,7 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
static int intel_i915_fetch_size(void)
{
struct aper_size_info_fixed *values;
- u32 temp, offset = 0;
+ u32 temp, offset;
#define I915_256MB_ADDRESS_MASK (1<<27)
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 9846defbddb4..1de1b12043bf 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -329,7 +329,7 @@ static int agp_uninorth_suspend(struct pci_dev *pdev)
/* turn off AGP on the bridge */
agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
- bridge->dev_private_data = (void *)cmd;
+ bridge->dev_private_data = (void *)(long)cmd;
if (cmd & PCI_AGP_COMMAND_AGP) {
printk("uninorth-agp: disabling AGP on bridge %s\n",
pci_name(pdev));
@@ -351,7 +351,7 @@ static int agp_uninorth_resume(struct pci_dev *pdev)
if (bridge == NULL)
return -ENODEV;
- command = (u32)bridge->dev_private_data;
+ command = (long)bridge->dev_private_data;
bridge->dev_private_data = NULL;
if (!(command & PCI_AGP_COMMAND_AGP))
return 0;
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 97b0a890ba7f..b8ec25d17478 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -345,6 +345,12 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata =
.chipset_name = "PT880",
},
+ /* PT880 Ultra */
+ {
+ .device_id = PCI_DEVICE_ID_VIA_PT880ULTRA,
+ .chipset_name = "PT880 Ultra",
+ },
+
/* PT890 */
{
.device_id = PCI_DEVICE_ID_VIA_8783_0,
@@ -511,6 +517,7 @@ static struct pci_device_id agp_via_pci_table[] = {
ID(PCI_DEVICE_ID_VIA_8763_0),
ID(PCI_DEVICE_ID_VIA_8378_0),
ID(PCI_DEVICE_ID_VIA_PT880),
+ ID(PCI_DEVICE_ID_VIA_PT880ULTRA),
ID(PCI_DEVICE_ID_VIA_8783_0),
ID(PCI_DEVICE_ID_VIA_PX8X0_0),
ID(PCI_DEVICE_ID_VIA_3269_0),
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index e1aadae00623..cb76e5ca9a23 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -889,7 +889,6 @@ extern int drm_lock_free(drm_device_t * dev,
/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request);
-extern int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request);
extern int drm_addmap(drm_device_t * dev, unsigned int offset,
unsigned int size, drm_map_type_t type,
drm_map_flags_t flags, drm_local_map_t ** map_ptr);
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
index fabc930c67a2..40bfd9b01e39 100644
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -503,8 +503,6 @@ int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
return agp_bind_memory(handle, start);
}
-EXPORT_SYMBOL(drm_agp_bind_memory);
-
/** Calls agp_unbind_memory() */
int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
{
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 8a9cf12e6183..006b06d29727 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -386,7 +386,6 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
return 0;
}
-EXPORT_SYMBOL(drm_rmmap_locked);
int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
{
@@ -398,7 +397,6 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
return ret;
}
-EXPORT_SYMBOL(drm_rmmap);
/* The rmmap ioctl appears to be unnecessary. All mappings are torn down on
* the last close of the device, and this is necessary for cleanup when things
@@ -1053,7 +1051,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
return 0;
}
-int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
+static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
@@ -1212,7 +1210,6 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
atomic_dec(&dev->buf_alloc);
return 0;
}
-EXPORT_SYMBOL(drm_addbufs_fb);
/**
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 68073e14fdec..9a842a36bb27 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -229,8 +229,6 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
return ret;
}
-EXPORT_SYMBOL(drm_get_dev);
-
/**
* Put a device minor number.
*
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index b108c7f913b2..26bdf2ca59d7 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -723,7 +723,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
dev_priv->scratch_ages[header.scratch.reg]++;
- ref_age_base = *(u32 **)cmdbuf->buf;
+ ref_age_base = (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
cmdbuf->buf += sizeof(u64);
cmdbuf->bufsz -= sizeof(u64);
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index d3a2bc36129b..588fca542a98 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -200,13 +200,13 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf,
/* first test allows optimizer to nuke this case for 32-bit machines */
if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
unsigned int uidata = data;
- retval = put_user(uidata, (unsigned long __user *)buf);
+ retval = put_user(uidata, (unsigned int __user *)buf) ?:
+ sizeof(unsigned int);
}
else {
- retval = put_user(data, (unsigned long __user *)buf);
+ retval = put_user(data, (unsigned long __user *)buf) ?:
+ sizeof(unsigned long);
}
- if (!retval)
- retval = sizeof(unsigned long);
out:
current->state = TASK_RUNNING;
remove_wait_queue(&gen_rtc_wait, &wait);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index b36eef0e9d19..02a7dd7a8a55 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1184,20 +1184,20 @@ static void port_outl(struct si_sm_io *io, unsigned int offset,
static void port_cleanup(struct smi_info *info)
{
unsigned int addr = info->io.addr_data;
- int mapsize;
+ int idx;
if (addr) {
- mapsize = ((info->io_size * info->io.regspacing)
- - (info->io.regspacing - info->io.regsize));
-
- release_region (addr, mapsize);
+ for (idx = 0; idx < info->io_size; idx++) {
+ release_region(addr + idx * info->io.regspacing,
+ info->io.regsize);
+ }
}
}
static int port_setup(struct smi_info *info)
{
unsigned int addr = info->io.addr_data;
- int mapsize;
+ int idx;
if (!addr)
return -ENODEV;
@@ -1225,16 +1225,22 @@ static int port_setup(struct smi_info *info)
return -EINVAL;
}
- /* Calculate the total amount of memory to claim. This is an
- * unusual looking calculation, but it avoids claiming any
- * more memory than it has to. It will claim everything
- * between the first address to the end of the last full
- * register. */
- mapsize = ((info->io_size * info->io.regspacing)
- - (info->io.regspacing - info->io.regsize));
-
- if (request_region(addr, mapsize, DEVICE_NAME) == NULL)
- return -EIO;
+ /* Some BIOSes reserve disjoint I/O regions in their ACPI
+ * tables. This causes problems when trying to register the
+ * entire I/O region. Therefore we must register each I/O
+ * port separately.
+ */
+ for (idx = 0; idx < info->io_size; idx++) {
+ if (request_region(addr + idx * info->io.regspacing,
+ info->io.regsize, DEVICE_NAME) == NULL) {
+ /* Undo allocations */
+ while (idx--) {
+ release_region(addr + idx * info->io.regspacing,
+ info->io.regsize);
+ }
+ return -EIO;
+ }
+ }
return 0;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 935670a3cd98..5755b7e5f187 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -860,9 +860,32 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc
}
/* by default, 300ms interval for combination release */
-static long brl_timeout = 300;
-MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)");
-module_param(brl_timeout, long, 0644);
+static unsigned brl_timeout = 300;
+MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
+module_param(brl_timeout, uint, 0644);
+
+static unsigned brl_nbchords = 1;
+MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
+module_param(brl_nbchords, uint, 0644);
+
+static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs)
+{
+ static unsigned long chords;
+ static unsigned committed;
+
+ if (!brl_nbchords)
+ k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs);
+ else {
+ committed |= pattern;
+ chords++;
+ if (chords == brl_nbchords) {
+ k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs);
+ chords = 0;
+ committed = 0;
+ }
+ }
+}
+
static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
{
static unsigned pressed,committing;
@@ -882,11 +905,6 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
if (value > 8)
return;
- if (brl_timeout < 0) {
- k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs);
- return;
- }
-
if (up_flag) {
if (brl_timeout) {
if (!committing ||
@@ -897,13 +915,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
pressed &= ~(1 << (value - 1));
if (!pressed) {
if (committing) {
- k_unicode(vc, BRL_UC_ROW | committing, 0, regs);
+ k_brlcommit(vc, committing, 0, regs);
committing = 0;
}
}
} else {
if (committing) {
- k_unicode(vc, BRL_UC_ROW | committing, 0, regs);
+ k_brlcommit(vc, committing, 0, regs);
committing = 0;
}
pressed &= ~(1 << (value - 1));
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 66719f9d294c..1fa9fa157c12 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -27,6 +27,7 @@
#include <linux/crash_dump.h>
#include <linux/backing-dev.h>
#include <linux/bootmem.h>
+#include <linux/pipe_fs_i.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -578,6 +579,18 @@ static ssize_t write_null(struct file * file, const char __user * buf,
return count;
}
+static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
+ struct splice_desc *sd)
+{
+ return sd->len;
+}
+
+static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+ loff_t *ppos, size_t len, unsigned int flags)
+{
+ return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
+}
+
#ifdef CONFIG_MMU
/*
* For fun, we are using the MMU for this.
@@ -785,6 +798,7 @@ static struct file_operations null_fops = {
.llseek = null_lseek,
.read = read_null,
.write = write_null,
+ .splice_write = splice_write_null,
};
#if defined(CONFIG_ISA) || !defined(__mc68000__)
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 8666171e187b..d3ba2f860ef0 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -271,7 +271,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
- if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
+ if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_REGISTER_IPC:"
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index ede365d05387..b9371d5bf790 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1384,8 +1384,10 @@ do_it_again:
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters.
*/
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
+ if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+ n_tty_set_room(tty);
check_unthrottle(tty);
+ }
if (b - buf >= minimum)
break;
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 02114a0bd0d9..eab5394da666 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -149,7 +149,7 @@ struct cm4000_dev {
#define ZERO_DEV(dev) \
memset(&dev->atr_csum,0, \
sizeof(struct cm4000_dev) - \
- /*link*/ sizeof(struct pcmcia_device) - \
+ /*link*/ sizeof(struct pcmcia_device *) - \
/*node*/ sizeof(dev_node_t) - \
/*atr*/ MAX_ATR*sizeof(char) - \
/*rbuf*/ 512*sizeof(char) - \
@@ -1981,10 +1981,6 @@ static int __init cmm_init(void)
if (!cmm_class)
return -1;
- rc = pcmcia_register_driver(&cm4000_driver);
- if (rc < 0)
- return rc;
-
major = register_chrdev(0, DEVICE_NAME, &cm4000_fops);
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
@@ -1992,6 +1988,12 @@ static int __init cmm_init(void)
return -1;
}
+ rc = pcmcia_register_driver(&cm4000_driver);
+ if (rc < 0) {
+ unregister_chrdev(major, DEVICE_NAME);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 29efa64580a8..47a8465bf95b 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -724,16 +724,19 @@ static int __init cm4040_init(void)
if (!cmx_class)
return -1;
- rc = pcmcia_register_driver(&reader_driver);
- if (rc < 0)
- return rc;
-
major = register_chrdev(0, DEVICE_NAME, &reader_fops);
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
return -1;
}
+
+ rc = pcmcia_register_driver(&reader_driver);
+ if (rc < 0) {
+ unregister_chrdev(major, DEVICE_NAME);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
index 3ec73d1a279a..179cdbea712b 100644
--- a/drivers/char/rio/host.h
+++ b/drivers/char/rio/host.h
@@ -33,12 +33,6 @@
#ifndef __rio_host_h__
#define __rio_host_h__
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_host_h_sccs_ = "@(#)host.h 1.2";
-#endif
-#endif
-
/*
** the host structure - one per host card in the system.
*/
@@ -77,9 +71,6 @@ struct Host {
#define RC_STARTUP 1
#define RC_RUNNING 2
#define RC_STUFFED 3
-#define RC_SOMETHING 4
-#define RC_SOMETHING_NEW 5
-#define RC_SOMETHING_ELSE 6
#define RC_READY 7
#define RUN_STATE 7
/*
diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c
index acda9326c2ef..290143addd34 100644
--- a/drivers/char/rio/rioboot.c
+++ b/drivers/char/rio/rioboot.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/termios.h>
#include <linux/serial.h>
+#include <linux/vmalloc.h>
#include <asm/semaphore.h>
#include <linux/generic_serial.h>
#include <linux/errno.h>
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index d31aba62bb7f..75b2557c37ec 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -1394,14 +1394,17 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
return RIO_FAIL;
}
- if (((int) ((char) PortP->InUse) == -1) || !(CmdBlkP = RIOGetCmdBlk())) {
- rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", Cmd, PortP->PortNum);
+ if ((PortP->InUse == (typeof(PortP->InUse))-1) ||
+ !(CmdBlkP = RIOGetCmdBlk())) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block "
+ "for command %d on port %d\n", Cmd, PortP->PortNum);
return RIO_FAIL;
}
- rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", CmdBlkP, PortP->InUse);
+ rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n",
+ CmdBlkP, PortP->InUse);
- PktCmdP = (struct PktCmd_M *) &CmdBlkP->Packet.data[0];
+ PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0];
CmdBlkP->Packet.src_unit = 0;
if (PortP->SecondBlock)
@@ -1425,38 +1428,46 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
switch (Cmd) {
case MEMDUMP:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p (addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
+ "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
PktCmdP->SubCommand = MEMDUMP;
PktCmdP->SubAddr = SubCmd.Addr;
break;
case FCLOSE:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
+ CmdBlkP);
break;
case READ_REGISTER:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
+ "command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
PktCmdP->SubCommand = READ_REGISTER;
PktCmdP->SubAddr = SubCmd.Addr;
break;
case RESUME:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
+ CmdBlkP);
break;
case RFLUSH:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
+ CmdBlkP);
CmdBlkP->PostFuncP = RIORFlushEnable;
break;
case SUSPEND:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
+ CmdBlkP);
break;
case MGET:
- rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
+ CmdBlkP);
break;
case MSET:
case MBIC:
case MBIS:
CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
- rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
+ "blk %p\n", CmdBlkP);
break;
case WFLUSH:
@@ -1465,12 +1476,14 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
** allowed then we should not bother sending any more to the
** RTA.
*/
- if ((int) ((char) PortP->WflushFlag) == (int) -1) {
- rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!");
+ if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, "
+ "WflushFlag about to wrap!");
RIOFreeCmdBlk(CmdBlkP);
return (RIO_FAIL);
} else {
- rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command blk %p\n", CmdBlkP);
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command "
+ "blk %p\n", CmdBlkP);
CmdBlkP->PostFuncP = RIOWFlushMark;
}
break;
diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h
index 14b83fae75c8..e8af5b30519e 100644
--- a/drivers/char/rio/rioioctl.h
+++ b/drivers/char/rio/rioioctl.h
@@ -33,10 +33,6 @@
#ifndef __rioioctl_h__
#define __rioioctl_h__
-#ifdef SCCS_LABELS
-static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2";
-#endif
-
/*
** RIO device driver - user ioctls and associated structures.
*/
@@ -44,55 +40,13 @@ static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2";
struct portStats {
int port;
int gather;
- ulong txchars;
- ulong rxchars;
- ulong opens;
- ulong closes;
- ulong ioctls;
+ unsigned long txchars;
+ unsigned long rxchars;
+ unsigned long opens;
+ unsigned long closes;
+ unsigned long ioctls;
};
-
-#define rIOC ('r'<<8)
-#define TCRIOSTATE (rIOC | 1)
-#define TCRIOXPON (rIOC | 2)
-#define TCRIOXPOFF (rIOC | 3)
-#define TCRIOXPCPS (rIOC | 4)
-#define TCRIOXPRINT (rIOC | 5)
-#define TCRIOIXANYON (rIOC | 6)
-#define TCRIOIXANYOFF (rIOC | 7)
-#define TCRIOIXONON (rIOC | 8)
-#define TCRIOIXONOFF (rIOC | 9)
-#define TCRIOMBIS (rIOC | 10)
-#define TCRIOMBIC (rIOC | 11)
-#define TCRIOTRIAD (rIOC | 12)
-#define TCRIOTSTATE (rIOC | 13)
-
-/*
-** 15.10.1998 ARG - ESIL 0761 part fix
-** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS
-** appears to not support hardware flow control).
-*/
-#define TCRIOCTSFLOWEN (rIOC | 14) /* enable CTS flow control */
-#define TCRIOCTSFLOWDIS (rIOC | 15) /* disable CTS flow control */
-#define TCRIORTSFLOWEN (rIOC | 16) /* enable RTS flow control */
-#define TCRIORTSFLOWDIS (rIOC | 17) /* disable RTS flow control */
-
-/*
-** 09.12.1998 ARG - ESIL 0776 part fix
-** Definition for 'RIOC' also appears in daemon.h, so we'd better do a
-** #ifndef here first.
-** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now
-** allowed to be used by customers.
-**
-** 05.02.1999 ARG -
-** This is what I've decied to do with ioctls etc., which are intended to be
-** invoked from users applications :
-** Anything that needs to be defined here will be removed from daemon.h, that
-** way it won't end up having to be defined/maintained in two places. The only
-** consequence of this is that this file should now be #include'd by daemon.h
-**
-** 'stats' ioctls now #define'd here as they are to be used by customers.
-*/
#define RIOC ('R'<<8)|('i'<<16)|('o'<<24)
#define RIO_QUICK_CHECK (RIOC | 105)
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index b543821d8cb4..56c8243cdb73 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -390,7 +390,8 @@ scdrv_init(void)
format_module_id(devnamep, geo_module(geoid),
MODULE_FORMAT_BRIEF);
devnamep = devname + strlen(devname);
- sprintf(devnamep, "#%d", geo_slab(geoid));
+ sprintf(devnamep, "^%d#%d", geo_slot(geoid),
+ geo_slab(geoid));
/* allocate sysctl device data */
scd = kzalloc(sizeof (struct sysctl_data_s),
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index eb2eb3e12d6a..079db5a935a1 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -515,7 +515,7 @@ tipar_init_module(void)
err = PTR_ERR(tipar_class);
goto out_chrdev;
}
- if (parport_register_driver(&tipar_driver) || tp_count == 0) {
+ if (parport_register_driver(&tipar_driver)) {
printk(KERN_ERR "tipar: unable to register with parport\n");
err = -EIO;
goto out_class;
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index a6873bf89ffa..fe00c7dfb649 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -20,9 +20,18 @@ config TCG_TPM
Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI
and CONFIG_PNPACPI.
+config TCG_TIS
+ tristate "TPM Interface Specification 1.2 Interface"
+ depends on TCG_TPM && PNPACPI
+ ---help---
+ If you have a TPM security chip that is compliant with the
+ TCG TIS 1.2 TPM specification say Yes and it will be accessible
+ from within Linux. To compile this driver as a module, choose
+ M here; the module will be called tpm_tis.
+
config TCG_NSC
tristate "National Semiconductor TPM Interface"
- depends on TCG_TPM
+ depends on TCG_TPM && PNPACPI
---help---
If you have a TPM security chip from National Semicondutor
say Yes and it will be accessible from within Linux. To
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index ba4582d160fd..ea3a1e02a824 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_TCG_TPM) += tpm.o
ifdef CONFIG_ACPI
obj-$(CONFIG_TCG_TPM) += tpm_bios.o
endif
+obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 5a3870477ef1..6889e7db3aff 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -32,12 +32,291 @@ enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 2048,
TPM_NUM_DEVICES = 256,
- TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
};
+enum tpm_duration {
+ TPM_SHORT = 0,
+ TPM_MEDIUM = 1,
+ TPM_LONG = 2,
+ TPM_UNDEFINED,
+};
+
+#define TPM_MAX_ORDINAL 243
+#define TPM_MAX_PROTECTED_ORDINAL 12
+#define TPM_PROTECTED_ORDINAL_MASK 0xFF
+
static LIST_HEAD(tpm_chip_list);
static DEFINE_SPINLOCK(driver_lock);
-static int dev_mask[TPM_NUM_MASK_ENTRIES];
+static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+
+/*
+ * Array with one entry per ordinal defining the maximum amount
+ * of time the chip could take to return the result. The ordinal
+ * designation of short, medium or long is defined in a table in
+ * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
+ * values of the SHORT, MEDIUM, and LONG durations are retrieved
+ * from the chip during initialization with a call to tpm_get_timeouts.
+ */
+static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+};
+
+static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_LONG,
+ TPM_MEDIUM, /* 15 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT, /* 20 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT, /* 25 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 30 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 35 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 40 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 45 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_MEDIUM, /* 50 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 55 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 60 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 65 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 70 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 75 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 80 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 85 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 90 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 95 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 100 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 105 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 110 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 115 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 120 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 125 */
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 130 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 135 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 140 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 145 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 150 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 155 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 160 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 165 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 170 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 175 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 180 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM, /* 185 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 190 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 195 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 200 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 205 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 210 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 215 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 220 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 225 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 230 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 235 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 240 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+};
static void user_reader_timeout(unsigned long ptr)
{
@@ -46,7 +325,7 @@ static void user_reader_timeout(unsigned long ptr)
schedule_work(&chip->work);
}
-static void timeout_work(void * ptr)
+static void timeout_work(void *ptr)
{
struct tpm_chip *chip = ptr;
@@ -57,17 +336,43 @@ static void timeout_work(void * ptr)
}
/*
+ * Returns max number of jiffies to wait
+ */
+unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
+ u32 ordinal)
+{
+ int duration_idx = TPM_UNDEFINED;
+ int duration = 0;
+
+ if (ordinal < TPM_MAX_ORDINAL)
+ duration_idx = tpm_ordinal_duration[ordinal];
+ else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+ TPM_MAX_PROTECTED_ORDINAL)
+ duration_idx =
+ tpm_protected_ordinal_duration[ordinal &
+ TPM_PROTECTED_ORDINAL_MASK];
+
+ if (duration_idx != TPM_UNDEFINED)
+ duration = chip->vendor.duration[duration_idx];
+ if (duration <= 0)
+ return 2 * 60 * HZ;
+ else
+ return duration;
+}
+EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
+
+/*
* Internal kernel interface to transmit TPM commands
*/
static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
size_t bufsiz)
{
ssize_t rc;
- u32 count;
+ u32 count, ordinal;
unsigned long stop;
count = be32_to_cpu(*((__be32 *) (buf + 2)));
-
+ ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
@@ -78,21 +383,23 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
down(&chip->tpm_mutex);
- if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+ if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
dev_err(chip->dev,
"tpm_transmit: tpm_send: error %zd\n", rc);
goto out;
}
- stop = jiffies + 2 * 60 * HZ;
+ if (chip->vendor.irq)
+ goto out_recv;
+
+ stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
do {
- u8 status = chip->vendor->status(chip);
- if ((status & chip->vendor->req_complete_mask) ==
- chip->vendor->req_complete_val) {
+ u8 status = chip->vendor.status(chip);
+ if ((status & chip->vendor.req_complete_mask) ==
+ chip->vendor.req_complete_val)
goto out_recv;
- }
- if ((status == chip->vendor->req_canceled)) {
+ if ((status == chip->vendor.req_canceled)) {
dev_err(chip->dev, "Operation Canceled\n");
rc = -ECANCELED;
goto out;
@@ -102,14 +409,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
rmb();
} while (time_before(jiffies, stop));
-
- chip->vendor->cancel(chip);
+ chip->vendor.cancel(chip);
dev_err(chip->dev, "Operation Timed out\n");
rc = -ETIME;
goto out;
out_recv:
- rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+ rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz);
if (rc < 0)
dev_err(chip->dev,
"tpm_transmit: tpm_recv: error %zd\n", rc);
@@ -119,17 +425,247 @@ out:
}
#define TPM_DIGEST_SIZE 20
-#define CAP_PCR_RESULT_SIZE 18
-static const u8 cap_pcr[] = {
+#define TPM_ERROR_SIZE 10
+#define TPM_RET_CODE_IDX 6
+#define TPM_GET_CAP_RET_SIZE_IDX 10
+#define TPM_GET_CAP_RET_UINT32_1_IDX 14
+#define TPM_GET_CAP_RET_UINT32_2_IDX 18
+#define TPM_GET_CAP_RET_UINT32_3_IDX 22
+#define TPM_GET_CAP_RET_UINT32_4_IDX 26
+#define TPM_GET_CAP_PERM_DISABLE_IDX 16
+#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
+#define TPM_GET_CAP_RET_BOOL_1_IDX 14
+#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16
+
+#define TPM_CAP_IDX 13
+#define TPM_CAP_SUBCAP_IDX 21
+
+enum tpm_capabilities {
+ TPM_CAP_FLAG = 4,
+ TPM_CAP_PROP = 5,
+};
+
+enum tpm_sub_capabilities {
+ TPM_CAP_PROP_PCR = 0x1,
+ TPM_CAP_PROP_MANUFACTURER = 0x3,
+ TPM_CAP_FLAG_PERM = 0x8,
+ TPM_CAP_FLAG_VOL = 0x9,
+ TPM_CAP_PROP_OWNER = 0x11,
+ TPM_CAP_PROP_TIS_TIMEOUT = 0x15,
+ TPM_CAP_PROP_TIS_DURATION = 0x20,
+};
+
+/*
+ * This is a semi generic GetCapability command for use
+ * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
+ * and their associated sub_capabilities.
+ */
+
+static const u8 tpm_cap[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 5,
- 0, 0, 0, 4,
- 0, 0, 1, 1
+ 0, 0, 0, 0, /* TPM_CAP_<TYPE> */
+ 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */
+ 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */
};
-#define READ_PCR_RESULT_SIZE 30
+static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len,
+ char *desc)
+{
+ int err;
+
+ len = tpm_transmit(chip, data, len);
+ if (len < 0)
+ return len;
+ if (len == TPM_ERROR_SIZE) {
+ err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)));
+ dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+ return err;
+ }
+ return 0;
+}
+
+void tpm_gen_interrupt(struct tpm_chip *chip)
+{
+ u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
+ ssize_t rc;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the timeouts");
+}
+EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
+
+void tpm_get_timeouts(struct tpm_chip *chip)
+{
+ u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)];
+ ssize_t rc;
+ u32 timeout;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the timeouts");
+ if (rc)
+ goto duration;
+
+ if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
+ != 4 * sizeof(u32))
+ goto duration;
+
+ /* Don't overwrite default if value is 0 */
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
+ if (timeout)
+ chip->vendor.timeout_a = msecs_to_jiffies(timeout);
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
+ if (timeout)
+ chip->vendor.timeout_b = msecs_to_jiffies(timeout);
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
+ if (timeout)
+ chip->vendor.timeout_c = msecs_to_jiffies(timeout);
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
+ if (timeout)
+ chip->vendor.timeout_d = msecs_to_jiffies(timeout);
+
+duration:
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the durations");
+ if (rc)
+ return;
+
+ if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX)))
+ != 3 * sizeof(u32))
+ return;
+
+ chip->vendor.duration[TPM_SHORT] =
+ msecs_to_jiffies(be32_to_cpu
+ (*((__be32 *) (data +
+ TPM_GET_CAP_RET_UINT32_1_IDX))));
+ chip->vendor.duration[TPM_MEDIUM] =
+ msecs_to_jiffies(be32_to_cpu
+ (*((__be32 *) (data +
+ TPM_GET_CAP_RET_UINT32_2_IDX))));
+ chip->vendor.duration[TPM_LONG] =
+ msecs_to_jiffies(be32_to_cpu
+ (*((__be32 *) (data +
+ TPM_GET_CAP_RET_UINT32_3_IDX))));
+}
+EXPORT_SYMBOL_GPL(tpm_get_timeouts);
+
+void tpm_continue_selftest(struct tpm_chip *chip)
+{
+ u8 data[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 10, /* length */
+ 0, 0, 0, 83, /* TPM_ORD_GetCapability */
+ };
+
+ tpm_transmit(chip, data, sizeof(data));
+}
+EXPORT_SYMBOL_GPL(tpm_continue_selftest);
+
+ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
+ char *buf)
+{
+ u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
+ ssize_t rc;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attemtping to determine the permanent state");
+ if (rc)
+ return 0;
+ return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
+}
+EXPORT_SYMBOL_GPL(tpm_show_enabled);
+
+ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
+ char *buf)
+{
+ u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)];
+ ssize_t rc;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attemtping to determine the permanent state");
+ if (rc)
+ return 0;
+ return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]);
+}
+EXPORT_SYMBOL_GPL(tpm_show_active);
+
+ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
+ char *buf)
+{
+ u8 data[sizeof(tpm_cap)];
+ ssize_t rc;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the owner state");
+ if (rc)
+ return 0;
+ return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
+}
+EXPORT_SYMBOL_GPL(tpm_show_owned);
+
+ssize_t tpm_show_temp_deactivated(struct device * dev,
+ struct device_attribute * attr, char *buf)
+{
+ u8 data[sizeof(tpm_cap)];
+ ssize_t rc;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the temporary state");
+ if (rc)
+ return 0;
+ return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]);
+}
+EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
+
static const u8 pcrread[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 14, /* length */
@@ -140,8 +676,8 @@ static const u8 pcrread[] = {
ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
char *buf)
{
- u8 data[READ_PCR_RESULT_SIZE];
- ssize_t len;
+ u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)];
+ ssize_t rc;
int i, j, num_pcrs;
__be32 index;
char *str = buf;
@@ -150,29 +686,24 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
if (chip == NULL)
return -ENODEV;
- memcpy(data, cap_pcr, sizeof(cap_pcr));
- if ((len = tpm_transmit(chip, data, sizeof(data)))
- < CAP_PCR_RESULT_SIZE) {
- dev_dbg(chip->dev, "A TPM error (%d) occurred "
- "attempting to determine the number of PCRS\n",
- be32_to_cpu(*((__be32 *) (data + 6))));
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
+
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the number of PCRS");
+ if (rc)
return 0;
- }
num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
-
for (i = 0; i < num_pcrs; i++) {
memcpy(data, pcrread, sizeof(pcrread));
index = cpu_to_be32(i);
memcpy(data + 10, &index, 4);
- if ((len = tpm_transmit(chip, data, sizeof(data)))
- < READ_PCR_RESULT_SIZE){
- dev_dbg(chip->dev, "A TPM error (%d) occurred"
- " attempting to read PCR %d of %d\n",
- be32_to_cpu(*((__be32 *) (data + 6))),
- i, num_pcrs);
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to read a PCR");
+ if (rc)
goto out;
- }
str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", *(data + 10 + j));
@@ -194,7 +725,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
char *buf)
{
u8 *data;
- ssize_t len;
+ ssize_t err;
int i, rc;
char *str = buf;
@@ -208,14 +739,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
memcpy(data, readpubek, sizeof(readpubek));
- if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
- READ_PUBEK_RESULT_SIZE) {
- dev_dbg(chip->dev, "A TPM error (%d) occurred "
- "attempting to read the PUBEK\n",
- be32_to_cpu(*((__be32 *) (data + 6))));
- rc = 0;
+ err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
+ "attempting to read the PUBEK");
+ if (err)
goto out;
- }
/*
ignore header 10 bytes
@@ -245,67 +772,110 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
if ((i + 1) % 16 == 0)
str += sprintf(str, "\n");
}
- rc = str - buf;
out:
+ rc = str - buf;
kfree(data);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_show_pubek);
-#define CAP_VER_RESULT_SIZE 18
+#define CAP_VERSION_1_1 6
+#define CAP_VERSION_1_2 0x1A
+#define CAP_VERSION_IDX 13
static const u8 cap_version[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 18, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 6,
+ 0, 0, 0, 0,
0, 0, 0, 0
};
-#define CAP_MANUFACTURER_RESULT_SIZE 18
-static const u8 cap_manufacturer[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 22, /* length */
- 0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 5,
- 0, 0, 0, 4,
- 0, 0, 1, 3
-};
-
ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
char *buf)
{
- u8 data[sizeof(cap_manufacturer)];
- ssize_t len;
+ u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+ ssize_t rc;
char *str = buf;
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip == NULL)
return -ENODEV;
- memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- CAP_MANUFACTURER_RESULT_SIZE)
- return len;
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the manufacturer");
+ if (rc)
+ return 0;
str += sprintf(str, "Manufacturer: 0x%x\n",
- be32_to_cpu(*((__be32 *) (data + 14))));
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
memcpy(data, cap_version, sizeof(cap_version));
+ data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
+ rc = transmit_cmd(chip, data, sizeof(data),
+ "attempting to determine the 1.1 version");
+ if (rc)
+ goto out;
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- CAP_VER_RESULT_SIZE)
- return len;
-
- str +=
- sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
- (int) data[14], (int) data[15], (int) data[16],
- (int) data[17]);
+ str += sprintf(str,
+ "TCG version: %d.%d\nFirmware version: %d.%d\n",
+ (int) data[14], (int) data[15], (int) data[16],
+ (int) data[17]);
+out:
return str - buf;
}
EXPORT_SYMBOL_GPL(tpm_show_caps);
+ssize_t tpm_show_caps_1_2(struct device * dev,
+ struct device_attribute * attr, char *buf)
+{
+ u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)];
+ ssize_t len;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <=
+ TPM_ERROR_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the manufacturer\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ return 0;
+ }
+
+ str += sprintf(str, "Manufacturer: 0x%x\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+
+ memcpy(data, cap_version, sizeof(cap_version));
+ data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <=
+ TPM_ERROR_SIZE) {
+ dev_err(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the 1.2 version\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ goto out;
+ }
+ str += sprintf(str,
+ "TCG version: %d.%d\nFirmware version: %d.%d\n",
+ (int) data[16], (int) data[17], (int) data[18],
+ (int) data[19]);
+
+out:
+ return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
+
ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -313,7 +883,7 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
if (chip == NULL)
return 0;
- chip->vendor->cancel(chip);
+ chip->vendor.cancel(chip);
return count;
}
EXPORT_SYMBOL_GPL(tpm_store_cancel);
@@ -329,7 +899,7 @@ int tpm_open(struct inode *inode, struct file *file)
spin_lock(&driver_lock);
list_for_each_entry(pos, &tpm_chip_list, list) {
- if (pos->vendor->miscdev.minor == minor) {
+ if (pos->vendor.miscdev.minor == minor) {
chip = pos;
break;
}
@@ -387,7 +957,7 @@ int tpm_release(struct inode *inode, struct file *file)
EXPORT_SYMBOL_GPL(tpm_release);
ssize_t tpm_write(struct file *file, const char __user *buf,
- size_t size, loff_t * off)
+ size_t size, loff_t *off)
{
struct tpm_chip *chip = file->private_data;
int in_size = size, out_size;
@@ -419,11 +989,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
return in_size;
}
-
EXPORT_SYMBOL_GPL(tpm_write);
-ssize_t tpm_read(struct file * file, char __user *buf,
- size_t size, loff_t * off)
+ssize_t tpm_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
{
struct tpm_chip *chip = file->private_data;
int ret_size;
@@ -462,14 +1031,13 @@ void tpm_remove_hardware(struct device *dev)
spin_unlock(&driver_lock);
dev_set_drvdata(dev, NULL);
- misc_deregister(&chip->vendor->miscdev);
- kfree(chip->vendor->miscdev.name);
+ misc_deregister(&chip->vendor.miscdev);
+ kfree(chip->vendor.miscdev.name);
- sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
+ sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
tpm_bios_log_teardown(chip->bios_dir);
- dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
- ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
+ clear_bit(chip->dev_num, dev_mask);
kfree(chip);
@@ -520,18 +1088,18 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
* upon errant exit from this function specific probe function should call
* pci_disable_device
*/
-int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
+ *entry)
{
#define DEVNAME_SIZE 7
char *devname;
struct tpm_chip *chip;
- int i, j;
/* Driver specific per-device data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
- return -ENOMEM;
+ return NULL;
init_MUTEX(&chip->buffer_mutex);
init_MUTEX(&chip->tpm_mutex);
@@ -543,45 +1111,37 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry)
chip->user_read_timer.function = user_reader_timeout;
chip->user_read_timer.data = (unsigned long) chip;
- chip->vendor = entry;
-
- chip->dev_num = -1;
+ memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
- for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
- for (j = 0; j < 8 * sizeof(int); j++)
- if ((dev_mask[i] & (1 << j)) == 0) {
- chip->dev_num =
- i * TPM_NUM_MASK_ENTRIES + j;
- dev_mask[i] |= 1 << j;
- goto dev_num_search_complete;
- }
+ chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
-dev_num_search_complete:
- if (chip->dev_num < 0) {
+ if (chip->dev_num >= TPM_NUM_DEVICES) {
dev_err(dev, "No available tpm device numbers\n");
kfree(chip);
- return -ENODEV;
+ return NULL;
} else if (chip->dev_num == 0)
- chip->vendor->miscdev.minor = TPM_MINOR;
+ chip->vendor.miscdev.minor = TPM_MINOR;
else
- chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
+ chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
+
+ set_bit(chip->dev_num, dev_mask);
devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
- chip->vendor->miscdev.name = devname;
+ chip->vendor.miscdev.name = devname;
- chip->vendor->miscdev.dev = dev;
+ chip->vendor.miscdev.dev = dev;
chip->dev = get_device(dev);
- if (misc_register(&chip->vendor->miscdev)) {
+ if (misc_register(&chip->vendor.miscdev)) {
dev_err(chip->dev,
"unable to misc_register %s, minor %d\n",
- chip->vendor->miscdev.name,
- chip->vendor->miscdev.minor);
+ chip->vendor.miscdev.name,
+ chip->vendor.miscdev.minor);
put_device(dev);
+ clear_bit(chip->dev_num, dev_mask);
kfree(chip);
- dev_mask[i] &= !(1 << j);
- return -ENODEV;
+ return NULL;
}
spin_lock(&driver_lock);
@@ -592,11 +1152,11 @@ dev_num_search_complete:
spin_unlock(&driver_lock);
- sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
+ sysfs_create_group(&dev->kobj, chip->vendor.attr_group);
chip->bios_dir = tpm_bios_log_setup(devname);
- return 0;
+ return chip;
}
EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index dec0224b4478..050ced247f68 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -42,18 +42,30 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
char *);
extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
char *);
+extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr,
+ char *);
extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
const char *, size_t);
+extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_temp_deactivated(struct device *,
+ struct device_attribute *attr, char *);
struct tpm_chip;
struct tpm_vendor_specific {
- u8 req_complete_mask;
- u8 req_complete_val;
- u8 req_canceled;
+ const u8 req_complete_mask;
+ const u8 req_complete_val;
+ const u8 req_canceled;
void __iomem *iobase; /* ioremapped address */
unsigned long base; /* TPM base address */
+ int irq;
+
int region_size;
int have_region;
@@ -63,6 +75,13 @@ struct tpm_vendor_specific {
u8 (*status) (struct tpm_chip *);
struct miscdevice miscdev;
struct attribute_group *attr_group;
+ struct list_head list;
+ int locality;
+ unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
+ unsigned long duration[3]; /* jiffies */
+
+ wait_queue_head_t read_queue;
+ wait_queue_head_t int_queue;
};
struct tpm_chip {
@@ -81,13 +100,15 @@ struct tpm_chip {
struct work_struct work;
struct semaphore tpm_mutex; /* tpm is processing */
- struct tpm_vendor_specific *vendor;
+ struct tpm_vendor_specific vendor;
struct dentry **bios_dir;
struct list_head list;
};
+#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
+
static inline int tpm_read_index(int base, int index)
{
outb(index, base);
@@ -100,8 +121,12 @@ static inline void tpm_write_index(int base, int index, int value)
outb(value & 0xFF, base+1);
}
-extern int tpm_register_hardware(struct device *,
- struct tpm_vendor_specific *);
+extern void tpm_get_timeouts(struct tpm_chip *);
+extern void tpm_gen_interrupt(struct tpm_chip *);
+extern void tpm_continue_selftest(struct tpm_chip *);
+extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
+extern struct tpm_chip* tpm_register_hardware(struct device *,
+ const struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
@@ -115,7 +140,7 @@ extern int tpm_pm_resume(struct device *);
extern struct dentry ** tpm_bios_log_setup(char *);
extern void tpm_bios_log_teardown(struct dentry **);
#else
-static inline struct dentry* tpm_bios_log_setup(char *name)
+static inline struct dentry ** tpm_bios_log_setup(char *name)
{
return NULL;
}
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index ff3654964fe3..58a258cec153 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO;
for (i = 0; i < 6; i++) {
- status = ioread8(chip->vendor->iobase + 1);
+ status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading header\n");
return -EIO;
}
- *buf++ = ioread8(chip->vendor->iobase);
+ *buf++ = ioread8(chip->vendor.iobase);
}
/* size of the data received */
@@ -63,7 +63,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
dev_err(chip->dev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
- status = ioread8(chip->vendor->iobase + 1);
+ status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading data\n");
return -EIO;
@@ -74,16 +74,16 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read all the data available */
for (; i < size; i++) {
- status = ioread8(chip->vendor->iobase + 1);
+ status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading data\n");
return -EIO;
}
- *buf++ = ioread8(chip->vendor->iobase);
+ *buf++ = ioread8(chip->vendor.iobase);
}
/* make sure data available is gone */
- status = ioread8(chip->vendor->iobase + 1);
+ status = ioread8(chip->vendor.iobase + 1);
if (status & ATML_STATUS_DATA_AVAIL) {
dev_err(chip->dev, "data available is stuck\n");
@@ -100,7 +100,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
dev_dbg(chip->dev, "tpm_atml_send:\n");
for (i = 0; i < count; i++) {
dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
- iowrite8(buf[i], chip->vendor->iobase);
+ iowrite8(buf[i], chip->vendor.iobase);
}
return count;
@@ -108,12 +108,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
static void tpm_atml_cancel(struct tpm_chip *chip)
{
- iowrite8(ATML_STATUS_ABORT, chip->vendor->iobase + 1);
+ iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1);
}
static u8 tpm_atml_status(struct tpm_chip *chip)
{
- return ioread8(chip->vendor->iobase + 1);
+ return ioread8(chip->vendor.iobase + 1);
}
static struct file_operations atmel_ops = {
@@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] = {
static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
-static struct tpm_vendor_specific tpm_atmel = {
+static const struct tpm_vendor_specific tpm_atmel = {
.recv = tpm_atml_recv,
.send = tpm_atml_send,
.cancel = tpm_atml_cancel,
@@ -159,10 +159,10 @@ static void atml_plat_remove(void)
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
if (chip) {
- if (chip->vendor->have_region)
- atmel_release_region(chip->vendor->base,
- chip->vendor->region_size);
- atmel_put_base_addr(chip->vendor);
+ if (chip->vendor.have_region)
+ atmel_release_region(chip->vendor.base,
+ chip->vendor.region_size);
+ atmel_put_base_addr(chip->vendor.iobase);
tpm_remove_hardware(chip->dev);
platform_device_unregister(pdev);
}
@@ -179,18 +179,22 @@ static struct device_driver atml_drv = {
static int __init init_atmel(void)
{
int rc = 0;
+ void __iomem *iobase = NULL;
+ int have_region, region_size;
+ unsigned long base;
+ struct tpm_chip *chip;
driver_register(&atml_drv);
- if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) {
+ if ((iobase = atmel_get_base_addr(&base, &region_size)) == NULL) {
rc = -ENODEV;
goto err_unreg_drv;
}
- tpm_atmel.have_region =
+ have_region =
(atmel_request_region
- (tpm_atmel.base, tpm_atmel.region_size,
- "tpm_atmel0") == NULL) ? 0 : 1;
+ (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
+
if (IS_ERR
(pdev =
@@ -199,17 +203,25 @@ static int __init init_atmel(void)
goto err_rel_reg;
}
- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0)
+ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
+ rc = -ENODEV;
goto err_unreg_dev;
+ }
+
+ chip->vendor.iobase = iobase;
+ chip->vendor.base = base;
+ chip->vendor.have_region = have_region;
+ chip->vendor.region_size = region_size;
+
return 0;
err_unreg_dev:
platform_device_unregister(pdev);
err_rel_reg:
- atmel_put_base_addr(&tpm_atmel);
- if (tpm_atmel.have_region)
- atmel_release_region(tpm_atmel.base,
- tpm_atmel.region_size);
+ atmel_put_base_addr(iobase);
+ if (have_region)
+ atmel_release_region(base,
+ region_size);
err_unreg_drv:
driver_unregister(&atml_drv);
return rc;
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index d3478aaadd77..2e68eeb8a2cd 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -28,13 +28,12 @@
#define atmel_request_region request_mem_region
#define atmel_release_region release_mem_region
-static inline void atmel_put_base_addr(struct tpm_vendor_specific
- *vendor)
+static inline void atmel_put_base_addr(void __iomem *iobase)
{
- iounmap(vendor->iobase);
+ iounmap(iobase);
}
-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor)
+static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
{
struct device_node *dn;
unsigned long address, size;
@@ -71,9 +70,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor)
else
size = reg[naddrc];
- vendor->base = address;
- vendor->region_size = size;
- return ioremap(vendor->base, vendor->region_size);
+ *base = address;
+ *region_size = size;
+ return ioremap(*base, *region_size);
}
#else
#define atmel_getb(chip, offset) inb(chip->vendor->base + offset)
@@ -106,14 +105,12 @@ static int atmel_verify_tpm11(void)
return 0;
}
-static inline void atmel_put_base_addr(struct tpm_vendor_specific
- *vendor)
+static inline void atmel_put_base_addr(void __iomem *iobase)
{
}
/* Determine where to talk to device */
-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific
- *vendor)
+static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
{
int lo, hi;
@@ -123,9 +120,9 @@ static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific
lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
- vendor->base = (hi << 8) | lo;
- vendor->region_size = 2;
+ *base = (hi << 8) | lo;
+ *region_size = 2;
- return ioport_map(vendor->base, vendor->region_size);
+ return ioport_map(*base, *region_size);
}
#endif
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 537aa45d8c67..a611972024e6 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -29,6 +29,11 @@
#define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
+enum bios_platform_class {
+ BIOS_CLIENT = 0x00,
+ BIOS_SERVER = 0x01,
+};
+
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
@@ -36,9 +41,18 @@ struct tpm_bios_log {
struct acpi_tcpa {
struct acpi_table_header hdr;
- u16 reserved;
- u32 log_max_len __attribute__ ((packed));
- u32 log_start_addr __attribute__ ((packed));
+ u16 platform_class;
+ union {
+ struct client_hdr {
+ u32 log_max_len __attribute__ ((packed));
+ u64 log_start_addr __attribute__ ((packed));
+ } client;
+ struct server_hdr {
+ u16 reserved;
+ u64 log_max_len __attribute__ ((packed));
+ u64 log_start_addr __attribute__ ((packed));
+ } server;
+ };
};
struct tcpa_event {
@@ -91,6 +105,12 @@ static const char* tcpa_event_type_strings[] = {
"Non-Host Info"
};
+struct tcpa_pc_event {
+ u32 event_id;
+ u32 event_size;
+ u8 event_data[0];
+};
+
enum tcpa_pc_event_ids {
SMBIOS = 1,
BIS_CERT,
@@ -100,14 +120,15 @@ enum tcpa_pc_event_ids {
NVRAM,
OPTION_ROM_EXEC,
OPTION_ROM_CONFIG,
- OPTION_ROM_MICROCODE,
+ OPTION_ROM_MICROCODE = 10,
S_CRTM_VERSION,
S_CRTM_CONTENTS,
POST_CONTENTS,
+ HOST_TABLE_OF_DEVICES,
};
static const char* tcpa_pc_event_id_strings[] = {
- ""
+ "",
"SMBIOS",
"BIS Certificate",
"POST BIOS ",
@@ -116,10 +137,12 @@ static const char* tcpa_pc_event_id_strings[] = {
"NVRAM",
"Option ROM",
"Option ROM config",
- "Option ROM microcode",
+ "",
+ "Option ROM microcode ",
"S-CRTM Version",
- "S-CRTM Contents",
- "S-CRTM POST Contents",
+ "S-CRTM Contents ",
+ "POST Contents ",
+ "Table of Devices",
};
/* returns pointer to start of pos. entry of tcg log */
@@ -191,7 +214,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
const char *name = "";
char data[40] = "";
int i, n_len = 0, d_len = 0;
- u32 event_id;
+ struct tcpa_pc_event *pc_event;
switch(event->event_type) {
case PREBOOT:
@@ -220,31 +243,32 @@ static int get_event_name(char *dest, struct tcpa_event *event,
}
break;
case EVENT_TAG:
- event_id = be32_to_cpu(*((u32 *)event_entry));
+ pc_event = (struct tcpa_pc_event *)event_entry;
/* ToDo Row data -> Base64 */
- switch (event_id) {
+ switch (pc_event->event_id) {
case SMBIOS:
case BIS_CERT:
case CMOS:
case NVRAM:
case OPTION_ROM_EXEC:
case OPTION_ROM_CONFIG:
- case OPTION_ROM_MICROCODE:
case S_CRTM_VERSION:
- case S_CRTM_CONTENTS:
- case POST_CONTENTS:
- name = tcpa_pc_event_id_strings[event_id];
+ name = tcpa_pc_event_id_strings[pc_event->event_id];
n_len = strlen(name);
break;
+ /* hash data */
case POST_BIOS_ROM:
case ESCD:
- name = tcpa_pc_event_id_strings[event_id];
+ case OPTION_ROM_MICROCODE:
+ case S_CRTM_CONTENTS:
+ case POST_CONTENTS:
+ name = tcpa_pc_event_id_strings[pc_event->event_id];
n_len = strlen(name);
for (i = 0; i < 20; i++)
- d_len += sprintf(data, "%02x",
- event_entry[8 + i]);
+ d_len += sprintf(&data[2*i], "%02x",
+ pc_event->event_data[i]);
break;
default:
break;
@@ -260,52 +284,13 @@ static int get_event_name(char *dest, struct tcpa_event *event,
static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
{
+ struct tcpa_event *event = v;
+ char *data = v;
+ int i;
- char *eventname;
- char data[4];
- u32 help;
- int i, len;
- struct tcpa_event *event = (struct tcpa_event *) v;
- unsigned char *event_entry =
- (unsigned char *) (v + sizeof(struct tcpa_event));
-
- eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
- if (!eventname) {
- printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
- __func__);
- return -ENOMEM;
- }
-
- /* 1st: PCR used is in little-endian format (4 bytes) */
- help = le32_to_cpu(event->pcr_index);
- memcpy(data, &help, 4);
- for (i = 0; i < 4; i++)
- seq_putc(m, data[i]);
-
- /* 2nd: SHA1 (20 bytes) */
- for (i = 0; i < 20; i++)
- seq_putc(m, event->pcr_value[i]);
-
- /* 3rd: event type identifier (4 bytes) */
- help = le32_to_cpu(event->event_type);
- memcpy(data, &help, 4);
- for (i = 0; i < 4; i++)
+ for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
seq_putc(m, data[i]);
- len = 0;
-
- len += get_event_name(eventname, event, event_entry);
-
- /* 4th: filename <= 255 + \'0' delimiter */
- if (len > TCG_EVENT_NAME_LEN_MAX)
- len = TCG_EVENT_NAME_LEN_MAX;
-
- for (i = 0; i < len; i++)
- seq_putc(m, eventname[i]);
-
- /* 5th: delimiter */
- seq_putc(m, '\0');
-
return 0;
}
@@ -353,6 +338,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
/* 4th: eventname <= max + \'0' delimiter */
seq_printf(m, " %s\n", eventname);
+ kfree(eventname);
return 0;
}
@@ -376,6 +362,7 @@ static int read_log(struct tpm_bios_log *log)
struct acpi_tcpa *buff;
acpi_status status;
struct acpi_table_header *virt;
+ u64 len, start;
if (log->bios_event_log != NULL) {
printk(KERN_ERR
@@ -396,27 +383,37 @@ static int read_log(struct tpm_bios_log *log)
return -EIO;
}
- if (buff->log_max_len == 0) {
+ switch(buff->platform_class) {
+ case BIOS_SERVER:
+ len = buff->server.log_max_len;
+ start = buff->server.log_start_addr;
+ break;
+ case BIOS_CLIENT:
+ default:
+ len = buff->client.log_max_len;
+ start = buff->client.log_start_addr;
+ break;
+ }
+ if (!len) {
printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
return -EIO;
}
/* malloc EventLog space */
- log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
+ log->bios_event_log = kmalloc(len, GFP_KERNEL);
if (!log->bios_event_log) {
- printk
- ("%s: ERROR - Not enough Memory for BIOS measurements\n",
- __func__);
+ printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
+ __func__);
return -ENOMEM;
}
- log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
+ log->bios_event_log_end = log->bios_event_log + len;
- acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt);
+ acpi_os_map_memory(start, len, (void *) &virt);
- memcpy(log->bios_event_log, virt, buff->log_max_len);
+ memcpy(log->bios_event_log, virt, len);
- acpi_os_unmap_memory(virt, buff->log_max_len);
+ acpi_os_unmap_memory(virt, len);
return 0;
}
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 24095f6ee6da..adfff21beb21 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -15,6 +15,7 @@
* License.
*/
+#include <linux/init.h>
#include <linux/pnp.h>
#include "tpm.h"
@@ -104,7 +105,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
if (clear_wrfifo) {
for (i = 0; i < 4096; i++) {
- status = inb(chip->vendor->base + WRFIFO);
+ status = inb(chip->vendor.base + WRFIFO);
if (status == 0xff) {
if (check == 5)
break;
@@ -124,8 +125,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
*/
i = 0;
do {
- status = inb(chip->vendor->base + RDFIFO);
- status = inb(chip->vendor->base + STAT);
+ status = inb(chip->vendor.base + RDFIFO);
+ status = inb(chip->vendor.base + STAT);
i++;
if (i == TPM_MAX_TRIES)
return -EIO;
@@ -138,7 +139,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
int status;
int i;
for (i = 0; i < TPM_MAX_TRIES; i++) {
- status = inb(chip->vendor->base + STAT);
+ status = inb(chip->vendor.base + STAT);
/* check the status-register if wait_for_bit is set */
if (status & 1 << wait_for_bit)
break;
@@ -157,7 +158,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
{
wait(chip, STAT_XFE);
- outb(sendbyte, chip->vendor->base + WRFIFO);
+ outb(sendbyte, chip->vendor.base + WRFIFO);
}
/* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
@@ -204,7 +205,7 @@ recv_begin:
ret = wait(chip, STAT_RDA);
if (ret)
return -EIO;
- buf[i] = inb(chip->vendor->base + RDFIFO);
+ buf[i] = inb(chip->vendor.base + RDFIFO);
}
if (buf[0] != TPM_VL_VER) {
@@ -219,7 +220,7 @@ recv_begin:
for (i = 0; i < size; i++) {
wait(chip, STAT_RDA);
- buf[i] = inb(chip->vendor->base + RDFIFO);
+ buf[i] = inb(chip->vendor.base + RDFIFO);
}
if ((size == 0x6D00) && (buf[1] == 0x80)) {
@@ -268,7 +269,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
u8 count_high, count_low, count_4, count_3, count_2, count_1;
/* Disabling Reset, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, chip->vendor->base + CMD);
+ outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
ret = empty_fifo(chip, 1);
if (ret) {
@@ -319,7 +320,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip)
static u8 tpm_inf_status(struct tpm_chip *chip)
{
- return inb(chip->vendor->base + STAT);
+ return inb(chip->vendor.base + STAT);
}
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
@@ -346,7 +347,7 @@ static struct file_operations inf_ops = {
.release = tpm_release,
};
-static struct tpm_vendor_specific tpm_inf = {
+static const struct tpm_vendor_specific tpm_inf = {
.recv = tpm_inf_recv,
.send = tpm_inf_send,
.cancel = tpm_inf_cancel,
@@ -375,6 +376,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
int version[2];
int productid[2];
char chipname[20];
+ struct tpm_chip *chip;
/* read IO-ports through PnP */
if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
@@ -395,14 +397,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
goto err_last;
}
/* publish my base address and request region */
- tpm_inf.base = TPM_INF_BASE;
if (request_region
- (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
+ (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
rc = -EINVAL;
goto err_last;
}
- if (request_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN,
- "tpm_infineon0") == NULL) {
+ if (request_region
+ (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
rc = -EINVAL;
goto err_last;
}
@@ -442,9 +443,9 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
/* configure TPM with IO-ports */
outb(IOLIMH, TPM_INF_ADDR);
- outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA);
+ outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
outb(IOLIML, TPM_INF_ADDR);
- outb((tpm_inf.base & 0xff), TPM_INF_DATA);
+ outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
/* control if IO-ports are set correctly */
outb(IOLIMH, TPM_INF_ADDR);
@@ -452,10 +453,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
outb(IOLIML, TPM_INF_ADDR);
iol = inb(TPM_INF_DATA);
- if ((ioh << 8 | iol) != tpm_inf.base) {
+ if ((ioh << 8 | iol) != TPM_INF_BASE) {
dev_err(&dev->dev,
- "Could not set IO-ports to 0x%lx\n",
- tpm_inf.base);
+ "Could not set IO-ports to 0x%x\n",
+ TPM_INF_BASE);
rc = -EIO;
goto err_release_region;
}
@@ -466,15 +467,15 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
/* disable RESET, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD);
+ outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
/* Finally, we're done, print some infos */
dev_info(&dev->dev, "TPM found: "
"config base 0x%x, "
"io base 0x%x, "
- "chip version %02x%02x, "
- "vendor id %x%x (Infineon), "
- "product id %02x%02x"
+ "chip version 0x%02x%02x, "
+ "vendor id 0x%x%x (Infineon), "
+ "product id 0x%02x%02x"
"%s\n",
TPM_INF_ADDR,
TPM_INF_BASE,
@@ -482,11 +483,10 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
- rc = tpm_register_hardware(&dev->dev, &tpm_inf);
- if (rc < 0) {
- rc = -ENODEV;
+ if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
goto err_release_region;
}
+ chip->vendor.base = TPM_INF_BASE;
return 0;
} else {
rc = -ENODEV;
@@ -494,7 +494,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
}
err_release_region:
- release_region(tpm_inf.base, TPM_INF_PORT_LEN);
+ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
err_last:
@@ -506,7 +506,8 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
struct tpm_chip *chip = pnp_get_drvdata(dev);
if (chip) {
- release_region(chip->vendor->base, TPM_INF_PORT_LEN);
+ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
+ release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
tpm_remove_hardware(chip->dev);
}
}
@@ -520,7 +521,7 @@ static struct pnp_driver tpm_inf_pnp = {
},
.id_table = tpm_pnp_tbl,
.probe = tpm_inf_pnp_probe,
- .remove = tpm_inf_pnp_remove,
+ .remove = __devexit_p(tpm_inf_pnp_remove),
};
static int __init init_inf(void)
@@ -538,5 +539,5 @@ module_exit(cleanup_inf);
MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
-MODULE_VERSION("1.7");
+MODULE_VERSION("1.8");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 680a8e331887..4c8bc06c7d95 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
unsigned long stop;
/* status immediately available check */
- *data = inb(chip->vendor->base + NSC_STATUS);
+ *data = inb(chip->vendor.base + NSC_STATUS);
if ((*data & mask) == val)
return 0;
@@ -79,7 +79,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
stop = jiffies + 10 * HZ;
do {
msleep(TPM_TIMEOUT);
- *data = inb(chip->vendor->base + 1);
+ *data = inb(chip->vendor.base + 1);
if ((*data & mask) == val)
return 0;
}
@@ -94,9 +94,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
unsigned long stop;
/* status immediately available check */
- status = inb(chip->vendor->base + NSC_STATUS);
+ status = inb(chip->vendor.base + NSC_STATUS);
if (status & NSC_STATUS_OBF)
- status = inb(chip->vendor->base + NSC_DATA);
+ status = inb(chip->vendor.base + NSC_DATA);
if (status & NSC_STATUS_RDY)
return 0;
@@ -104,9 +104,9 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
stop = jiffies + 100;
do {
msleep(TPM_TIMEOUT);
- status = inb(chip->vendor->base + NSC_STATUS);
+ status = inb(chip->vendor.base + NSC_STATUS);
if (status & NSC_STATUS_OBF)
- status = inb(chip->vendor->base + NSC_DATA);
+ status = inb(chip->vendor.base + NSC_DATA);
if (status & NSC_STATUS_RDY)
return 0;
}
@@ -132,7 +132,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
}
if ((data =
- inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
+ inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
dev_err(chip->dev, "not in normal mode (0x%x)\n",
data);
return -EIO;
@@ -148,7 +148,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (data & NSC_STATUS_F0)
break;
- *p = inb(chip->vendor->base + NSC_DATA);
+ *p = inb(chip->vendor.base + NSC_DATA);
}
if ((data & NSC_STATUS_F0) == 0 &&
@@ -156,7 +156,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
dev_err(chip->dev, "F0 not set\n");
return -EIO;
}
- if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
+ if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
dev_err(chip->dev,
"expected end of command(0x%x)\n", data);
return -EIO;
@@ -182,7 +182,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
* fix it. Not sure why this is needed, we followed the flow
* chart in the manual to the letter.
*/
- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND);
if (nsc_wait_for_ready(chip) != 0)
return -EIO;
@@ -192,7 +192,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
}
- outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
+ outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
dev_err(chip->dev, "IBR timeout\n");
return -EIO;
@@ -204,26 +204,26 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
"IBF timeout (while writing data)\n");
return -EIO;
}
- outb(buf[i], chip->vendor->base + NSC_DATA);
+ outb(buf[i], chip->vendor.base + NSC_DATA);
}
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
dev_err(chip->dev, "IBF timeout\n");
return -EIO;
}
- outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
+ outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
return count;
}
static void tpm_nsc_cancel(struct tpm_chip *chip)
{
- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND);
}
static u8 tpm_nsc_status(struct tpm_chip *chip)
{
- return inb(chip->vendor->base + NSC_STATUS);
+ return inb(chip->vendor.base + NSC_STATUS);
}
static struct file_operations nsc_ops = {
@@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] = {
static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
-static struct tpm_vendor_specific tpm_nsc = {
+static const struct tpm_vendor_specific tpm_nsc = {
.recv = tpm_nsc_recv,
.send = tpm_nsc_send,
.cancel = tpm_nsc_cancel,
@@ -268,7 +268,7 @@ static void __devexit tpm_nsc_remove(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if ( chip ) {
- release_region(chip->vendor->base, 2);
+ release_region(chip->vendor.base, 2);
tpm_remove_hardware(chip->dev);
}
}
@@ -286,7 +286,8 @@ static int __init init_nsc(void)
int rc = 0;
int lo, hi;
int nscAddrBase = TPM_ADDR;
-
+ struct tpm_chip *chip;
+ unsigned long base;
/* verify that it is a National part (SID) */
if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
@@ -300,7 +301,7 @@ static int __init init_nsc(void)
hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
- tpm_nsc.base = (hi<<8) | lo;
+ base = (hi<<8) | lo;
/* enable the DPM module */
tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
@@ -320,13 +321,15 @@ static int __init init_nsc(void)
if ((rc = platform_device_register(pdev)) < 0)
goto err_free_dev;
- if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) {
+ if (request_region(base, 2, "tpm_nsc0") == NULL ) {
rc = -EBUSY;
goto err_unreg_dev;
}
- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0)
+ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
+ rc = -ENODEV;
goto err_rel_reg;
+ }
dev_dbg(&pdev->dev, "NSC TPM detected\n");
dev_dbg(&pdev->dev,
@@ -361,10 +364,12 @@ static int __init init_nsc(void)
"NSC TPM revision %d\n",
tpm_read_index(nscAddrBase, 0x27) & 0x1F);
+ chip->vendor.base = base;
+
return 0;
err_rel_reg:
- release_region(tpm_nsc.base, 2);
+ release_region(base, 2);
err_unreg_dev:
platform_device_unregister(pdev);
err_free_dev:
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
new file mode 100644
index 000000000000..8ea70625f7ea
--- /dev/null
+++ b/drivers/char/tpm/tpm_tis.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2005, 2006 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This device driver implements the TPM interface as defined in
+ * the TCG TPM Interface Spec version 1.2, revision 1.0.
+ *
+ * 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 of the
+ * License.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pnp.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include "tpm.h"
+
+#define TPM_HEADER_SIZE 10
+
+enum tis_access {
+ TPM_ACCESS_VALID = 0x80,
+ TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
+ TPM_ACCESS_REQUEST_PENDING = 0x04,
+ TPM_ACCESS_REQUEST_USE = 0x02,
+};
+
+enum tis_status {
+ TPM_STS_VALID = 0x80,
+ TPM_STS_COMMAND_READY = 0x40,
+ TPM_STS_GO = 0x20,
+ TPM_STS_DATA_AVAIL = 0x10,
+ TPM_STS_DATA_EXPECT = 0x08,
+};
+
+enum tis_int_flags {
+ TPM_GLOBAL_INT_ENABLE = 0x80000000,
+ TPM_INTF_BURST_COUNT_STATIC = 0x100,
+ TPM_INTF_CMD_READY_INT = 0x080,
+ TPM_INTF_INT_EDGE_FALLING = 0x040,
+ TPM_INTF_INT_EDGE_RISING = 0x020,
+ TPM_INTF_INT_LEVEL_LOW = 0x010,
+ TPM_INTF_INT_LEVEL_HIGH = 0x008,
+ TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+ TPM_INTF_STS_VALID_INT = 0x002,
+ TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+ TIS_MEM_BASE = 0xFED40000,
+ TIS_MEM_LEN = 0x5000,
+ TIS_SHORT_TIMEOUT = 750, /* ms */
+ TIS_LONG_TIMEOUT = 2000, /* 2 sec */
+};
+
+#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
+#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
+#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
+#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
+#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
+#define TPM_STS(l) (0x0018 | ((l) << 12))
+#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
+
+#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
+#define TPM_RID(l) (0x0F04 | ((l) << 12))
+
+static LIST_HEAD(tis_chips);
+static DEFINE_SPINLOCK(tis_lock);
+
+static int check_locality(struct tpm_chip *chip, int l)
+{
+ if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
+ return chip->vendor.locality = l;
+
+ return -1;
+}
+
+static void release_locality(struct tpm_chip *chip, int l, int force)
+{
+ if (force || (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
+ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
+ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))
+ iowrite8(TPM_ACCESS_ACTIVE_LOCALITY,
+ chip->vendor.iobase + TPM_ACCESS(l));
+}
+
+static int request_locality(struct tpm_chip *chip, int l)
+{
+ unsigned long stop;
+ long rc;
+
+ if (check_locality(chip, l) >= 0)
+ return l;
+
+ iowrite8(TPM_ACCESS_REQUEST_USE,
+ chip->vendor.iobase + TPM_ACCESS(l));
+
+ if (chip->vendor.irq) {
+ rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
+ (check_locality
+ (chip, l) >= 0),
+ chip->vendor.timeout_a);
+ if (rc > 0)
+ return l;
+
+ } else {
+ /* wait for burstcount */
+ stop = jiffies + chip->vendor.timeout_a;
+ do {
+ if (check_locality(chip, l) >= 0)
+ return l;
+ msleep(TPM_TIMEOUT);
+ }
+ while (time_before(jiffies, stop));
+ }
+ return -1;
+}
+
+static u8 tpm_tis_status(struct tpm_chip *chip)
+{
+ return ioread8(chip->vendor.iobase +
+ TPM_STS(chip->vendor.locality));
+}
+
+static void tpm_tis_ready(struct tpm_chip *chip)
+{
+ /* this causes the current command to be aborted */
+ iowrite8(TPM_STS_COMMAND_READY,
+ chip->vendor.iobase + TPM_STS(chip->vendor.locality));
+}
+
+static int get_burstcount(struct tpm_chip *chip)
+{
+ unsigned long stop;
+ int burstcnt;
+
+ /* wait for burstcount */
+ /* which timeout value, spec has 2 answers (c & d) */
+ stop = jiffies + chip->vendor.timeout_d;
+ do {
+ burstcnt = ioread8(chip->vendor.iobase +
+ TPM_STS(chip->vendor.locality) + 1);
+ burstcnt += ioread8(chip->vendor.iobase +
+ TPM_STS(chip->vendor.locality) +
+ 2) << 8;
+ if (burstcnt)
+ return burstcnt;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ return -EBUSY;
+}
+
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+ wait_queue_head_t *queue)
+{
+ unsigned long stop;
+ long rc;
+ u8 status;
+
+ /* check current status */
+ status = tpm_tis_status(chip);
+ if ((status & mask) == mask)
+ return 0;
+
+ if (chip->vendor.irq) {
+ rc = wait_event_interruptible_timeout(*queue,
+ ((tpm_tis_status
+ (chip) & mask) ==
+ mask), timeout);
+ if (rc > 0)
+ return 0;
+ } else {
+ stop = jiffies + timeout;
+ do {
+ msleep(TPM_TIMEOUT);
+ status = tpm_tis_status(chip);
+ if ((status & mask) == mask)
+ return 0;
+ } while (time_before(jiffies, stop));
+ }
+ return -ETIME;
+}
+
+static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ int size = 0, burstcnt;
+ while (size < count &&
+ wait_for_stat(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ chip->vendor.timeout_c,
+ &chip->vendor.read_queue)
+ == 0) {
+ burstcnt = get_burstcount(chip);
+ for (; burstcnt > 0 && size < count; burstcnt--)
+ buf[size++] = ioread8(chip->vendor.iobase +
+ TPM_DATA_FIFO(chip->vendor.
+ locality));
+ }
+ return size;
+}
+
+static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ int size = 0;
+ int expected, status;
+
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
+
+ /* read first 10 bytes, including tag, paramsize, and result */
+ if ((size =
+ recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
+ dev_err(chip->dev, "Unable to read header\n");
+ goto out;
+ }
+
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count) {
+ size = -EIO;
+ goto out;
+ }
+
+ if ((size +=
+ recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE)) < expected) {
+ dev_err(chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
+
+ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+ &chip->vendor.int_queue);
+ status = tpm_tis_status(chip);
+ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ dev_err(chip->dev, "Error left over data\n");
+ size = -EIO;
+ goto out;
+ }
+
+out:
+ tpm_tis_ready(chip);
+ release_locality(chip, chip->vendor.locality, 0);
+ return size;
+}
+
+/*
+ * If interrupts are used (signaled by an irq set in the vendor structure)
+ * tpm.c can skip polling for the data to be available as the interrupt is
+ * waited for here
+ */
+static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+ int rc, status, burstcnt;
+ size_t count = 0;
+ u32 ordinal;
+
+ if (request_locality(chip, 0) < 0)
+ return -EBUSY;
+
+ status = tpm_tis_status(chip);
+ if ((status & TPM_STS_COMMAND_READY) == 0) {
+ tpm_tis_ready(chip);
+ if (wait_for_stat
+ (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
+ &chip->vendor.int_queue) < 0) {
+ rc = -ETIME;
+ goto out_err;
+ }
+ }
+
+ while (count < len - 1) {
+ burstcnt = get_burstcount(chip);
+ for (; burstcnt > 0 && count < len - 1; burstcnt--) {
+ iowrite8(buf[count], chip->vendor.iobase +
+ TPM_DATA_FIFO(chip->vendor.locality));
+ count++;
+ }
+
+ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+ &chip->vendor.int_queue);
+ status = tpm_tis_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) == 0) {
+ rc = -EIO;
+ goto out_err;
+ }
+ }
+
+ /* write last byte */
+ iowrite8(buf[count],
+ chip->vendor.iobase +
+ TPM_DATA_FIFO(chip->vendor.locality));
+ wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+ &chip->vendor.int_queue);
+ status = tpm_tis_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) != 0) {
+ rc = -EIO;
+ goto out_err;
+ }
+
+ /* go and do it */
+ iowrite8(TPM_STS_GO,
+ chip->vendor.iobase + TPM_STS(chip->vendor.locality));
+
+ if (chip->vendor.irq) {
+ ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+ if (wait_for_stat
+ (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ tpm_calc_ordinal_duration(chip, ordinal),
+ &chip->vendor.read_queue) < 0) {
+ rc = -ETIME;
+ goto out_err;
+ }
+ }
+ return len;
+out_err:
+ tpm_tis_ready(chip);
+ release_locality(chip, chip->vendor.locality, 0);
+ return rc;
+}
+
+static struct file_operations tis_ops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = tpm_open,
+ .read = tpm_read,
+ .write = tpm_write,
+ .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
+ NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute *tis_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_enabled.attr,
+ &dev_attr_active.attr,
+ &dev_attr_owned.attr,
+ &dev_attr_temp_deactivated.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr, NULL,
+};
+
+static struct attribute_group tis_attr_grp = {
+ .attrs = tis_attrs
+};
+
+static struct tpm_vendor_specific tpm_tis = {
+ .status = tpm_tis_status,
+ .recv = tpm_tis_recv,
+ .send = tpm_tis_send,
+ .cancel = tpm_tis_ready,
+ .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_canceled = TPM_STS_COMMAND_READY,
+ .attr_group = &tis_attr_grp,
+ .miscdev = {
+ .fops = &tis_ops,},
+};
+
+static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ u32 interrupt;
+
+ interrupt = ioread32(chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+
+ if (interrupt == 0)
+ return IRQ_NONE;
+
+ chip->vendor.irq = irq;
+
+ /* Clear interrupts handled with TPM_EOI */
+ iowrite32(interrupt,
+ chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ u32 interrupt;
+ int i;
+
+ interrupt = ioread32(chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+
+ if (interrupt == 0)
+ return IRQ_NONE;
+
+ if (interrupt & TPM_INTF_DATA_AVAIL_INT)
+ wake_up_interruptible(&chip->vendor.read_queue);
+ if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
+ for (i = 0; i < 5; i++)
+ if (check_locality(chip, i) >= 0)
+ break;
+ if (interrupt &
+ (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
+ TPM_INTF_CMD_READY_INT))
+ wake_up_interruptible(&chip->vendor.int_queue);
+
+ /* Clear interrupts handled with TPM_EOI */
+ iowrite32(interrupt,
+ chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+ return IRQ_HANDLED;
+}
+
+static int interrupts = 1;
+module_param(interrupts, bool, 0444);
+MODULE_PARM_DESC(interrupts, "Enable interrupts");
+
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *pnp_id)
+{
+ u32 vendor, intfcaps, intmask;
+ int rc, i;
+ unsigned long start, len;
+ struct tpm_chip *chip;
+
+ start = pnp_mem_start(pnp_dev, 0);
+ len = pnp_mem_len(pnp_dev, 0);
+
+ if (!start)
+ start = TIS_MEM_BASE;
+ if (!len)
+ len = TIS_MEM_LEN;
+
+ if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+ return -ENODEV;
+
+ chip->vendor.iobase = ioremap(start, len);
+ if (!chip->vendor.iobase) {
+ rc = -EIO;
+ goto out_err;
+ }
+
+ vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+
+ /* Default timeouts */
+ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
+ chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+
+ dev_info(&pnp_dev->dev,
+ "1.2 TPM (device-id 0x%X, rev-id %d)\n",
+ vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
+
+ /* Figure out the capabilities */
+ intfcaps =
+ ioread32(chip->vendor.iobase +
+ TPM_INTF_CAPS(chip->vendor.locality));
+ dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+ intfcaps);
+ if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
+ dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+ if (intfcaps & TPM_INTF_CMD_READY_INT)
+ dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+ if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
+ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+ if (intfcaps & TPM_INTF_INT_EDGE_RISING)
+ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+ if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
+ dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+ if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
+ dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+ if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
+ dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+ if (intfcaps & TPM_INTF_STS_VALID_INT)
+ dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+ if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
+ dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
+
+ if (request_locality(chip, 0) != 0) {
+ rc = -ENODEV;
+ goto out_err;
+ }
+
+ /* INTERRUPT Setup */
+ init_waitqueue_head(&chip->vendor.read_queue);
+ init_waitqueue_head(&chip->vendor.int_queue);
+
+ intmask =
+ ioread32(chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+
+ intmask |= TPM_INTF_CMD_READY_INT
+ | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
+ | TPM_INTF_STS_VALID_INT;
+
+ iowrite32(intmask,
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ if (interrupts) {
+ chip->vendor.irq =
+ ioread8(chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+
+ for (i = 3; i < 16 && chip->vendor.irq == 0; i++) {
+ iowrite8(i, chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+ if (request_irq
+ (i, tis_int_probe, SA_SHIRQ,
+ chip->vendor.miscdev.name, chip) != 0) {
+ dev_info(chip->dev,
+ "Unable to request irq: %d for probe\n",
+ i);
+ continue;
+ }
+
+ /* Clear all existing */
+ iowrite32(ioread32
+ (chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality)),
+ chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+
+ /* Turn on */
+ iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+
+ /* Generate Interrupts */
+ tpm_gen_interrupt(chip);
+
+ /* Turn off */
+ iowrite32(intmask,
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ free_irq(i, chip);
+ }
+ }
+ if (chip->vendor.irq) {
+ iowrite8(chip->vendor.irq,
+ chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+ if (request_irq
+ (chip->vendor.irq, tis_int_handler, SA_SHIRQ,
+ chip->vendor.miscdev.name, chip) != 0) {
+ dev_info(chip->dev,
+ "Unable to request irq: %d for use\n",
+ chip->vendor.irq);
+ chip->vendor.irq = 0;
+ } else {
+ /* Clear all existing */
+ iowrite32(ioread32
+ (chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality)),
+ chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality));
+
+ /* Turn on */
+ iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ }
+ }
+
+ INIT_LIST_HEAD(&chip->vendor.list);
+ spin_lock(&tis_lock);
+ list_add(&chip->vendor.list, &tis_chips);
+ spin_unlock(&tis_lock);
+
+ tpm_get_timeouts(chip);
+ tpm_continue_selftest(chip);
+
+ return 0;
+out_err:
+ if (chip->vendor.iobase)
+ iounmap(chip->vendor.iobase);
+ tpm_remove_hardware(chip->dev);
+ return rc;
+}
+
+static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
+{
+ return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_tis_pnp_resume(struct pnp_dev *dev)
+{
+ return tpm_pm_resume(&dev->dev);
+}
+
+static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
+ {"PNP0C31", 0}, /* TPM */
+ {"ATM1200", 0}, /* Atmel */
+ {"IFX0102", 0}, /* Infineon */
+ {"BCM0101", 0}, /* Broadcom */
+ {"NSC1200", 0}, /* National */
+ /* Add new here */
+ {"", 0}, /* User Specified */
+ {"", 0} /* Terminator */
+};
+
+static struct pnp_driver tis_pnp_driver = {
+ .name = "tpm_tis",
+ .id_table = tpm_pnp_tbl,
+ .probe = tpm_tis_pnp_init,
+ .suspend = tpm_tis_pnp_suspend,
+ .resume = tpm_tis_pnp_resume,
+};
+
+#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
+module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
+ sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
+MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+
+static int __init init_tis(void)
+{
+ return pnp_register_driver(&tis_pnp_driver);
+}
+
+static void __exit cleanup_tis(void)
+{
+ struct tpm_vendor_specific *i, *j;
+ struct tpm_chip *chip;
+ spin_lock(&tis_lock);
+ list_for_each_entry_safe(i, j, &tis_chips, list) {
+ chip = to_tpm_chip(i);
+ iowrite32(~TPM_GLOBAL_INT_ENABLE &
+ ioread32(chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.
+ locality)),
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ release_locality(chip, chip->vendor.locality, 1);
+ if (chip->vendor.irq)
+ free_irq(chip->vendor.irq, chip);
+ iounmap(i->iobase);
+ list_del(&i->list);
+ tpm_remove_hardware(chip->dev);
+ }
+ spin_unlock(&tis_lock);
+ pnp_unregister_driver(&tis_pnp_driver);
+}
+
+module_init(init_tis);
+module_exit(cleanup_tis);
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f07637a8f88f..a88b94a82b14 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -398,7 +398,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
while (unlikely(size > copied));
return copied;
}
-EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
void tty_schedule_flip(struct tty_struct *tty)
{
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index acc5d47844eb..6c94879e0b99 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -3238,14 +3238,6 @@ void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
}
}
-int is_console_suspend_safe(void)
-{
- /* It is unsafe to suspend devices while X has control of the
- * hardware. Make sure we are running on a kernel-controlled console.
- */
- return vc_cons[fg_console].d->vc_mode == KD_TEXT;
-}
-
/*
* Visible symbols for modules
*/
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index a13395e2c372..fa2ba9ebe42a 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -33,11 +33,6 @@
* 82801E (C-ICH) : document number 273599-001, 273645-002,
* 82801EB (ICH5) : document number 252516-001, 252517-003,
* 82801ER (ICH5R) : document number 252516-001, 252517-003,
- * 82801FB (ICH6) : document number 301473-002, 301474-007,
- * 82801FR (ICH6R) : document number 301473-002, 301474-007,
- * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
- * 82801FW (ICH6W) : document number 301473-001, 301474-007,
- * 82801FRW (ICH6RW) : document number 301473-001, 301474-007
*
* 20000710 Nils Faerber
* Initial Version 0.01
@@ -66,6 +61,10 @@
* 20050807 Wim Van Sebroeck <wim@iguana.be>
* 0.08 Make sure that the watchdog is only "armed" when started.
* (Kernel Bug 4251)
+ * 20060416 Wim Van Sebroeck <wim@iguana.be>
+ * 0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and
+ * ICH7 chipsets. (See Kernel Bug 6031 - other code will support these
+ * chipsets)
*/
/*
@@ -90,7 +89,7 @@
#include "i8xx_tco.h"
/* Module and version information */
-#define TCO_VERSION "0.08"
+#define TCO_VERSION "0.09"
#define TCO_MODULE_NAME "i8xx TCO timer"
#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
#define PFX TCO_MODULE_NAME ": "
@@ -391,11 +390,6 @@ static struct pci_device_id i8xx_tco_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }, /* End of list */
};
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 9dc54736e4eb..1ea04e9b2b0b 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -423,6 +423,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
if (tmr_atboot && started == 0) {
printk(KERN_INFO PFX "Starting Watchdog Timer\n");
s3c2410wdt_start();
+ } else if (!tmr_atboot) {
+ /* if we're not enabling the watchdog, then ensure it is
+ * disabled if it has been left running from the bootloader
+ * or other source */
+
+ s3c2410wdt_stop();
}
return 0;
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 515ce7572049..20b88f9b7be2 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -377,7 +377,7 @@ static int __init sc1200wdt_init(void)
{
int ret;
- printk(banner);
+ printk("%s\n", banner);
spin_lock_init(&sc1200wdt_lock);
sema_init(&open_sem, 1);
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 9f2f00d82917..05f8ce2cfb4a 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -127,7 +127,7 @@ void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
if (found) {
cn_queue_free_callback(cbq);
- atomic_dec_and_test(&dev->refcnt);
+ atomic_dec(&dev->refcnt);
}
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 9759d05b1972..44d1eca83a72 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -257,7 +257,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((policy) && (policy->cpu == freqs->cpu) &&
(policy->cur) && (policy->cur != freqs->old)) {
- dprintk(KERN_WARNING "Warning: CPU frequency is"
+ dprintk("Warning: CPU frequency is"
" %u, cpufreq assumed %u kHz.\n",
freqs->old, policy->cur);
freqs->old = policy->cur;
@@ -874,7 +874,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne
{
struct cpufreq_freqs freqs;
- dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
+ dprintk("Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
freqs.cpu = cpu;
@@ -1006,7 +1006,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
struct cpufreq_freqs freqs;
if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
- dprintk(KERN_DEBUG "Warning: CPU frequency is %u, "
+ dprintk("Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n",
cur_freq, cpu_policy->cur);
@@ -1087,7 +1087,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
struct cpufreq_freqs freqs;
if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
- dprintk(KERN_WARNING "Warning: CPU frequency"
+ dprintk("Warning: CPU frequency"
"is %u, cpufreq assumed %u kHz.\n",
cur_freq, cpu_policy->cur);
@@ -1497,7 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_update_policy);
-static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
+static int cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 956d121cb161..3e6ffcaa5af4 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -74,6 +74,8 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
static DEFINE_MUTEX (dbs_mutex);
static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
+static struct workqueue_struct *dbs_workq;
+
struct dbs_tuners {
unsigned int sampling_rate;
unsigned int sampling_down_factor;
@@ -364,23 +366,29 @@ static void do_dbs_timer(void *data)
mutex_lock(&dbs_mutex);
for_each_online_cpu(i)
dbs_check_cpu(i);
- schedule_delayed_work(&dbs_work,
- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+ queue_delayed_work(dbs_workq, &dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
mutex_unlock(&dbs_mutex);
}
static inline void dbs_timer_init(void)
{
INIT_WORK(&dbs_work, do_dbs_timer, NULL);
- schedule_delayed_work(&dbs_work,
- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+ if (!dbs_workq)
+ dbs_workq = create_singlethread_workqueue("ondemand");
+ if (!dbs_workq) {
+ printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n");
+ return;
+ }
+ queue_delayed_work(dbs_workq, &dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
return;
}
static inline void dbs_timer_exit(void)
{
- cancel_delayed_work(&dbs_work);
- return;
+ if (dbs_workq)
+ cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work);
}
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -489,8 +497,12 @@ static int __init cpufreq_gov_dbs_init(void)
static void __exit cpufreq_gov_dbs_exit(void)
{
- /* Make sure that the scheduled work is indeed not running */
- flush_scheduled_work();
+ /* Make sure that the scheduled work is indeed not running.
+ Assumes the timer has been cancelled first. */
+ if (dbs_workq) {
+ flush_workqueue(dbs_workq);
+ destroy_workqueue(dbs_workq);
+ }
cpufreq_unregister_governor(&cpufreq_gov_dbs);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 9694b6ed3268..c576c0b3f452 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -74,7 +74,7 @@ static ssize_t
show_total_trans(struct cpufreq_policy *policy, char *buf)
{
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
- if(!stat)
+ if (!stat)
return 0;
return sprintf(buf, "%d\n",
cpufreq_stats_table[stat->cpu]->total_trans);
@@ -86,7 +86,7 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
ssize_t len = 0;
int i;
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
- if(!stat)
+ if (!stat)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
@@ -104,7 +104,7 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
int i, j;
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
- if(!stat)
+ if (!stat)
return 0;
cpufreq_stats_update(stat->cpu);
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index a4818ce88919..551f4ccf87fd 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -20,7 +20,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
{
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
- unsigned int i = 0;
+ unsigned int i;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
@@ -51,7 +51,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int next_larger = ~0;
- unsigned int i = 0;
+ unsigned int i;
unsigned int count = 0;
dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
@@ -91,20 +91,24 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
unsigned int *index)
{
- struct cpufreq_frequency_table optimal = { .index = ~0, };
- struct cpufreq_frequency_table suboptimal = { .index = ~0, };
+ struct cpufreq_frequency_table optimal = {
+ .index = ~0,
+ .frequency = 0,
+ };
+ struct cpufreq_frequency_table suboptimal = {
+ .index = ~0,
+ .frequency = 0,
+ };
unsigned int i;
dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
switch (relation) {
case CPUFREQ_RELATION_H:
- optimal.frequency = 0;
suboptimal.frequency = ~0;
break;
case CPUFREQ_RELATION_L:
optimal.frequency = ~0;
- suboptimal.frequency = 0;
break;
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
new file mode 100644
index 000000000000..30d021d1a07c
--- /dev/null
+++ b/drivers/dma/Kconfig
@@ -0,0 +1,34 @@
+#
+# DMA engine configuration
+#
+
+menu "DMA Engine support"
+
+config DMA_ENGINE
+ bool "Support for DMA engines"
+ ---help---
+ DMA engines offload copy operations from the CPU to dedicated
+ hardware, allowing the copies to happen asynchronously.
+
+comment "DMA Clients"
+
+config NET_DMA
+ bool "Network: TCP receive copy offload"
+ depends on DMA_ENGINE && NET
+ default y
+ ---help---
+ This enables the use of DMA engines in the network stack to
+ offload receive copy-to-user operations, freeing CPU cycles.
+ Since this is the main user of the DMA engine, it should be enabled;
+ say Y here.
+
+comment "DMA Devices"
+
+config INTEL_IOATDMA
+ tristate "Intel I/OAT DMA support"
+ depends on DMA_ENGINE && PCI
+ default m
+ ---help---
+ Enable support for the Intel(R) I/OAT DMA engine.
+
+endmenu
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
new file mode 100644
index 000000000000..bdcfdbdb1aec
--- /dev/null
+++ b/drivers/dma/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
+obj-$(CONFIG_NET_DMA) += iovlock.o
+obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
new file mode 100644
index 000000000000..5829143558e1
--- /dev/null
+++ b/drivers/dma/dmaengine.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This code implements the DMA subsystem. It provides a HW-neutral interface
+ * for other kernel code to use asynchronous memory copy capabilities,
+ * if present, and allows different HW DMA drivers to register as providing
+ * this capability.
+ *
+ * Due to the fact we are accelerating what is already a relatively fast
+ * operation, the code goes to great lengths to avoid additional overhead,
+ * such as locking.
+ *
+ * LOCKING:
+ *
+ * The subsystem keeps two global lists, dma_device_list and dma_client_list.
+ * Both of these are protected by a mutex, dma_list_mutex.
+ *
+ * Each device has a channels list, which runs unlocked but is never modified
+ * once the device is registered, it's just setup by the driver.
+ *
+ * Each client has a channels list, it's only modified under the client->lock
+ * and in an RCU callback, so it's safe to read under rcu_read_lock().
+ *
+ * Each device has a kref, which is initialized to 1 when the device is
+ * registered. A kref_put is done for each class_device registered. When the
+ * class_device is released, the coresponding kref_put is done in the release
+ * method. Every time one of the device's channels is allocated to a client,
+ * a kref_get occurs. When the channel is freed, the coresponding kref_put
+ * happens. The device's release function does a completion, so
+ * unregister_device does a remove event, class_device_unregister, a kref_put
+ * for the first reference, then waits on the completion for all other
+ * references to finish.
+ *
+ * Each channel has an open-coded implementation of Rusty Russell's "bigref,"
+ * with a kref and a per_cpu local_t. A single reference is set when on an
+ * ADDED event, and removed with a REMOVE event. Net DMA client takes an
+ * extra reference per outstanding transaction. The relase function does a
+ * kref_put on the device. -ChrisL
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/percpu.h>
+#include <linux/rcupdate.h>
+#include <linux/mutex.h>
+
+static DEFINE_MUTEX(dma_list_mutex);
+static LIST_HEAD(dma_device_list);
+static LIST_HEAD(dma_client_list);
+
+/* --- sysfs implementation --- */
+
+static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
+{
+ struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+ unsigned long count = 0;
+ int i;
+
+ for_each_possible_cpu(i)
+ count += per_cpu_ptr(chan->local, i)->memcpy_count;
+
+ return sprintf(buf, "%lu\n", count);
+}
+
+static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
+{
+ struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+ unsigned long count = 0;
+ int i;
+
+ for_each_possible_cpu(i)
+ count += per_cpu_ptr(chan->local, i)->bytes_transferred;
+
+ return sprintf(buf, "%lu\n", count);
+}
+
+static ssize_t show_in_use(struct class_device *cd, char *buf)
+{
+ struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+
+ return sprintf(buf, "%d\n", (chan->client ? 1 : 0));
+}
+
+static struct class_device_attribute dma_class_attrs[] = {
+ __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
+ __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
+ __ATTR(in_use, S_IRUGO, show_in_use, NULL),
+ __ATTR_NULL
+};
+
+static void dma_async_device_cleanup(struct kref *kref);
+
+static void dma_class_dev_release(struct class_device *cd)
+{
+ struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+ kref_put(&chan->device->refcount, dma_async_device_cleanup);
+}
+
+static struct class dma_devclass = {
+ .name = "dma",
+ .class_dev_attrs = dma_class_attrs,
+ .release = dma_class_dev_release,
+};
+
+/* --- client and device registration --- */
+
+/**
+ * dma_client_chan_alloc - try to allocate a channel to a client
+ * @client: &dma_client
+ *
+ * Called with dma_list_mutex held.
+ */
+static struct dma_chan *dma_client_chan_alloc(struct dma_client *client)
+{
+ struct dma_device *device;
+ struct dma_chan *chan;
+ unsigned long flags;
+ int desc; /* allocated descriptor count */
+
+ /* Find a channel, any DMA engine will do */
+ list_for_each_entry(device, &dma_device_list, global_node) {
+ list_for_each_entry(chan, &device->channels, device_node) {
+ if (chan->client)
+ continue;
+
+ desc = chan->device->device_alloc_chan_resources(chan);
+ if (desc >= 0) {
+ kref_get(&device->refcount);
+ kref_init(&chan->refcount);
+ chan->slow_ref = 0;
+ INIT_RCU_HEAD(&chan->rcu);
+ chan->client = client;
+ spin_lock_irqsave(&client->lock, flags);
+ list_add_tail_rcu(&chan->client_node,
+ &client->channels);
+ spin_unlock_irqrestore(&client->lock, flags);
+ return chan;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * dma_client_chan_free - release a DMA channel
+ * @chan: &dma_chan
+ */
+void dma_chan_cleanup(struct kref *kref)
+{
+ struct dma_chan *chan = container_of(kref, struct dma_chan, refcount);
+ chan->device->device_free_chan_resources(chan);
+ chan->client = NULL;
+ kref_put(&chan->device->refcount, dma_async_device_cleanup);
+}
+
+static void dma_chan_free_rcu(struct rcu_head *rcu)
+{
+ struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu);
+ int bias = 0x7FFFFFFF;
+ int i;
+ for_each_possible_cpu(i)
+ bias -= local_read(&per_cpu_ptr(chan->local, i)->refcount);
+ atomic_sub(bias, &chan->refcount.refcount);
+ kref_put(&chan->refcount, dma_chan_cleanup);
+}
+
+static void dma_client_chan_free(struct dma_chan *chan)
+{
+ atomic_add(0x7FFFFFFF, &chan->refcount.refcount);
+ chan->slow_ref = 1;
+ call_rcu(&chan->rcu, dma_chan_free_rcu);
+}
+
+/**
+ * dma_chans_rebalance - reallocate channels to clients
+ *
+ * When the number of DMA channel in the system changes,
+ * channels need to be rebalanced among clients
+ */
+static void dma_chans_rebalance(void)
+{
+ struct dma_client *client;
+ struct dma_chan *chan;
+ unsigned long flags;
+
+ mutex_lock(&dma_list_mutex);
+
+ list_for_each_entry(client, &dma_client_list, global_node) {
+ while (client->chans_desired > client->chan_count) {
+ chan = dma_client_chan_alloc(client);
+ if (!chan)
+ break;
+ client->chan_count++;
+ client->event_callback(client,
+ chan,
+ DMA_RESOURCE_ADDED);
+ }
+ while (client->chans_desired < client->chan_count) {
+ spin_lock_irqsave(&client->lock, flags);
+ chan = list_entry(client->channels.next,
+ struct dma_chan,
+ client_node);
+ list_del_rcu(&chan->client_node);
+ spin_unlock_irqrestore(&client->lock, flags);
+ client->chan_count--;
+ client->event_callback(client,
+ chan,
+ DMA_RESOURCE_REMOVED);
+ dma_client_chan_free(chan);
+ }
+ }
+
+ mutex_unlock(&dma_list_mutex);
+}
+
+/**
+ * dma_async_client_register - allocate and register a &dma_client
+ * @event_callback: callback for notification of channel addition/removal
+ */
+struct dma_client *dma_async_client_register(dma_event_callback event_callback)
+{
+ struct dma_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+
+ INIT_LIST_HEAD(&client->channels);
+ spin_lock_init(&client->lock);
+ client->chans_desired = 0;
+ client->chan_count = 0;
+ client->event_callback = event_callback;
+
+ mutex_lock(&dma_list_mutex);
+ list_add_tail(&client->global_node, &dma_client_list);
+ mutex_unlock(&dma_list_mutex);
+
+ return client;
+}
+
+/**
+ * dma_async_client_unregister - unregister a client and free the &dma_client
+ * @client:
+ *
+ * Force frees any allocated DMA channels, frees the &dma_client memory
+ */
+void dma_async_client_unregister(struct dma_client *client)
+{
+ struct dma_chan *chan;
+
+ if (!client)
+ return;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(chan, &client->channels, client_node)
+ dma_client_chan_free(chan);
+ rcu_read_unlock();
+
+ mutex_lock(&dma_list_mutex);
+ list_del(&client->global_node);
+ mutex_unlock(&dma_list_mutex);
+
+ kfree(client);
+ dma_chans_rebalance();
+}
+
+/**
+ * dma_async_client_chan_request - request DMA channels
+ * @client: &dma_client
+ * @number: count of DMA channels requested
+ *
+ * Clients call dma_async_client_chan_request() to specify how many
+ * DMA channels they need, 0 to free all currently allocated.
+ * The resulting allocations/frees are indicated to the client via the
+ * event callback.
+ */
+void dma_async_client_chan_request(struct dma_client *client,
+ unsigned int number)
+{
+ client->chans_desired = number;
+ dma_chans_rebalance();
+}
+
+/**
+ * dma_async_device_register -
+ * @device: &dma_device
+ */
+int dma_async_device_register(struct dma_device *device)
+{
+ static int id;
+ int chancnt = 0;
+ struct dma_chan* chan;
+
+ if (!device)
+ return -ENODEV;
+
+ init_completion(&device->done);
+ kref_init(&device->refcount);
+ device->dev_id = id++;
+
+ /* represent channels in sysfs. Probably want devs too */
+ list_for_each_entry(chan, &device->channels, device_node) {
+ chan->local = alloc_percpu(typeof(*chan->local));
+ if (chan->local == NULL)
+ continue;
+
+ chan->chan_id = chancnt++;
+ chan->class_dev.class = &dma_devclass;
+ chan->class_dev.dev = NULL;
+ snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
+ device->dev_id, chan->chan_id);
+
+ kref_get(&device->refcount);
+ class_device_register(&chan->class_dev);
+ }
+
+ mutex_lock(&dma_list_mutex);
+ list_add_tail(&device->global_node, &dma_device_list);
+ mutex_unlock(&dma_list_mutex);
+
+ dma_chans_rebalance();
+
+ return 0;
+}
+
+/**
+ * dma_async_device_unregister -
+ * @device: &dma_device
+ */
+static void dma_async_device_cleanup(struct kref *kref)
+{
+ struct dma_device *device;
+
+ device = container_of(kref, struct dma_device, refcount);
+ complete(&device->done);
+}
+
+void dma_async_device_unregister(struct dma_device* device)
+{
+ struct dma_chan *chan;
+ unsigned long flags;
+
+ mutex_lock(&dma_list_mutex);
+ list_del(&device->global_node);
+ mutex_unlock(&dma_list_mutex);
+
+ list_for_each_entry(chan, &device->channels, device_node) {
+ if (chan->client) {
+ spin_lock_irqsave(&chan->client->lock, flags);
+ list_del(&chan->client_node);
+ chan->client->chan_count--;
+ spin_unlock_irqrestore(&chan->client->lock, flags);
+ chan->client->event_callback(chan->client,
+ chan,
+ DMA_RESOURCE_REMOVED);
+ dma_client_chan_free(chan);
+ }
+ class_device_unregister(&chan->class_dev);
+ }
+ dma_chans_rebalance();
+
+ kref_put(&device->refcount, dma_async_device_cleanup);
+ wait_for_completion(&device->done);
+}
+
+static int __init dma_bus_init(void)
+{
+ mutex_init(&dma_list_mutex);
+ return class_register(&dma_devclass);
+}
+
+subsys_initcall(dma_bus_init);
+
+EXPORT_SYMBOL(dma_async_client_register);
+EXPORT_SYMBOL(dma_async_client_unregister);
+EXPORT_SYMBOL(dma_async_client_chan_request);
+EXPORT_SYMBOL(dma_async_memcpy_buf_to_buf);
+EXPORT_SYMBOL(dma_async_memcpy_buf_to_pg);
+EXPORT_SYMBOL(dma_async_memcpy_pg_to_pg);
+EXPORT_SYMBOL(dma_async_memcpy_complete);
+EXPORT_SYMBOL(dma_async_memcpy_issue_pending);
+EXPORT_SYMBOL(dma_async_device_register);
+EXPORT_SYMBOL(dma_async_device_unregister);
+EXPORT_SYMBOL(dma_chan_cleanup);
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
new file mode 100644
index 000000000000..0fdf7fbd6495
--- /dev/null
+++ b/drivers/dma/ioatdma.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine, which does asynchronous
+ * copy operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include "ioatdma.h"
+#include "ioatdma_io.h"
+#include "ioatdma_registers.h"
+#include "ioatdma_hw.h"
+
+#define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common)
+#define to_ioat_device(dev) container_of(dev, struct ioat_device, common)
+#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
+
+/* internal functions */
+static int __devinit ioat_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit ioat_remove(struct pci_dev *pdev);
+
+static int enumerate_dma_channels(struct ioat_device *device)
+{
+ u8 xfercap_scale;
+ u32 xfercap;
+ int i;
+ struct ioat_dma_chan *ioat_chan;
+
+ device->common.chancnt = ioatdma_read8(device, IOAT_CHANCNT_OFFSET);
+ xfercap_scale = ioatdma_read8(device, IOAT_XFERCAP_OFFSET);
+ xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
+
+ for (i = 0; i < device->common.chancnt; i++) {
+ ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
+ if (!ioat_chan) {
+ device->common.chancnt = i;
+ break;
+ }
+
+ ioat_chan->device = device;
+ ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1));
+ ioat_chan->xfercap = xfercap;
+ spin_lock_init(&ioat_chan->cleanup_lock);
+ spin_lock_init(&ioat_chan->desc_lock);
+ INIT_LIST_HEAD(&ioat_chan->free_desc);
+ INIT_LIST_HEAD(&ioat_chan->used_desc);
+ /* This should be made common somewhere in dmaengine.c */
+ ioat_chan->common.device = &device->common;
+ ioat_chan->common.client = NULL;
+ list_add_tail(&ioat_chan->common.device_node,
+ &device->common.channels);
+ }
+ return device->common.chancnt;
+}
+
+static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
+ struct ioat_dma_chan *ioat_chan,
+ int flags)
+{
+ struct ioat_dma_descriptor *desc;
+ struct ioat_desc_sw *desc_sw;
+ struct ioat_device *ioat_device;
+ dma_addr_t phys;
+
+ ioat_device = to_ioat_device(ioat_chan->common.device);
+ desc = pci_pool_alloc(ioat_device->dma_pool, flags, &phys);
+ if (unlikely(!desc))
+ return NULL;
+
+ desc_sw = kzalloc(sizeof(*desc_sw), flags);
+ if (unlikely(!desc_sw)) {
+ pci_pool_free(ioat_device->dma_pool, desc, phys);
+ return NULL;
+ }
+
+ memset(desc, 0, sizeof(*desc));
+ desc_sw->hw = desc;
+ desc_sw->phys = phys;
+
+ return desc_sw;
+}
+
+#define INITIAL_IOAT_DESC_COUNT 128
+
+static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan);
+
+/* returns the actual number of allocated descriptors */
+static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_desc_sw *desc = NULL;
+ u16 chanctrl;
+ u32 chanerr;
+ int i;
+ LIST_HEAD(tmp_list);
+
+ /*
+ * In-use bit automatically set by reading chanctrl
+ * If 0, we got it, if 1, someone else did
+ */
+ chanctrl = ioatdma_chan_read16(ioat_chan, IOAT_CHANCTRL_OFFSET);
+ if (chanctrl & IOAT_CHANCTRL_CHANNEL_IN_USE)
+ return -EBUSY;
+
+ /* Setup register to interrupt and write completion status on error */
+ chanctrl = IOAT_CHANCTRL_CHANNEL_IN_USE |
+ IOAT_CHANCTRL_ERR_INT_EN |
+ IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
+ IOAT_CHANCTRL_ERR_COMPLETION_EN;
+ ioatdma_chan_write16(ioat_chan, IOAT_CHANCTRL_OFFSET, chanctrl);
+
+ chanerr = ioatdma_chan_read32(ioat_chan, IOAT_CHANERR_OFFSET);
+ if (chanerr) {
+ printk("IOAT: CHANERR = %x, clearing\n", chanerr);
+ ioatdma_chan_write32(ioat_chan, IOAT_CHANERR_OFFSET, chanerr);
+ }
+
+ /* Allocate descriptors */
+ for (i = 0; i < INITIAL_IOAT_DESC_COUNT; i++) {
+ desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
+ if (!desc) {
+ printk(KERN_ERR "IOAT: Only %d initial descriptors\n", i);
+ break;
+ }
+ list_add_tail(&desc->node, &tmp_list);
+ }
+ spin_lock_bh(&ioat_chan->desc_lock);
+ list_splice(&tmp_list, &ioat_chan->free_desc);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ /* allocate a completion writeback area */
+ /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
+ ioat_chan->completion_virt =
+ pci_pool_alloc(ioat_chan->device->completion_pool,
+ GFP_KERNEL,
+ &ioat_chan->completion_addr);
+ memset(ioat_chan->completion_virt, 0,
+ sizeof(*ioat_chan->completion_virt));
+ ioatdma_chan_write32(ioat_chan, IOAT_CHANCMP_OFFSET_LOW,
+ ((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF);
+ ioatdma_chan_write32(ioat_chan, IOAT_CHANCMP_OFFSET_HIGH,
+ ((u64) ioat_chan->completion_addr) >> 32);
+
+ ioat_start_null_desc(ioat_chan);
+ return i;
+}
+
+static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan);
+
+static void ioat_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_device *ioat_device = to_ioat_device(chan->device);
+ struct ioat_desc_sw *desc, *_desc;
+ u16 chanctrl;
+ int in_use_descs = 0;
+
+ ioat_dma_memcpy_cleanup(ioat_chan);
+
+ ioatdma_chan_write8(ioat_chan, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_RESET);
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+ list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) {
+ in_use_descs++;
+ list_del(&desc->node);
+ pci_pool_free(ioat_device->dma_pool, desc->hw, desc->phys);
+ kfree(desc);
+ }
+ list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) {
+ list_del(&desc->node);
+ pci_pool_free(ioat_device->dma_pool, desc->hw, desc->phys);
+ kfree(desc);
+ }
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ pci_pool_free(ioat_device->completion_pool,
+ ioat_chan->completion_virt,
+ ioat_chan->completion_addr);
+
+ /* one is ok since we left it on there on purpose */
+ if (in_use_descs > 1)
+ printk(KERN_ERR "IOAT: Freeing %d in use descriptors!\n",
+ in_use_descs - 1);
+
+ ioat_chan->last_completion = ioat_chan->completion_addr = 0;
+
+ /* Tell hw the chan is free */
+ chanctrl = ioatdma_chan_read16(ioat_chan, IOAT_CHANCTRL_OFFSET);
+ chanctrl &= ~IOAT_CHANCTRL_CHANNEL_IN_USE;
+ ioatdma_chan_write16(ioat_chan, IOAT_CHANCTRL_OFFSET, chanctrl);
+}
+
+/**
+ * do_ioat_dma_memcpy - actual function that initiates a IOAT DMA transaction
+ * @chan: IOAT DMA channel handle
+ * @dest: DMA destination address
+ * @src: DMA source address
+ * @len: transaction length in bytes
+ */
+
+static dma_cookie_t do_ioat_dma_memcpy(struct ioat_dma_chan *ioat_chan,
+ dma_addr_t dest,
+ dma_addr_t src,
+ size_t len)
+{
+ struct ioat_desc_sw *first;
+ struct ioat_desc_sw *prev;
+ struct ioat_desc_sw *new;
+ dma_cookie_t cookie;
+ LIST_HEAD(new_chain);
+ u32 copy;
+ size_t orig_len;
+ dma_addr_t orig_src, orig_dst;
+ unsigned int desc_count = 0;
+ unsigned int append = 0;
+
+ if (!ioat_chan || !dest || !src)
+ return -EFAULT;
+
+ if (!len)
+ return ioat_chan->common.cookie;
+
+ orig_len = len;
+ orig_src = src;
+ orig_dst = dest;
+
+ first = NULL;
+ prev = NULL;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+
+ while (len) {
+ if (!list_empty(&ioat_chan->free_desc)) {
+ new = to_ioat_desc(ioat_chan->free_desc.next);
+ list_del(&new->node);
+ } else {
+ /* try to get another desc */
+ new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
+ /* will this ever happen? */
+ /* TODO add upper limit on these */
+ BUG_ON(!new);
+ }
+
+ copy = min((u32) len, ioat_chan->xfercap);
+
+ new->hw->size = copy;
+ new->hw->ctl = 0;
+ new->hw->src_addr = src;
+ new->hw->dst_addr = dest;
+ new->cookie = 0;
+
+ /* chain together the physical address list for the HW */
+ if (!first)
+ first = new;
+ else
+ prev->hw->next = (u64) new->phys;
+
+ prev = new;
+
+ len -= copy;
+ dest += copy;
+ src += copy;
+
+ list_add_tail(&new->node, &new_chain);
+ desc_count++;
+ }
+ new->hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
+ new->hw->next = 0;
+
+ /* cookie incr and addition to used_list must be atomic */
+
+ cookie = ioat_chan->common.cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ ioat_chan->common.cookie = new->cookie = cookie;
+
+ pci_unmap_addr_set(new, src, orig_src);
+ pci_unmap_addr_set(new, dst, orig_dst);
+ pci_unmap_len_set(new, src_len, orig_len);
+ pci_unmap_len_set(new, dst_len, orig_len);
+
+ /* write address into NextDescriptor field of last desc in chain */
+ to_ioat_desc(ioat_chan->used_desc.prev)->hw->next = first->phys;
+ list_splice_init(&new_chain, ioat_chan->used_desc.prev);
+
+ ioat_chan->pending += desc_count;
+ if (ioat_chan->pending >= 20) {
+ append = 1;
+ ioat_chan->pending = 0;
+ }
+
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ if (append)
+ ioatdma_chan_write8(ioat_chan,
+ IOAT_CHANCMD_OFFSET,
+ IOAT_CHANCMD_APPEND);
+ return cookie;
+}
+
+/**
+ * ioat_dma_memcpy_buf_to_buf - wrapper that takes src & dest bufs
+ * @chan: IOAT DMA channel handle
+ * @dest: DMA destination address
+ * @src: DMA source address
+ * @len: transaction length in bytes
+ */
+
+static dma_cookie_t ioat_dma_memcpy_buf_to_buf(struct dma_chan *chan,
+ void *dest,
+ void *src,
+ size_t len)
+{
+ dma_addr_t dest_addr;
+ dma_addr_t src_addr;
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ dest_addr = pci_map_single(ioat_chan->device->pdev,
+ dest, len, PCI_DMA_FROMDEVICE);
+ src_addr = pci_map_single(ioat_chan->device->pdev,
+ src, len, PCI_DMA_TODEVICE);
+
+ return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
+}
+
+/**
+ * ioat_dma_memcpy_buf_to_pg - wrapper, copying from a buf to a page
+ * @chan: IOAT DMA channel handle
+ * @page: pointer to the page to copy to
+ * @offset: offset into that page
+ * @src: DMA source address
+ * @len: transaction length in bytes
+ */
+
+static dma_cookie_t ioat_dma_memcpy_buf_to_pg(struct dma_chan *chan,
+ struct page *page,
+ unsigned int offset,
+ void *src,
+ size_t len)
+{
+ dma_addr_t dest_addr;
+ dma_addr_t src_addr;
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ dest_addr = pci_map_page(ioat_chan->device->pdev,
+ page, offset, len, PCI_DMA_FROMDEVICE);
+ src_addr = pci_map_single(ioat_chan->device->pdev,
+ src, len, PCI_DMA_TODEVICE);
+
+ return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
+}
+
+/**
+ * ioat_dma_memcpy_pg_to_pg - wrapper, copying between two pages
+ * @chan: IOAT DMA channel handle
+ * @dest_pg: pointer to the page to copy to
+ * @dest_off: offset into that page
+ * @src_pg: pointer to the page to copy from
+ * @src_off: offset into that page
+ * @len: transaction length in bytes. This is guaranteed to not make a copy
+ * across a page boundary.
+ */
+
+static dma_cookie_t ioat_dma_memcpy_pg_to_pg(struct dma_chan *chan,
+ struct page *dest_pg,
+ unsigned int dest_off,
+ struct page *src_pg,
+ unsigned int src_off,
+ size_t len)
+{
+ dma_addr_t dest_addr;
+ dma_addr_t src_addr;
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ dest_addr = pci_map_page(ioat_chan->device->pdev,
+ dest_pg, dest_off, len, PCI_DMA_FROMDEVICE);
+ src_addr = pci_map_page(ioat_chan->device->pdev,
+ src_pg, src_off, len, PCI_DMA_TODEVICE);
+
+ return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
+}
+
+/**
+ * ioat_dma_memcpy_issue_pending - push potentially unrecognoized appended descriptors to hw
+ * @chan: DMA channel handle
+ */
+
+static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ if (ioat_chan->pending != 0) {
+ ioat_chan->pending = 0;
+ ioatdma_chan_write8(ioat_chan,
+ IOAT_CHANCMD_OFFSET,
+ IOAT_CHANCMD_APPEND);
+ }
+}
+
+static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
+{
+ unsigned long phys_complete;
+ struct ioat_desc_sw *desc, *_desc;
+ dma_cookie_t cookie = 0;
+
+ prefetch(chan->completion_virt);
+
+ if (!spin_trylock(&chan->cleanup_lock))
+ return;
+
+ /* The completion writeback can happen at any time,
+ so reads by the driver need to be atomic operations
+ The descriptor physical addresses are limited to 32-bits
+ when the CPU can only do a 32-bit mov */
+
+#if (BITS_PER_LONG == 64)
+ phys_complete =
+ chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
+#else
+ phys_complete = chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK;
+#endif
+
+ if ((chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) ==
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) {
+ printk("IOAT: Channel halted, chanerr = %x\n",
+ ioatdma_chan_read32(chan, IOAT_CHANERR_OFFSET));
+
+ /* TODO do something to salvage the situation */
+ }
+
+ if (phys_complete == chan->last_completion) {
+ spin_unlock(&chan->cleanup_lock);
+ return;
+ }
+
+ spin_lock_bh(&chan->desc_lock);
+ list_for_each_entry_safe(desc, _desc, &chan->used_desc, node) {
+
+ /*
+ * Incoming DMA requests may use multiple descriptors, due to
+ * exceeding xfercap, perhaps. If so, only the last one will
+ * have a cookie, and require unmapping.
+ */
+ if (desc->cookie) {
+ cookie = desc->cookie;
+
+ /* yes we are unmapping both _page and _single alloc'd
+ regions with unmap_page. Is this *really* that bad?
+ */
+ pci_unmap_page(chan->device->pdev,
+ pci_unmap_addr(desc, dst),
+ pci_unmap_len(desc, dst_len),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_page(chan->device->pdev,
+ pci_unmap_addr(desc, src),
+ pci_unmap_len(desc, src_len),
+ PCI_DMA_TODEVICE);
+ }
+
+ if (desc->phys != phys_complete) {
+ /* a completed entry, but not the last, so cleanup */
+ list_del(&desc->node);
+ list_add_tail(&desc->node, &chan->free_desc);
+ } else {
+ /* last used desc. Do not remove, so we can append from
+ it, but don't look at it next time, either */
+ desc->cookie = 0;
+
+ /* TODO check status bits? */
+ break;
+ }
+ }
+
+ spin_unlock_bh(&chan->desc_lock);
+
+ chan->last_completion = phys_complete;
+ if (cookie != 0)
+ chan->completed_cookie = cookie;
+
+ spin_unlock(&chan->cleanup_lock);
+}
+
+/**
+ * ioat_dma_is_complete - poll the status of a IOAT DMA transaction
+ * @chan: IOAT DMA channel handle
+ * @cookie: DMA transaction identifier
+ */
+
+static enum dma_status ioat_dma_is_complete(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ dma_cookie_t *done,
+ dma_cookie_t *used)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+
+ last_used = chan->cookie;
+ last_complete = ioat_chan->completed_cookie;
+
+ if (done)
+ *done= last_complete;
+ if (used)
+ *used = last_used;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret == DMA_SUCCESS)
+ return ret;
+
+ ioat_dma_memcpy_cleanup(ioat_chan);
+
+ last_used = chan->cookie;
+ last_complete = ioat_chan->completed_cookie;
+
+ if (done)
+ *done= last_complete;
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+/* PCI API */
+
+static struct pci_device_id ioat_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
+ { 0, }
+};
+
+static struct pci_driver ioat_pci_drv = {
+ .name = "ioatdma",
+ .id_table = ioat_pci_tbl,
+ .probe = ioat_probe,
+ .remove = __devexit_p(ioat_remove),
+};
+
+static irqreturn_t ioat_do_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+ struct ioat_device *instance = data;
+ unsigned long attnstatus;
+ u8 intrctrl;
+
+ intrctrl = ioatdma_read8(instance, IOAT_INTRCTRL_OFFSET);
+
+ if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
+ return IRQ_NONE;
+
+ if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
+ ioatdma_write8(instance, IOAT_INTRCTRL_OFFSET, intrctrl);
+ return IRQ_NONE;
+ }
+
+ attnstatus = ioatdma_read32(instance, IOAT_ATTNSTATUS_OFFSET);
+
+ printk(KERN_ERR "ioatdma error: interrupt! status %lx\n", attnstatus);
+
+ ioatdma_write8(instance, IOAT_INTRCTRL_OFFSET, intrctrl);
+ return IRQ_HANDLED;
+}
+
+static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan)
+{
+ struct ioat_desc_sw *desc;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+
+ if (!list_empty(&ioat_chan->free_desc)) {
+ desc = to_ioat_desc(ioat_chan->free_desc.next);
+ list_del(&desc->node);
+ } else {
+ /* try to get another desc */
+ spin_unlock_bh(&ioat_chan->desc_lock);
+ desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
+ spin_lock_bh(&ioat_chan->desc_lock);
+ /* will this ever happen? */
+ BUG_ON(!desc);
+ }
+
+ desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL;
+ desc->hw->next = 0;
+
+ list_add_tail(&desc->node, &ioat_chan->used_desc);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+#if (BITS_PER_LONG == 64)
+ ioatdma_chan_write64(ioat_chan, IOAT_CHAINADDR_OFFSET, desc->phys);
+#else
+ ioatdma_chan_write32(ioat_chan,
+ IOAT_CHAINADDR_OFFSET_LOW,
+ (u32) desc->phys);
+ ioatdma_chan_write32(ioat_chan, IOAT_CHAINADDR_OFFSET_HIGH, 0);
+#endif
+ ioatdma_chan_write8(ioat_chan, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_START);
+}
+
+/*
+ * Perform a IOAT transaction to verify the HW works.
+ */
+#define IOAT_TEST_SIZE 2000
+
+static int ioat_self_test(struct ioat_device *device)
+{
+ int i;
+ u8 *src;
+ u8 *dest;
+ struct dma_chan *dma_chan;
+ dma_cookie_t cookie;
+ int err = 0;
+
+ src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, SLAB_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, SLAB_KERNEL);
+ if (!dest) {
+ kfree(src);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffer */
+ for (i = 0; i < IOAT_TEST_SIZE; i++)
+ src[i] = (u8)i;
+
+ /* Start copy, using first DMA channel */
+ dma_chan = container_of(device->common.channels.next,
+ struct dma_chan,
+ device_node);
+ if (ioat_dma_alloc_chan_resources(dma_chan) < 1) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ cookie = ioat_dma_memcpy_buf_to_buf(dma_chan, dest, src, IOAT_TEST_SIZE);
+ ioat_dma_memcpy_issue_pending(dma_chan);
+ msleep(1);
+
+ if (ioat_dma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ printk(KERN_ERR "ioatdma: Self-test copy timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ if (memcmp(src, dest, IOAT_TEST_SIZE)) {
+ printk(KERN_ERR "ioatdma: Self-test copy failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ ioat_dma_free_chan_resources(dma_chan);
+out:
+ kfree(src);
+ kfree(dest);
+ return err;
+}
+
+static int __devinit ioat_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int err;
+ unsigned long mmio_start, mmio_len;
+ void *reg_base;
+ struct ioat_device *device;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto err_enable_device;
+
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err)
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err)
+ goto err_set_dma_mask;
+
+ err = pci_request_regions(pdev, ioat_pci_drv.name);
+ if (err)
+ goto err_request_regions;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ reg_base = ioremap(mmio_start, mmio_len);
+ if (!reg_base) {
+ err = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ err = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ /* DMA coherent memory pool for DMA descriptor allocations */
+ device->dma_pool = pci_pool_create("dma_desc_pool", pdev,
+ sizeof(struct ioat_dma_descriptor), 64, 0);
+ if (!device->dma_pool) {
+ err = -ENOMEM;
+ goto err_dma_pool;
+ }
+
+ device->completion_pool = pci_pool_create("completion_pool", pdev, sizeof(u64), SMP_CACHE_BYTES, SMP_CACHE_BYTES);
+ if (!device->completion_pool) {
+ err = -ENOMEM;
+ goto err_completion_pool;
+ }
+
+ device->pdev = pdev;
+ pci_set_drvdata(pdev, device);
+#ifdef CONFIG_PCI_MSI
+ if (pci_enable_msi(pdev) == 0) {
+ device->msi = 1;
+ } else {
+ device->msi = 0;
+ }
+#endif
+ err = request_irq(pdev->irq, &ioat_do_interrupt, SA_SHIRQ, "ioat",
+ device);
+ if (err)
+ goto err_irq;
+
+ device->reg_base = reg_base;
+
+ ioatdma_write8(device, IOAT_INTRCTRL_OFFSET, IOAT_INTRCTRL_MASTER_INT_EN);
+ pci_set_master(pdev);
+
+ INIT_LIST_HEAD(&device->common.channels);
+ enumerate_dma_channels(device);
+
+ device->common.device_alloc_chan_resources = ioat_dma_alloc_chan_resources;
+ device->common.device_free_chan_resources = ioat_dma_free_chan_resources;
+ device->common.device_memcpy_buf_to_buf = ioat_dma_memcpy_buf_to_buf;
+ device->common.device_memcpy_buf_to_pg = ioat_dma_memcpy_buf_to_pg;
+ device->common.device_memcpy_pg_to_pg = ioat_dma_memcpy_pg_to_pg;
+ device->common.device_memcpy_complete = ioat_dma_is_complete;
+ device->common.device_memcpy_issue_pending = ioat_dma_memcpy_issue_pending;
+ printk(KERN_INFO "Intel(R) I/OAT DMA Engine found, %d channels\n",
+ device->common.chancnt);
+
+ err = ioat_self_test(device);
+ if (err)
+ goto err_self_test;
+
+ dma_async_device_register(&device->common);
+
+ return 0;
+
+err_self_test:
+err_irq:
+ pci_pool_destroy(device->completion_pool);
+err_completion_pool:
+ pci_pool_destroy(device->dma_pool);
+err_dma_pool:
+ kfree(device);
+err_kzalloc:
+ iounmap(reg_base);
+err_ioremap:
+ pci_release_regions(pdev);
+err_request_regions:
+err_set_dma_mask:
+ pci_disable_device(pdev);
+err_enable_device:
+ return err;
+}
+
+static void __devexit ioat_remove(struct pci_dev *pdev)
+{
+ struct ioat_device *device;
+ struct dma_chan *chan, *_chan;
+ struct ioat_dma_chan *ioat_chan;
+
+ device = pci_get_drvdata(pdev);
+ dma_async_device_unregister(&device->common);
+
+ free_irq(device->pdev->irq, device);
+#ifdef CONFIG_PCI_MSI
+ if (device->msi)
+ pci_disable_msi(device->pdev);
+#endif
+ pci_pool_destroy(device->dma_pool);
+ pci_pool_destroy(device->completion_pool);
+ iounmap(device->reg_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) {
+ ioat_chan = to_ioat_chan(chan);
+ list_del(&chan->device_node);
+ kfree(ioat_chan);
+ }
+ kfree(device);
+}
+
+/* MODULE API */
+MODULE_VERSION("1.7");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+static int __init ioat_init_module(void)
+{
+ /* it's currently unsafe to unload this module */
+ /* if forced, worst case is that rmmod hangs */
+ if (THIS_MODULE != NULL)
+ THIS_MODULE->unsafe = 1;
+
+ return pci_module_init(&ioat_pci_drv);
+}
+
+module_init(ioat_init_module);
+
+static void __exit ioat_exit_module(void)
+{
+ pci_unregister_driver(&ioat_pci_drv);
+}
+
+module_exit(ioat_exit_module);
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
new file mode 100644
index 000000000000..a5d3b3644160
--- /dev/null
+++ b/drivers/dma/ioatdma.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef IOATDMA_H
+#define IOATDMA_H
+
+#include <linux/dmaengine.h>
+#include "ioatdma_hw.h"
+#include <linux/init.h>
+#include <linux/dmapool.h>
+#include <linux/cache.h>
+#include <linux/pci_ids.h>
+
+#define IOAT_LOW_COMPLETION_MASK 0xffffffc0
+
+extern struct list_head dma_device_list;
+extern struct list_head dma_client_list;
+
+/**
+ * struct ioat_device - internal representation of a IOAT device
+ * @pdev: PCI-Express device
+ * @reg_base: MMIO register space base address
+ * @dma_pool: for allocating DMA descriptors
+ * @common: embedded struct dma_device
+ * @msi: Message Signaled Interrupt number
+ */
+
+struct ioat_device {
+ struct pci_dev *pdev;
+ void *reg_base;
+ struct pci_pool *dma_pool;
+ struct pci_pool *completion_pool;
+
+ struct dma_device common;
+ u8 msi;
+};
+
+/**
+ * struct ioat_dma_chan - internal representation of a DMA channel
+ * @device:
+ * @reg_base:
+ * @sw_in_use:
+ * @completion:
+ * @completion_low:
+ * @completion_high:
+ * @completed_cookie: last cookie seen completed on cleanup
+ * @cookie: value of last cookie given to client
+ * @last_completion:
+ * @xfercap:
+ * @desc_lock:
+ * @free_desc:
+ * @used_desc:
+ * @resource:
+ * @device_node:
+ */
+
+struct ioat_dma_chan {
+
+ void *reg_base;
+
+ dma_cookie_t completed_cookie;
+ unsigned long last_completion;
+
+ u32 xfercap; /* XFERCAP register value expanded out */
+
+ spinlock_t cleanup_lock;
+ spinlock_t desc_lock;
+ struct list_head free_desc;
+ struct list_head used_desc;
+
+ int pending;
+
+ struct ioat_device *device;
+ struct dma_chan common;
+
+ dma_addr_t completion_addr;
+ union {
+ u64 full; /* HW completion writeback */
+ struct {
+ u32 low;
+ u32 high;
+ };
+ } *completion_virt;
+};
+
+/* wrapper around hardware descriptor format + additional software fields */
+
+/**
+ * struct ioat_desc_sw - wrapper around hardware descriptor
+ * @hw: hardware DMA descriptor
+ * @node:
+ * @cookie:
+ * @phys:
+ */
+
+struct ioat_desc_sw {
+ struct ioat_dma_descriptor *hw;
+ struct list_head node;
+ dma_cookie_t cookie;
+ dma_addr_t phys;
+ DECLARE_PCI_UNMAP_ADDR(src)
+ DECLARE_PCI_UNMAP_LEN(src_len)
+ DECLARE_PCI_UNMAP_ADDR(dst)
+ DECLARE_PCI_UNMAP_LEN(dst_len)
+};
+
+#endif /* IOATDMA_H */
+
diff --git a/drivers/dma/ioatdma_hw.h b/drivers/dma/ioatdma_hw.h
new file mode 100644
index 000000000000..4d7a12880be3
--- /dev/null
+++ b/drivers/dma/ioatdma_hw.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef _IOAT_HW_H_
+#define _IOAT_HW_H_
+
+/* PCI Configuration Space Values */
+#define IOAT_PCI_VID 0x8086
+#define IOAT_PCI_DID 0x1A38
+#define IOAT_PCI_RID 0x00
+#define IOAT_PCI_SVID 0x8086
+#define IOAT_PCI_SID 0x8086
+#define IOAT_VER 0x12 /* Version 1.2 */
+
+struct ioat_dma_descriptor {
+ uint32_t size;
+ uint32_t ctl;
+ uint64_t src_addr;
+ uint64_t dst_addr;
+ uint64_t next;
+ uint64_t rsv1;
+ uint64_t rsv2;
+ uint64_t user1;
+ uint64_t user2;
+};
+
+#define IOAT_DMA_DESCRIPTOR_CTL_INT_GN 0x00000001
+#define IOAT_DMA_DESCRIPTOR_CTL_SRC_SN 0x00000002
+#define IOAT_DMA_DESCRIPTOR_CTL_DST_SN 0x00000004
+#define IOAT_DMA_DESCRIPTOR_CTL_CP_STS 0x00000008
+#define IOAT_DMA_DESCRIPTOR_CTL_FRAME 0x00000010
+#define IOAT_DMA_DESCRIPTOR_NUL 0x00000020
+#define IOAT_DMA_DESCRIPTOR_OPCODE 0xFF000000
+
+#endif
diff --git a/drivers/dma/ioatdma_io.h b/drivers/dma/ioatdma_io.h
new file mode 100644
index 000000000000..c0b4bf66c920
--- /dev/null
+++ b/drivers/dma/ioatdma_io.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef IOATDMA_IO_H
+#define IOATDMA_IO_H
+
+#include <asm/io.h>
+
+/*
+ * device and per-channel MMIO register read and write functions
+ * this is a lot of anoying inline functions, but it's typesafe
+ */
+
+static inline u8 ioatdma_read8(struct ioat_device *device,
+ unsigned int offset)
+{
+ return readb(device->reg_base + offset);
+}
+
+static inline u16 ioatdma_read16(struct ioat_device *device,
+ unsigned int offset)
+{
+ return readw(device->reg_base + offset);
+}
+
+static inline u32 ioatdma_read32(struct ioat_device *device,
+ unsigned int offset)
+{
+ return readl(device->reg_base + offset);
+}
+
+static inline void ioatdma_write8(struct ioat_device *device,
+ unsigned int offset, u8 value)
+{
+ writeb(value, device->reg_base + offset);
+}
+
+static inline void ioatdma_write16(struct ioat_device *device,
+ unsigned int offset, u16 value)
+{
+ writew(value, device->reg_base + offset);
+}
+
+static inline void ioatdma_write32(struct ioat_device *device,
+ unsigned int offset, u32 value)
+{
+ writel(value, device->reg_base + offset);
+}
+
+static inline u8 ioatdma_chan_read8(struct ioat_dma_chan *chan,
+ unsigned int offset)
+{
+ return readb(chan->reg_base + offset);
+}
+
+static inline u16 ioatdma_chan_read16(struct ioat_dma_chan *chan,
+ unsigned int offset)
+{
+ return readw(chan->reg_base + offset);
+}
+
+static inline u32 ioatdma_chan_read32(struct ioat_dma_chan *chan,
+ unsigned int offset)
+{
+ return readl(chan->reg_base + offset);
+}
+
+static inline void ioatdma_chan_write8(struct ioat_dma_chan *chan,
+ unsigned int offset, u8 value)
+{
+ writeb(value, chan->reg_base + offset);
+}
+
+static inline void ioatdma_chan_write16(struct ioat_dma_chan *chan,
+ unsigned int offset, u16 value)
+{
+ writew(value, chan->reg_base + offset);
+}
+
+static inline void ioatdma_chan_write32(struct ioat_dma_chan *chan,
+ unsigned int offset, u32 value)
+{
+ writel(value, chan->reg_base + offset);
+}
+
+#if (BITS_PER_LONG == 64)
+static inline u64 ioatdma_chan_read64(struct ioat_dma_chan *chan,
+ unsigned int offset)
+{
+ return readq(chan->reg_base + offset);
+}
+
+static inline void ioatdma_chan_write64(struct ioat_dma_chan *chan,
+ unsigned int offset, u64 value)
+{
+ writeq(value, chan->reg_base + offset);
+}
+#endif
+
+#endif /* IOATDMA_IO_H */
+
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h
new file mode 100644
index 000000000000..41a21ab2b000
--- /dev/null
+++ b/drivers/dma/ioatdma_registers.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef _IOAT_REGISTERS_H_
+#define _IOAT_REGISTERS_H_
+
+
+/* MMIO Device Registers */
+#define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */
+
+#define IOAT_XFERCAP_OFFSET 0x01 /* 8-bit */
+#define IOAT_XFERCAP_4KB 12
+#define IOAT_XFERCAP_8KB 13
+#define IOAT_XFERCAP_16KB 14
+#define IOAT_XFERCAP_32KB 15
+#define IOAT_XFERCAP_32GB 0
+
+#define IOAT_GENCTRL_OFFSET 0x02 /* 8-bit */
+#define IOAT_GENCTRL_DEBUG_EN 0x01
+
+#define IOAT_INTRCTRL_OFFSET 0x03 /* 8-bit */
+#define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */
+#define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */
+#define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */
+
+#define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */
+
+#define IOAT_VER_OFFSET 0x08 /* 8-bit */
+#define IOAT_VER_MAJOR_MASK 0xF0
+#define IOAT_VER_MINOR_MASK 0x0F
+#define GET_IOAT_VER_MAJOR(x) ((x) & IOAT_VER_MAJOR_MASK)
+#define GET_IOAT_VER_MINOR(x) ((x) & IOAT_VER_MINOR_MASK)
+
+#define IOAT_PERPORTOFFSET_OFFSET 0x0A /* 16-bit */
+
+#define IOAT_INTRDELAY_OFFSET 0x0C /* 16-bit */
+#define IOAT_INTRDELAY_INT_DELAY_MASK 0x3FFF /* Interrupt Delay Time */
+#define IOAT_INTRDELAY_COALESE_SUPPORT 0x8000 /* Interrupt Coalesing Supported */
+
+#define IOAT_DEVICE_STATUS_OFFSET 0x0E /* 16-bit */
+#define IOAT_DEVICE_STATUS_DEGRADED_MODE 0x0001
+
+
+#define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */
+
+/* DMA Channel Registers */
+#define IOAT_CHANCTRL_OFFSET 0x00 /* 16-bit Channel Control Register */
+#define IOAT_CHANCTRL_CHANNEL_PRIORITY_MASK 0xF000
+#define IOAT_CHANCTRL_CHANNEL_IN_USE 0x0100
+#define IOAT_CHANCTRL_DESCRIPTOR_ADDR_SNOOP_CONTROL 0x0020
+#define IOAT_CHANCTRL_ERR_INT_EN 0x0010
+#define IOAT_CHANCTRL_ANY_ERR_ABORT_EN 0x0008
+#define IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004
+#define IOAT_CHANCTRL_INT_DISABLE 0x0001
+
+#define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatability */
+#define IOAT_DMA_COMP_V1 0x0001 /* Compatability with DMA version 1 */
+
+#define IOAT_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
+#define IOAT_CHANSTS_OFFSET_LOW 0x04
+#define IOAT_CHANSTS_OFFSET_HIGH 0x08
+#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR 0xFFFFFFFFFFFFFFC0
+#define IOAT_CHANSTS_SOFT_ERR 0x0000000000000010
+#define IOAT_CHANSTS_DMA_TRANSFER_STATUS 0x0000000000000007
+#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE 0x0
+#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE 0x1
+#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_SUSPENDED 0x2
+#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED 0x3
+
+#define IOAT_CHAINADDR_OFFSET 0x0C /* 64-bit Descriptor Chain Address Register */
+#define IOAT_CHAINADDR_OFFSET_LOW 0x0C
+#define IOAT_CHAINADDR_OFFSET_HIGH 0x10
+
+#define IOAT_CHANCMD_OFFSET 0x14 /* 8-bit DMA Channel Command Register */
+#define IOAT_CHANCMD_RESET 0x20
+#define IOAT_CHANCMD_RESUME 0x10
+#define IOAT_CHANCMD_ABORT 0x08
+#define IOAT_CHANCMD_SUSPEND 0x04
+#define IOAT_CHANCMD_APPEND 0x02
+#define IOAT_CHANCMD_START 0x01
+
+#define IOAT_CHANCMP_OFFSET 0x18 /* 64-bit Channel Completion Address Register */
+#define IOAT_CHANCMP_OFFSET_LOW 0x18
+#define IOAT_CHANCMP_OFFSET_HIGH 0x1C
+
+#define IOAT_CDAR_OFFSET 0x20 /* 64-bit Current Descriptor Address Register */
+#define IOAT_CDAR_OFFSET_LOW 0x20
+#define IOAT_CDAR_OFFSET_HIGH 0x24
+
+#define IOAT_CHANERR_OFFSET 0x28 /* 32-bit Channel Error Register */
+#define IOAT_CHANERR_DMA_TRANSFER_SRC_ADDR_ERR 0x0001
+#define IOAT_CHANERR_DMA_TRANSFER_DEST_ADDR_ERR 0x0002
+#define IOAT_CHANERR_NEXT_DESCRIPTOR_ADDR_ERR 0x0004
+#define IOAT_CHANERR_NEXT_DESCRIPTOR_ALIGNMENT_ERR 0x0008
+#define IOAT_CHANERR_CHAIN_ADDR_VALUE_ERR 0x0010
+#define IOAT_CHANERR_CHANCMD_ERR 0x0020
+#define IOAT_CHANERR_CHIPSET_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0040
+#define IOAT_CHANERR_DMA_UNCORRECTABLE_DATA_INTEGRITY_ERR 0x0080
+#define IOAT_CHANERR_READ_DATA_ERR 0x0100
+#define IOAT_CHANERR_WRITE_DATA_ERR 0x0200
+#define IOAT_CHANERR_DESCRIPTOR_CONTROL_ERR 0x0400
+#define IOAT_CHANERR_DESCRIPTOR_LENGTH_ERR 0x0800
+#define IOAT_CHANERR_COMPLETION_ADDR_ERR 0x1000
+#define IOAT_CHANERR_INT_CONFIGURATION_ERR 0x2000
+#define IOAT_CHANERR_SOFT_ERR 0x4000
+
+#define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
+
+#endif /* _IOAT_REGISTERS_H_ */
diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c
new file mode 100644
index 000000000000..5ed327e453a2
--- /dev/null
+++ b/drivers/dma/iovlock.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ * Portions based on net/core/datagram.c and copyrighted by their authors.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This code allows the net stack to make use of a DMA engine for
+ * skb to iovec copies.
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/pagemap.h>
+#include <net/tcp.h> /* for memcpy_toiovec */
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+int num_pages_spanned(struct iovec *iov)
+{
+ return
+ ((PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) -
+ ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT);
+}
+
+/*
+ * Pin down all the iovec pages needed for len bytes.
+ * Return a struct dma_pinned_list to keep track of pages pinned down.
+ *
+ * We are allocating a single chunk of memory, and then carving it up into
+ * 3 sections, the latter 2 whose size depends on the number of iovecs and the
+ * total number of pages, respectively.
+ */
+struct dma_pinned_list *dma_pin_iovec_pages(struct iovec *iov, size_t len)
+{
+ struct dma_pinned_list *local_list;
+ struct page **pages;
+ int i;
+ int ret;
+ int nr_iovecs = 0;
+ int iovec_len_used = 0;
+ int iovec_pages_used = 0;
+ long err;
+
+ /* don't pin down non-user-based iovecs */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return NULL;
+
+ /* determine how many iovecs/pages there are, up front */
+ do {
+ iovec_len_used += iov[nr_iovecs].iov_len;
+ iovec_pages_used += num_pages_spanned(&iov[nr_iovecs]);
+ nr_iovecs++;
+ } while (iovec_len_used < len);
+
+ /* single kmalloc for pinned list, page_list[], and the page arrays */
+ local_list = kmalloc(sizeof(*local_list)
+ + (nr_iovecs * sizeof (struct dma_page_list))
+ + (iovec_pages_used * sizeof (struct page*)), GFP_KERNEL);
+ if (!local_list) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* list of pages starts right after the page list array */
+ pages = (struct page **) &local_list->page_list[nr_iovecs];
+
+ for (i = 0; i < nr_iovecs; i++) {
+ struct dma_page_list *page_list = &local_list->page_list[i];
+
+ len -= iov[i].iov_len;
+
+ if (!access_ok(VERIFY_WRITE, iov[i].iov_base, iov[i].iov_len)) {
+ err = -EFAULT;
+ goto unpin;
+ }
+
+ page_list->nr_pages = num_pages_spanned(&iov[i]);
+ page_list->base_address = iov[i].iov_base;
+
+ page_list->pages = pages;
+ pages += page_list->nr_pages;
+
+ /* pin pages down */
+ down_read(&current->mm->mmap_sem);
+ ret = get_user_pages(
+ current,
+ current->mm,
+ (unsigned long) iov[i].iov_base,
+ page_list->nr_pages,
+ 1, /* write */
+ 0, /* force */
+ page_list->pages,
+ NULL);
+ up_read(&current->mm->mmap_sem);
+
+ if (ret != page_list->nr_pages) {
+ err = -ENOMEM;
+ goto unpin;
+ }
+
+ local_list->nr_iovecs = i + 1;
+ }
+
+ return local_list;
+
+unpin:
+ dma_unpin_iovec_pages(local_list);
+out:
+ return ERR_PTR(err);
+}
+
+void dma_unpin_iovec_pages(struct dma_pinned_list *pinned_list)
+{
+ int i, j;
+
+ if (!pinned_list)
+ return;
+
+ for (i = 0; i < pinned_list->nr_iovecs; i++) {
+ struct dma_page_list *page_list = &pinned_list->page_list[i];
+ for (j = 0; j < page_list->nr_pages; j++) {
+ set_page_dirty_lock(page_list->pages[j]);
+ page_cache_release(page_list->pages[j]);
+ }
+ }
+
+ kfree(pinned_list);
+}
+
+static dma_cookie_t dma_memcpy_to_kernel_iovec(struct dma_chan *chan, struct
+ iovec *iov, unsigned char *kdata, size_t len)
+{
+ dma_cookie_t dma_cookie = 0;
+
+ while (len > 0) {
+ if (iov->iov_len) {
+ int copy = min_t(unsigned int, iov->iov_len, len);
+ dma_cookie = dma_async_memcpy_buf_to_buf(
+ chan,
+ iov->iov_base,
+ kdata,
+ copy);
+ kdata += copy;
+ len -= copy;
+ iov->iov_len -= copy;
+ iov->iov_base += copy;
+ }
+ iov++;
+ }
+
+ return dma_cookie;
+}
+
+/*
+ * We have already pinned down the pages we will be using in the iovecs.
+ * Each entry in iov array has corresponding entry in pinned_list->page_list.
+ * Using array indexing to keep iov[] and page_list[] in sync.
+ * Initial elements in iov array's iov->iov_len will be 0 if already copied into
+ * by another call.
+ * iov array length remaining guaranteed to be bigger than len.
+ */
+dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov,
+ struct dma_pinned_list *pinned_list, unsigned char *kdata, size_t len)
+{
+ int iov_byte_offset;
+ int copy;
+ dma_cookie_t dma_cookie = 0;
+ int iovec_idx;
+ int page_idx;
+
+ if (!chan)
+ return memcpy_toiovec(iov, kdata, len);
+
+ /* -> kernel copies (e.g. smbfs) */
+ if (!pinned_list)
+ return dma_memcpy_to_kernel_iovec(chan, iov, kdata, len);
+
+ iovec_idx = 0;
+ while (iovec_idx < pinned_list->nr_iovecs) {
+ struct dma_page_list *page_list;
+
+ /* skip already used-up iovecs */
+ while (!iov[iovec_idx].iov_len)
+ iovec_idx++;
+
+ page_list = &pinned_list->page_list[iovec_idx];
+
+ iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK);
+ page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK)
+ - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT;
+
+ /* break up copies to not cross page boundary */
+ while (iov[iovec_idx].iov_len) {
+ copy = min_t(int, PAGE_SIZE - iov_byte_offset, len);
+ copy = min_t(int, copy, iov[iovec_idx].iov_len);
+
+ dma_cookie = dma_async_memcpy_buf_to_pg(chan,
+ page_list->pages[page_idx],
+ iov_byte_offset,
+ kdata,
+ copy);
+
+ len -= copy;
+ iov[iovec_idx].iov_len -= copy;
+ iov[iovec_idx].iov_base += copy;
+
+ if (!len)
+ return dma_cookie;
+
+ kdata += copy;
+ iov_byte_offset = 0;
+ page_idx++;
+ }
+ iovec_idx++;
+ }
+
+ /* really bad if we ever run out of iovecs */
+ BUG();
+ return -EFAULT;
+}
+
+dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov,
+ struct dma_pinned_list *pinned_list, struct page *page,
+ unsigned int offset, size_t len)
+{
+ int iov_byte_offset;
+ int copy;
+ dma_cookie_t dma_cookie = 0;
+ int iovec_idx;
+ int page_idx;
+ int err;
+
+ /* this needs as-yet-unimplemented buf-to-buff, so punt. */
+ /* TODO: use dma for this */
+ if (!chan || !pinned_list) {
+ u8 *vaddr = kmap(page);
+ err = memcpy_toiovec(iov, vaddr + offset, len);
+ kunmap(page);
+ return err;
+ }
+
+ iovec_idx = 0;
+ while (iovec_idx < pinned_list->nr_iovecs) {
+ struct dma_page_list *page_list;
+
+ /* skip already used-up iovecs */
+ while (!iov[iovec_idx].iov_len)
+ iovec_idx++;
+
+ page_list = &pinned_list->page_list[iovec_idx];
+
+ iov_byte_offset = ((unsigned long)iov[iovec_idx].iov_base & ~PAGE_MASK);
+ page_idx = (((unsigned long)iov[iovec_idx].iov_base & PAGE_MASK)
+ - ((unsigned long)page_list->base_address & PAGE_MASK)) >> PAGE_SHIFT;
+
+ /* break up copies to not cross page boundary */
+ while (iov[iovec_idx].iov_len) {
+ copy = min_t(int, PAGE_SIZE - iov_byte_offset, len);
+ copy = min_t(int, copy, iov[iovec_idx].iov_len);
+
+ dma_cookie = dma_async_memcpy_pg_to_pg(chan,
+ page_list->pages[page_idx],
+ iov_byte_offset,
+ page,
+ offset,
+ copy);
+
+ len -= copy;
+ iov[iovec_idx].iov_len -= copy;
+ iov[iovec_idx].iov_base += copy;
+
+ if (!len)
+ return dma_cookie;
+
+ offset += copy;
+ iov_byte_offset = 0;
+ page_idx++;
+ }
+ iovec_idx++;
+ }
+
+ /* really bad if we ever run out of iovecs */
+ BUG();
+ return -EFAULT;
+}
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 66572c5323ad..fce31936e6d7 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -25,6 +25,8 @@
#include <linux/slab.h>
#include "edac_mc.h"
+static int force_function_unhide;
+
#define e752x_printk(level, fmt, arg...) \
edac_printk(level, "e752x", fmt, ##arg)
@@ -782,8 +784,16 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s(): mci\n", __func__);
debugf0("Starting Probe1\n");
- /* enable device 0 function 1 */
+ /* check to see if device 0 function 1 is enabled; if it isn't, we
+ * assume the BIOS has reserved it for a reason and is expecting
+ * exclusive access, we take care not to violate that assumption and
+ * fail the probe. */
pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
+ if (!force_function_unhide && !(stat8 & (1 << 5))) {
+ printk(KERN_INFO "Contact your BIOS vendor to see if the "
+ "E752x error registers can be safely un-hidden\n");
+ goto fail;
+ }
stat8 |= (1 << 5);
pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
@@ -1063,3 +1073,8 @@ module_exit(e752x_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
+
+module_param(force_function_unhide, int, 0444);
+MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
+" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 8bd305e47f0d..766cc969c4d0 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -133,6 +133,9 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+
+ /* Reset the status register */
+ outb(0, ACBST);
return;
}
@@ -228,6 +231,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface)
timeout = jiffies + POLL_TIMEOUT;
while (time_before(jiffies, timeout)) {
status = inb(ACBST);
+
+ /* Reset the status register to avoid the hang */
+ outb(0, ACBST);
+
if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
scx200_acb_machine(iface, status);
return;
@@ -415,7 +422,6 @@ static int __init scx200_acb_create(const char *text, int base, int index)
struct scx200_acb_iface *iface;
struct i2c_adapter *adapter;
int rc;
- char description[64];
iface = kzalloc(sizeof(*iface), GFP_KERNEL);
if (!iface) {
@@ -434,10 +440,7 @@ static int __init scx200_acb_create(const char *text, int base, int index)
mutex_init(&iface->mutex);
- snprintf(description, sizeof(description), "%s ACCESS.bus [%s]",
- text, adapter->name);
-
- if (request_region(base, 8, description) == 0) {
+ if (!request_region(base, 8, adapter->name)) {
printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n",
base, base + 8-1);
rc = -EBUSY;
@@ -488,7 +491,7 @@ static struct pci_device_id divil_pci[] = {
#define MSR_LBAR_SMB 0x5140000B
-static int scx200_add_cs553x(void)
+static __init int scx200_add_cs553x(void)
{
u32 low, hi;
u32 smb_base;
@@ -524,6 +527,9 @@ static int __init scx200_acb_init(void)
} else if (pci_dev_present(divil_pci))
rc = scx200_add_cs553x();
+ /* If at least one bus was created, init must succeed */
+ if (scx200_acb_list)
+ return 0;
return rc;
}
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 4961f1e764a7..602797a44208 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -392,6 +392,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 43b96e298363..27c9eb989a9a 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -345,17 +345,17 @@ sgiioc4_resetproc(ide_drive_t * drive)
static u8
sgiioc4_INB(unsigned long port)
{
- u8 reg = (u8) inb(port);
+ u8 reg = (u8) readb((void __iomem *) port);
if ((port & 0xFFF) == 0x11C) { /* Status register of IOC4 */
if (reg & 0x51) { /* Not busy...check for interrupt */
unsigned long other_ir = port - 0x110;
- unsigned int intr_reg = (u32) inl(other_ir);
+ unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
/* Clear the Interrupt, Error bits on the IOC4 */
if (intr_reg & 0x03) {
- outl(0x03, other_ir);
- intr_reg = (u32) inl(other_ir);
+ writel(0x03, (void __iomem *) other_ir);
+ intr_reg = (u32) readl((void __iomem *) other_ir);
}
}
}
@@ -606,6 +606,12 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
hwif->ide_dma_timeout = &__ide_dma_timeout;
+
+ /*
+ * The IOC4 uses MMIO rather than Port IO.
+ * It also needs special workarounds for INB.
+ */
+ default_hwif_mmiops(hwif);
hwif->INB = &sgiioc4_INB;
}
@@ -743,6 +749,6 @@ ioc4_ide_exit(void)
module_init(ioc4_ide_init);
module_exit(ioc4_ide_exit);
-MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
+MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 78e30f803671..ffca8b63ee79 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -553,6 +553,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
if (irq != NULL)
*irq = pmac_ide[ix].irq;
+
+ hw->dev = &pmac_ide[ix].mdev->ofdev.dev;
}
#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x)))
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 19222878aae9..11f13778f139 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -553,7 +553,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
* register content.
* To actually enable physical responses is the job of our interrupt
* handler which programs the physical request filter. */
- reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
+ reg_write(ohci, OHCI1394_PhyUpperBound, 0x01000000);
DBGMSG("physUpperBoundOffset=%08x",
reg_read(ohci, OHCI1394_PhyUpperBound));
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index f4206604db03..5413dc43b9f1 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -42,6 +42,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
+#include <linux/stringify.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
@@ -117,7 +118,8 @@ MODULE_PARM_DESC(serialize_io, "Serialize I/O coming from scsi drivers (default
*/
static int max_sectors = SBP2_MAX_SECTORS;
module_param(max_sectors, int, 0444);
-MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)");
+MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = "
+ __stringify(SBP2_MAX_SECTORS) ")");
/*
* Exclusive login to sbp2 device? In most cases, the sbp2 driver should
@@ -135,18 +137,45 @@ module_param(exclusive_login, int, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)");
/*
- * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on
- * if your sbp2 device is not properly handling the SCSI inquiry command.
- * This hack makes the inquiry look more like a typical MS Windows inquiry
- * by enforcing 36 byte inquiry and avoiding access to mode_sense page 8.
+ * If any of the following workarounds is required for your device to work,
+ * please submit the kernel messages logged by sbp2 to the linux1394-devel
+ * mailing list.
*
- * If force_inquiry_hack=1 is required for your device to work,
- * please submit the logged sbp2_firmware_revision value of this device to
- * the linux1394-devel mailing list.
+ * - 128kB max transfer
+ * Limit transfer size. Necessary for some old bridges.
+ *
+ * - 36 byte inquiry
+ * When scsi_mod probes the device, let the inquiry command look like that
+ * from MS Windows.
+ *
+ * - skip mode page 8
+ * Suppress sending of mode_sense for mode page 8 if the device pretends to
+ * support the SCSI Primary Block commands instead of Reduced Block Commands.
+ *
+ * - fix capacity
+ * Tell sd_mod to correct the last sector number reported by read_capacity.
+ * Avoids access beyond actual disk limits on devices with an off-by-one bug.
+ * Don't use this with devices which don't have this bug.
+ *
+ * - override internal blacklist
+ * Instead of adding to the built-in blacklist, use only the workarounds
+ * specified in the module load parameter.
+ * Useful if a blacklist entry interfered with a non-broken device.
*/
+static int sbp2_default_workarounds;
+module_param_named(workarounds, sbp2_default_workarounds, int, 0644);
+MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
+ ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
+ ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
+ ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
+ ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+ ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
+ ", or a combination)");
+
+/* legacy parameter */
static int force_inquiry_hack;
module_param(force_inquiry_hack, int, 0644);
-MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
+MODULE_PARM_DESC(force_inquiry_hack, "Deprecated, use 'workarounds'");
/*
* Export information about protocols/devices supported by this driver.
@@ -266,14 +295,55 @@ static struct hpsb_protocol_driver sbp2_driver = {
};
/*
- * List of device firmwares that require the inquiry hack.
- * Yields a few false positives but did not break other devices so far.
+ * List of devices with known bugs.
+ *
+ * The firmware_revision field, masked with 0xffff00, is the best indicator
+ * for the type of bridge chip of a device. It yields a few false positives
+ * but this did not break correctly behaving devices so far.
*/
-static u32 sbp2_broken_inquiry_list[] = {
- 0x00002800, /* Stefan Richter <stefanr@s5r6.in-berlin.de> */
- /* DViCO Momobay CX-1 */
- 0x00000200 /* Andreas Plesch <plesch@fas.harvard.edu> */
- /* QPS Fire DVDBurner */
+static const struct {
+ u32 firmware_revision;
+ u32 model_id;
+ unsigned workarounds;
+} sbp2_workarounds_table[] = {
+ /* TSB42AA9 */ {
+ .firmware_revision = 0x002800,
+ .workarounds = SBP2_WORKAROUND_INQUIRY_36 |
+ SBP2_WORKAROUND_MODE_SENSE_8,
+ },
+ /* Initio bridges, actually only needed for some older ones */ {
+ .firmware_revision = 0x000200,
+ .workarounds = SBP2_WORKAROUND_INQUIRY_36,
+ },
+ /* Symbios bridge */ {
+ .firmware_revision = 0xa0b800,
+ .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
+ },
+ /*
+ * Note about the following Apple iPod blacklist entries:
+ *
+ * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our
+ * matching logic treats 0 as a wildcard, we cannot match this ID
+ * without rewriting the matching routine. Fortunately these iPods
+ * do not feature the read_capacity bug according to one report.
+ * Read_capacity behaviour as well as model_id could change due to
+ * Apple-supplied firmware updates though.
+ */
+ /* iPod 4th generation */ {
+ .firmware_revision = 0x0a2700,
+ .model_id = 0x000021,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ },
+ /* iPod mini */ {
+ .firmware_revision = 0x0a2700,
+ .model_id = 0x000023,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ },
+ /* iPod Photo */ {
+ .firmware_revision = 0x0a2700,
+ .model_id = 0x00007e,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ }
};
/**************************************
@@ -765,12 +835,17 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
/* Register the status FIFO address range. We could use the same FIFO
* for targets at different nodes. However we need different FIFOs per
- * target in order to support multi-unit devices. */
+ * target in order to support multi-unit devices.
+ * The FIFO is located out of the local host controller's physical range
+ * but, if possible, within the posted write area. Status writes will
+ * then be performed as unified transactions. This slightly reduces
+ * bandwidth usage, and some Prolific based devices seem to require it.
+ */
scsi_id->status_fifo_addr = hpsb_allocate_and_register_addrspace(
&sbp2_highlevel, ud->ne->host, &sbp2_ops,
sizeof(struct sbp2_status_block), sizeof(quadlet_t),
- ~0ULL, ~0ULL);
- if (!scsi_id->status_fifo_addr) {
+ 0x010000000000ULL, CSR1212_ALL_SPACE_END);
+ if (scsi_id->status_fifo_addr == ~0ULL) {
SBP2_ERR("failed to allocate status FIFO address range");
goto failed_alloc;
}
@@ -1450,7 +1525,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
struct csr1212_dentry *dentry;
u64 management_agent_addr;
u32 command_set_spec_id, command_set, unit_characteristics,
- firmware_revision, workarounds;
+ firmware_revision;
+ unsigned workarounds;
int i;
SBP2_DEBUG_ENTER();
@@ -1506,12 +1582,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
case SBP2_FIRMWARE_REVISION_KEY:
/* Firmware revision */
firmware_revision = kv->value.immediate;
- if (force_inquiry_hack)
- SBP2_INFO("sbp2_firmware_revision = %x",
- (unsigned int)firmware_revision);
- else
- SBP2_DEBUG("sbp2_firmware_revision = %x",
- (unsigned int)firmware_revision);
+ SBP2_DEBUG("sbp2_firmware_revision = %x",
+ (unsigned int)firmware_revision);
break;
default:
@@ -1519,41 +1591,44 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
}
}
- /* This is the start of our broken device checking. We try to hack
- * around oddities and known defects. */
- workarounds = 0x0;
+ workarounds = sbp2_default_workarounds;
+ if (force_inquiry_hack) {
+ SBP2_WARN("force_inquiry_hack is deprecated. "
+ "Use parameter 'workarounds' instead.");
+ workarounds |= SBP2_WORKAROUND_INQUIRY_36;
+ }
- /* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a
- * bridge with 128KB max transfer size limitation. For sanity, we
- * only voice this when the current max_sectors setting
- * exceeds the 128k limit. By default, that is not the case.
- *
- * It would be really nice if we could detect this before the scsi
- * host gets initialized. That way we can down-force the
- * max_sectors to account for it. That is not currently
- * possible. */
- if ((firmware_revision & 0xffff00) ==
- SBP2_128KB_BROKEN_FIRMWARE &&
- (max_sectors * 512) > (128*1024)) {
- SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
- SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",
- max_sectors);
- workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
- }
-
- /* Check for a blacklisted set of devices that require us to force
- * a 36 byte host inquiry. This can be overriden as a module param
- * (to force all hosts). */
- for (i = 0; i < ARRAY_SIZE(sbp2_broken_inquiry_list); i++) {
- if ((firmware_revision & 0xffff00) ==
- sbp2_broken_inquiry_list[i]) {
- SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
- workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
- break; /* No need to continue. */
+ if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
+ for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
+ if (sbp2_workarounds_table[i].firmware_revision &&
+ sbp2_workarounds_table[i].firmware_revision !=
+ (firmware_revision & 0xffff00))
+ continue;
+ if (sbp2_workarounds_table[i].model_id &&
+ sbp2_workarounds_table[i].model_id != ud->model_id)
+ continue;
+ workarounds |= sbp2_workarounds_table[i].workarounds;
+ break;
}
- }
+
+ if (workarounds)
+ SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x "
+ "(firmware_revision 0x%06x, vendor_id 0x%06x,"
+ " model_id 0x%06x)",
+ NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
+ workarounds, firmware_revision,
+ ud->vendor_id ? ud->vendor_id : ud->ne->vendor_id,
+ ud->model_id);
+
+ /* We would need one SCSI host template for each target to adjust
+ * max_sectors on the fly, therefore warn only. */
+ if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
+ (max_sectors * 512) > (128 * 1024))
+ SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB "
+ "max transfer size. WARNING: Current max_sectors "
+ "setting is larger than 128KB (%d sectors)",
+ NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
+ max_sectors);
/* If this is a logical unit directory entry, process the parent
* to get the values. */
@@ -2447,19 +2522,25 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
scsi_id->sdev = sdev;
- if (force_inquiry_hack ||
- scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK) {
+ if (scsi_id->workarounds & SBP2_WORKAROUND_INQUIRY_36)
sdev->inquiry_len = 36;
- sdev->skip_ms_page_8 = 1;
- }
return 0;
}
static int sbp2scsi_slave_configure(struct scsi_device *sdev)
{
+ struct scsi_id_instance_data *scsi_id =
+ (struct scsi_id_instance_data *)sdev->host->hostdata[0];
+
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ if (sdev->type == TYPE_DISK &&
+ scsi_id->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
+ sdev->skip_ms_page_8 = 1;
+ if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
+ sdev->fix_capacity = 1;
return 0;
}
@@ -2603,7 +2684,9 @@ static int sbp2_module_init(void)
scsi_driver_template.cmd_per_lun = 1;
}
- /* Set max sectors (module load option). Default is 255 sectors. */
+ if (sbp2_default_workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
+ (max_sectors * 512) > (128 * 1024))
+ max_sectors = 128 * 1024 / 512;
scsi_driver_template.max_sectors = max_sectors;
/* Register our high level driver with 1394 stack */
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index e2d357a9ea3a..f4ccc9d0fba4 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -227,11 +227,6 @@ struct sbp2_status_block {
#define SBP2_SW_VERSION_ENTRY 0x00010483
/*
- * Other misc defines
- */
-#define SBP2_128KB_BROKEN_FIRMWARE 0xa0b800
-
-/*
* SCSI specific stuff
*/
@@ -239,6 +234,13 @@ struct sbp2_status_block {
#define SBP2_MAX_SECTORS 255 /* Max sectors supported */
#define SBP2_MAX_CMDS 8 /* This should be safe */
+/* Flags for detected oddities and brokeness */
+#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
+#define SBP2_WORKAROUND_INQUIRY_36 0x2
+#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
+#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
+#define SBP2_WORKAROUND_OVERRIDE 0x100
+
/* This is the two dma types we use for cmd_dma below */
enum cmd_dma_types {
CMD_DMA_NONE,
@@ -268,10 +270,6 @@ struct sbp2_command_info {
};
-/* A list of flags for detected oddities and brokeness. */
-#define SBP2_BREAKAGE_128K_MAX_TRANSFER 0x1
-#define SBP2_BREAKAGE_INQUIRY_HACK 0x2
-
struct sbp2scsi_host_info;
/*
@@ -345,7 +343,7 @@ struct scsi_id_instance_data {
struct Scsi_Host *scsi_host;
/* Device specific workarounds/brokeness */
- u32 workarounds;
+ unsigned workarounds;
};
/* Sbp2 host data structure (one per IEEE1394 host) */
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index afc612b8577d..ba2d6505e9a4 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -29,6 +29,11 @@ config INFINIBAND_USER_ACCESS
libibverbs, libibcm and a hardware driver library from
<http://www.openib.org>.
+config INFINIBAND_ADDR_TRANS
+ bool
+ depends on INFINIBAND && INET
+ default y
+
source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/hw/ipath/Kconfig"
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index ec3353f24b27..68e73ec2d1f8 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,5 +1,7 @@
+infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o
+
obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \
- ib_cm.o
+ ib_cm.o $(infiniband-y)
obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o
@@ -12,8 +14,13 @@ ib_sa-y := sa_query.o
ib_cm-y := cm.o
+rdma_cm-y := cma.o
+
+ib_addr-y := addr.o
+
ib_umad-y := user_mad.o
ib_ucm-y := ucm.o
-ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o
+ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o \
+ uverbs_marshall.o
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
new file mode 100644
index 000000000000..d294bbc42f09
--- /dev/null
+++ b/drivers/infiniband/core/addr.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2005 Voltaire Inc. All rights reserved.
+ * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved.
+ * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved.
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ *
+ * This Software is licensed under one of the following licenses:
+ *
+ * 1) under the terms of the "Common Public License 1.0" a copy of which is
+ * available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/cpl.php.
+ *
+ * 2) under the terms of the "The BSD License" a copy of which is
+ * available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/bsd-license.php.
+ *
+ * 3) under the terms of the "GNU General Public License (GPL) Version 2" a
+ * copy of which is available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/gpl-license.php.
+ *
+ * Licensee has the right to choose one of the above licenses.
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice and one of the license notices.
+ *
+ * Redistributions in binary form must reproduce both the above copyright
+ * notice, one of the license notices in the documentation
+ * and/or other materials provided with the distribution.
+ */
+
+#include <linux/mutex.h>
+#include <linux/inetdevice.h>
+#include <linux/workqueue.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <rdma/ib_addr.h>
+
+MODULE_AUTHOR("Sean Hefty");
+MODULE_DESCRIPTION("IB Address Translation");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct addr_req {
+ struct list_head list;
+ struct sockaddr src_addr;
+ struct sockaddr dst_addr;
+ struct rdma_dev_addr *addr;
+ void *context;
+ void (*callback)(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context);
+ unsigned long timeout;
+ int status;
+};
+
+static void process_req(void *data);
+
+static DEFINE_MUTEX(lock);
+static LIST_HEAD(req_list);
+static DECLARE_WORK(work, process_req, NULL);
+static struct workqueue_struct *addr_wq;
+
+static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
+ unsigned char *dst_dev_addr)
+{
+ switch (dev->type) {
+ case ARPHRD_INFINIBAND:
+ dev_addr->dev_type = IB_NODE_CA;
+ break;
+ default:
+ return -EADDRNOTAVAIL;
+ }
+
+ memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+ memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN);
+ if (dst_dev_addr)
+ memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
+ return 0;
+}
+
+int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
+{
+ struct net_device *dev;
+ u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ int ret;
+
+ dev = ip_dev_find(ip);
+ if (!dev)
+ return -EADDRNOTAVAIL;
+
+ ret = copy_addr(dev_addr, dev, NULL);
+ dev_put(dev);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_translate_ip);
+
+static void set_timeout(unsigned long time)
+{
+ unsigned long delay;
+
+ cancel_delayed_work(&work);
+
+ delay = time - jiffies;
+ if ((long)delay <= 0)
+ delay = 1;
+
+ queue_delayed_work(addr_wq, &work, delay);
+}
+
+static void queue_req(struct addr_req *req)
+{
+ struct addr_req *temp_req;
+
+ mutex_lock(&lock);
+ list_for_each_entry_reverse(temp_req, &req_list, list) {
+ if (time_after(req->timeout, temp_req->timeout))
+ break;
+ }
+
+ list_add(&req->list, &temp_req->list);
+
+ if (req_list.next == &req->list)
+ set_timeout(req->timeout);
+ mutex_unlock(&lock);
+}
+
+static void addr_send_arp(struct sockaddr_in *dst_in)
+{
+ struct rtable *rt;
+ struct flowi fl;
+ u32 dst_ip = dst_in->sin_addr.s_addr;
+
+ memset(&fl, 0, sizeof fl);
+ fl.nl_u.ip4_u.daddr = dst_ip;
+ if (ip_route_output_key(&rt, &fl))
+ return;
+
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev,
+ rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL);
+ ip_rt_put(rt);
+}
+
+static int addr_resolve_remote(struct sockaddr_in *src_in,
+ struct sockaddr_in *dst_in,
+ struct rdma_dev_addr *addr)
+{
+ u32 src_ip = src_in->sin_addr.s_addr;
+ u32 dst_ip = dst_in->sin_addr.s_addr;
+ struct flowi fl;
+ struct rtable *rt;
+ struct neighbour *neigh;
+ int ret;
+
+ memset(&fl, 0, sizeof fl);
+ fl.nl_u.ip4_u.daddr = dst_ip;
+ fl.nl_u.ip4_u.saddr = src_ip;
+ ret = ip_route_output_key(&rt, &fl);
+ if (ret)
+ goto out;
+
+ /* If the device does ARP internally, return 'done' */
+ if (rt->idev->dev->flags & IFF_NOARP) {
+ copy_addr(addr, rt->idev->dev, NULL);
+ goto put;
+ }
+
+ neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
+ if (!neigh) {
+ ret = -ENODATA;
+ goto put;
+ }
+
+ if (!(neigh->nud_state & NUD_VALID)) {
+ ret = -ENODATA;
+ goto release;
+ }
+
+ if (!src_ip) {
+ src_in->sin_family = dst_in->sin_family;
+ src_in->sin_addr.s_addr = rt->rt_src;
+ }
+
+ ret = copy_addr(addr, neigh->dev, neigh->ha);
+release:
+ neigh_release(neigh);
+put:
+ ip_rt_put(rt);
+out:
+ return ret;
+}
+
+static void process_req(void *data)
+{
+ struct addr_req *req, *temp_req;
+ struct sockaddr_in *src_in, *dst_in;
+ struct list_head done_list;
+
+ INIT_LIST_HEAD(&done_list);
+
+ mutex_lock(&lock);
+ list_for_each_entry_safe(req, temp_req, &req_list, list) {
+ if (req->status) {
+ src_in = (struct sockaddr_in *) &req->src_addr;
+ dst_in = (struct sockaddr_in *) &req->dst_addr;
+ req->status = addr_resolve_remote(src_in, dst_in,
+ req->addr);
+ }
+ if (req->status && time_after(jiffies, req->timeout))
+ req->status = -ETIMEDOUT;
+ else if (req->status == -ENODATA)
+ continue;
+
+ list_del(&req->list);
+ list_add_tail(&req->list, &done_list);
+ }
+
+ if (!list_empty(&req_list)) {
+ req = list_entry(req_list.next, struct addr_req, list);
+ set_timeout(req->timeout);
+ }
+ mutex_unlock(&lock);
+
+ list_for_each_entry_safe(req, temp_req, &done_list, list) {
+ list_del(&req->list);
+ req->callback(req->status, &req->src_addr, req->addr,
+ req->context);
+ kfree(req);
+ }
+}
+
+static int addr_resolve_local(struct sockaddr_in *src_in,
+ struct sockaddr_in *dst_in,
+ struct rdma_dev_addr *addr)
+{
+ struct net_device *dev;
+ u32 src_ip = src_in->sin_addr.s_addr;
+ u32 dst_ip = dst_in->sin_addr.s_addr;
+ int ret;
+
+ dev = ip_dev_find(dst_ip);
+ if (!dev)
+ return -EADDRNOTAVAIL;
+
+ if (ZERONET(src_ip)) {
+ src_in->sin_family = dst_in->sin_family;
+ src_in->sin_addr.s_addr = dst_ip;
+ ret = copy_addr(addr, dev, dev->dev_addr);
+ } else if (LOOPBACK(src_ip)) {
+ ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
+ if (!ret)
+ memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+ } else {
+ ret = rdma_translate_ip((struct sockaddr *)src_in, addr);
+ if (!ret)
+ memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+ }
+
+ dev_put(dev);
+ return ret;
+}
+
+int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
+ struct rdma_dev_addr *addr, int timeout_ms,
+ void (*callback)(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context),
+ void *context)
+{
+ struct sockaddr_in *src_in, *dst_in;
+ struct addr_req *req;
+ int ret = 0;
+
+ req = kmalloc(sizeof *req, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ memset(req, 0, sizeof *req);
+
+ if (src_addr)
+ memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
+ memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr));
+ req->addr = addr;
+ req->callback = callback;
+ req->context = context;
+
+ src_in = (struct sockaddr_in *) &req->src_addr;
+ dst_in = (struct sockaddr_in *) &req->dst_addr;
+
+ req->status = addr_resolve_local(src_in, dst_in, addr);
+ if (req->status == -EADDRNOTAVAIL)
+ req->status = addr_resolve_remote(src_in, dst_in, addr);
+
+ switch (req->status) {
+ case 0:
+ req->timeout = jiffies;
+ queue_req(req);
+ break;
+ case -ENODATA:
+ req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
+ queue_req(req);
+ addr_send_arp(dst_in);
+ break;
+ default:
+ ret = req->status;
+ kfree(req);
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(rdma_resolve_ip);
+
+void rdma_addr_cancel(struct rdma_dev_addr *addr)
+{
+ struct addr_req *req, *temp_req;
+
+ mutex_lock(&lock);
+ list_for_each_entry_safe(req, temp_req, &req_list, list) {
+ if (req->addr == addr) {
+ req->status = -ECANCELED;
+ req->timeout = jiffies;
+ list_del(&req->list);
+ list_add(&req->list, &req_list);
+ set_timeout(req->timeout);
+ break;
+ }
+ }
+ mutex_unlock(&lock);
+}
+EXPORT_SYMBOL(rdma_addr_cancel);
+
+static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pkt, struct net_device *orig_dev)
+{
+ struct arphdr *arp_hdr;
+
+ arp_hdr = (struct arphdr *) skb->nh.raw;
+
+ if (arp_hdr->ar_op == htons(ARPOP_REQUEST) ||
+ arp_hdr->ar_op == htons(ARPOP_REPLY))
+ set_timeout(jiffies);
+
+ kfree_skb(skb);
+ return 0;
+}
+
+static struct packet_type addr_arp = {
+ .type = __constant_htons(ETH_P_ARP),
+ .func = addr_arp_recv,
+ .af_packet_priv = (void*) 1,
+};
+
+static int addr_init(void)
+{
+ addr_wq = create_singlethread_workqueue("ib_addr_wq");
+ if (!addr_wq)
+ return -ENOMEM;
+
+ dev_add_pack(&addr_arp);
+ return 0;
+}
+
+static void addr_cleanup(void)
+{
+ dev_remove_pack(&addr_arp);
+ destroy_workqueue(addr_wq);
+}
+
+module_init(addr_init);
+module_exit(addr_cleanup);
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 50364c0b090c..e05ca2cdc73f 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -191,6 +191,24 @@ int ib_find_cached_pkey(struct ib_device *device,
}
EXPORT_SYMBOL(ib_find_cached_pkey);
+int ib_get_cached_lmc(struct ib_device *device,
+ u8 port_num,
+ u8 *lmc)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (port_num < start_port(device) || port_num > end_port(device))
+ return -EINVAL;
+
+ read_lock_irqsave(&device->cache.lock, flags);
+ *lmc = device->cache.lmc_cache[port_num - start_port(device)];
+ read_unlock_irqrestore(&device->cache.lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(ib_get_cached_lmc);
+
static void ib_cache_update(struct ib_device *device,
u8 port)
{
@@ -251,6 +269,8 @@ static void ib_cache_update(struct ib_device *device,
device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
device->cache.gid_cache [port - start_port(device)] = gid_cache;
+ device->cache.lmc_cache[port - start_port(device)] = tprops->lmc;
+
write_unlock_irq(&device->cache.lock);
kfree(old_pkey_cache);
@@ -305,7 +325,13 @@ static void ib_cache_setup_one(struct ib_device *device)
kmalloc(sizeof *device->cache.gid_cache *
(end_port(device) - start_port(device) + 1), GFP_KERNEL);
- if (!device->cache.pkey_cache || !device->cache.gid_cache) {
+ device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache *
+ (end_port(device) -
+ start_port(device) + 1),
+ GFP_KERNEL);
+
+ if (!device->cache.pkey_cache || !device->cache.gid_cache ||
+ !device->cache.lmc_cache) {
printk(KERN_WARNING "Couldn't allocate cache "
"for %s\n", device->name);
goto err;
@@ -333,6 +359,7 @@ err_cache:
err:
kfree(device->cache.pkey_cache);
kfree(device->cache.gid_cache);
+ kfree(device->cache.lmc_cache);
}
static void ib_cache_cleanup_one(struct ib_device *device)
@@ -349,6 +376,7 @@ static void ib_cache_cleanup_one(struct ib_device *device)
kfree(device->cache.pkey_cache);
kfree(device->cache.gid_cache);
+ kfree(device->cache.lmc_cache);
}
static struct ib_client cache_client = {
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 7cfedb8d9bcd..450adfe0a4f1 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -32,8 +32,10 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $
+ * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
*/
+
+#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/idr.h>
@@ -122,7 +124,7 @@ struct cm_id_private {
struct rb_node service_node;
struct rb_node sidr_id_node;
spinlock_t lock; /* Do not acquire inside cm.lock */
- wait_queue_head_t wait;
+ struct completion comp;
atomic_t refcount;
struct ib_mad_send_buf *msg;
@@ -130,6 +132,7 @@ struct cm_id_private {
/* todo: use alternate port on send failure */
struct cm_av av;
struct cm_av alt_av;
+ struct ib_cm_compare_data *compare_data;
void *private_data;
__be64 tid;
@@ -159,7 +162,7 @@ static void cm_work_handler(void *data);
static inline void cm_deref_id(struct cm_id_private *cm_id_priv)
{
if (atomic_dec_and_test(&cm_id_priv->refcount))
- wake_up(&cm_id_priv->wait);
+ complete(&cm_id_priv->comp);
}
static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
@@ -251,23 +254,13 @@ static void cm_set_private_data(struct cm_id_private *cm_id_priv,
cm_id_priv->private_data_len = private_data_len;
}
-static void cm_set_ah_attr(struct ib_ah_attr *ah_attr, u8 port_num,
- u16 dlid, u8 sl, u16 src_path_bits)
-{
- memset(ah_attr, 0, sizeof ah_attr);
- ah_attr->dlid = dlid;
- ah_attr->sl = sl;
- ah_attr->src_path_bits = src_path_bits;
- ah_attr->port_num = port_num;
-}
-
-static void cm_init_av_for_response(struct cm_port *port,
- struct ib_wc *wc, struct cm_av *av)
+static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
+ struct ib_grh *grh, struct cm_av *av)
{
av->port = port;
av->pkey_index = wc->pkey_index;
- cm_set_ah_attr(&av->ah_attr, port->port_num, wc->slid,
- wc->sl, wc->dlid_path_bits);
+ ib_init_ah_from_wc(port->cm_dev->device, port->port_num, wc,
+ grh, &av->ah_attr);
}
static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
@@ -297,9 +290,8 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
return ret;
av->port = port;
- cm_set_ah_attr(&av->ah_attr, av->port->port_num,
- be16_to_cpu(path->dlid), path->sl,
- be16_to_cpu(path->slid) & 0x7F);
+ ib_init_ah_from_path(cm_dev->device, port->port_num, path,
+ &av->ah_attr);
av->packet_life_time = path->packet_life_time;
return 0;
}
@@ -355,6 +347,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
return cm_id_priv;
}
+static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
+{
+ int i;
+
+ for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
+ ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
+ ((unsigned long *) mask)[i];
+}
+
+static int cm_compare_data(struct ib_cm_compare_data *src_data,
+ struct ib_cm_compare_data *dst_data)
+{
+ u8 src[IB_CM_COMPARE_SIZE];
+ u8 dst[IB_CM_COMPARE_SIZE];
+
+ if (!src_data || !dst_data)
+ return 0;
+
+ cm_mask_copy(src, src_data->data, dst_data->mask);
+ cm_mask_copy(dst, dst_data->data, src_data->mask);
+ return memcmp(src, dst, IB_CM_COMPARE_SIZE);
+}
+
+static int cm_compare_private_data(u8 *private_data,
+ struct ib_cm_compare_data *dst_data)
+{
+ u8 src[IB_CM_COMPARE_SIZE];
+
+ if (!dst_data)
+ return 0;
+
+ cm_mask_copy(src, private_data, dst_data->mask);
+ return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
+}
+
static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
{
struct rb_node **link = &cm.listen_service_table.rb_node;
@@ -362,14 +389,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
struct cm_id_private *cur_cm_id_priv;
__be64 service_id = cm_id_priv->id.service_id;
__be64 service_mask = cm_id_priv->id.service_mask;
+ int data_cmp;
while (*link) {
parent = *link;
cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
service_node);
+ data_cmp = cm_compare_data(cm_id_priv->compare_data,
+ cur_cm_id_priv->compare_data);
if ((cur_cm_id_priv->id.service_mask & service_id) ==
(service_mask & cur_cm_id_priv->id.service_id) &&
- (cm_id_priv->id.device == cur_cm_id_priv->id.device))
+ (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
+ !data_cmp)
return cur_cm_id_priv;
if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
@@ -378,6 +409,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
link = &(*link)->rb_right;
else if (service_id < cur_cm_id_priv->id.service_id)
link = &(*link)->rb_left;
+ else if (service_id > cur_cm_id_priv->id.service_id)
+ link = &(*link)->rb_right;
+ else if (data_cmp < 0)
+ link = &(*link)->rb_left;
else
link = &(*link)->rb_right;
}
@@ -387,16 +422,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
}
static struct cm_id_private * cm_find_listen(struct ib_device *device,
- __be64 service_id)
+ __be64 service_id,
+ u8 *private_data)
{
struct rb_node *node = cm.listen_service_table.rb_node;
struct cm_id_private *cm_id_priv;
+ int data_cmp;
while (node) {
cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
+ data_cmp = cm_compare_private_data(private_data,
+ cm_id_priv->compare_data);
if ((cm_id_priv->id.service_mask & service_id) ==
cm_id_priv->id.service_id &&
- (cm_id_priv->id.device == device))
+ (cm_id_priv->id.device == device) && !data_cmp)
return cm_id_priv;
if (device < cm_id_priv->id.device)
@@ -405,6 +444,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
node = node->rb_right;
else if (service_id < cm_id_priv->id.service_id)
node = node->rb_left;
+ else if (service_id > cm_id_priv->id.service_id)
+ node = node->rb_right;
+ else if (data_cmp < 0)
+ node = node->rb_left;
else
node = node->rb_right;
}
@@ -559,7 +602,7 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
goto error;
spin_lock_init(&cm_id_priv->lock);
- init_waitqueue_head(&cm_id_priv->wait);
+ init_completion(&cm_id_priv->comp);
INIT_LIST_HEAD(&cm_id_priv->work_list);
atomic_set(&cm_id_priv->work_count, -1);
atomic_set(&cm_id_priv->refcount, 1);
@@ -724,19 +767,18 @@ retest:
}
cm_free_id(cm_id->local_id);
- atomic_dec(&cm_id_priv->refcount);
- wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount));
+ cm_deref_id(cm_id_priv);
+ wait_for_completion(&cm_id_priv->comp);
while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
cm_free_work(work);
- if (cm_id_priv->private_data && cm_id_priv->private_data_len)
- kfree(cm_id_priv->private_data);
+ kfree(cm_id_priv->compare_data);
+ kfree(cm_id_priv->private_data);
kfree(cm_id_priv);
}
EXPORT_SYMBOL(ib_destroy_cm_id);
-int ib_cm_listen(struct ib_cm_id *cm_id,
- __be64 service_id,
- __be64 service_mask)
+int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
+ struct ib_cm_compare_data *compare_data)
{
struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
unsigned long flags;
@@ -750,7 +792,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
return -EINVAL;
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
- BUG_ON(cm_id->state != IB_CM_IDLE);
+ if (cm_id->state != IB_CM_IDLE)
+ return -EINVAL;
+
+ if (compare_data) {
+ cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
+ GFP_KERNEL);
+ if (!cm_id_priv->compare_data)
+ return -ENOMEM;
+ cm_mask_copy(cm_id_priv->compare_data->data,
+ compare_data->data, compare_data->mask);
+ memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
+ IB_CM_COMPARE_SIZE);
+ }
cm_id->state = IB_CM_LISTEN;
@@ -767,6 +821,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
if (cur_cm_id_priv) {
cm_id->state = IB_CM_IDLE;
+ kfree(cm_id_priv->compare_data);
+ cm_id_priv->compare_data = NULL;
ret = -EBUSY;
}
return ret;
@@ -1239,7 +1295,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
/* Find matching listen request. */
listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
- req_msg->service_id);
+ req_msg->service_id,
+ req_msg->private_data);
if (!listen_cm_id_priv) {
spin_unlock_irqrestore(&cm.lock, flags);
cm_issue_rej(work->port, work->mad_recv_wc,
@@ -1274,6 +1331,7 @@ static int cm_req_handler(struct cm_work *work)
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
cm_id_priv->id.remote_id = req_msg->local_comm_id;
cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
+ work->mad_recv_wc->recv_buf.grh,
&cm_id_priv->av);
cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
id.local_id);
@@ -2547,7 +2605,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg,
cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID,
cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR));
sidr_req_msg->request_id = cm_id_priv->id.local_id;
- sidr_req_msg->pkey = cpu_to_be16(param->pkey);
+ sidr_req_msg->pkey = cpu_to_be16(param->path->pkey);
sidr_req_msg->service_id = param->service_id;
if (param->private_data && param->private_data_len)
@@ -2639,6 +2697,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid);
cm_id_priv->av.dgid.global.interface_id = 0;
cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
+ work->mad_recv_wc->recv_buf.grh,
&cm_id_priv->av);
cm_id_priv->id.remote_id = sidr_req_msg->request_id;
cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
@@ -2652,7 +2711,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
goto out; /* Duplicate message. */
}
cur_cm_id_priv = cm_find_listen(cm_id->device,
- sidr_req_msg->service_id);
+ sidr_req_msg->service_id,
+ sidr_req_msg->private_data);
if (!cur_cm_id_priv) {
rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
spin_unlock_irqrestore(&cm.lock, flags);
@@ -3289,7 +3349,6 @@ error:
static void __exit ib_cm_cleanup(void)
{
- flush_workqueue(cm.wq);
destroy_workqueue(cm.wq);
ib_unregister_client(&cm_client);
idr_destroy(&cm.local_id_table);
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
new file mode 100644
index 000000000000..a76834edf608
--- /dev/null
+++ b/drivers/infiniband/core/cma.c
@@ -0,0 +1,1927 @@
+/*
+ * Copyright (c) 2005 Voltaire Inc. All rights reserved.
+ * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved.
+ * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved.
+ * Copyright (c) 2005-2006 Intel Corporation. All rights reserved.
+ *
+ * This Software is licensed under one of the following licenses:
+ *
+ * 1) under the terms of the "Common Public License 1.0" a copy of which is
+ * available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/cpl.php.
+ *
+ * 2) under the terms of the "The BSD License" a copy of which is
+ * available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/bsd-license.php.
+ *
+ * 3) under the terms of the "GNU General Public License (GPL) Version 2" a
+ * copy of which is available from the Open Source Initiative, see
+ * http://www.opensource.org/licenses/gpl-license.php.
+ *
+ * Licensee has the right to choose one of the above licenses.
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice and one of the license notices.
+ *
+ * Redistributions in binary form must reproduce both the above copyright
+ * notice, one of the license notices in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/mutex.h>
+#include <linux/random.h>
+#include <linux/idr.h>
+
+#include <net/tcp.h>
+
+#include <rdma/rdma_cm.h>
+#include <rdma/rdma_cm_ib.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_cm.h>
+#include <rdma/ib_sa.h>
+
+MODULE_AUTHOR("Sean Hefty");
+MODULE_DESCRIPTION("Generic RDMA CM Agent");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define CMA_CM_RESPONSE_TIMEOUT 20
+#define CMA_MAX_CM_RETRIES 3
+
+static void cma_add_one(struct ib_device *device);
+static void cma_remove_one(struct ib_device *device);
+
+static struct ib_client cma_client = {
+ .name = "cma",
+ .add = cma_add_one,
+ .remove = cma_remove_one
+};
+
+static LIST_HEAD(dev_list);
+static LIST_HEAD(listen_any_list);
+static DEFINE_MUTEX(lock);
+static struct workqueue_struct *cma_wq;
+static DEFINE_IDR(sdp_ps);
+static DEFINE_IDR(tcp_ps);
+
+struct cma_device {
+ struct list_head list;
+ struct ib_device *device;
+ __be64 node_guid;
+ struct completion comp;
+ atomic_t refcount;
+ struct list_head id_list;
+};
+
+enum cma_state {
+ CMA_IDLE,
+ CMA_ADDR_QUERY,
+ CMA_ADDR_RESOLVED,
+ CMA_ROUTE_QUERY,
+ CMA_ROUTE_RESOLVED,
+ CMA_CONNECT,
+ CMA_DISCONNECT,
+ CMA_ADDR_BOUND,
+ CMA_LISTEN,
+ CMA_DEVICE_REMOVAL,
+ CMA_DESTROYING
+};
+
+struct rdma_bind_list {
+ struct idr *ps;
+ struct hlist_head owners;
+ unsigned short port;
+};
+
+/*
+ * Device removal can occur at anytime, so we need extra handling to
+ * serialize notifying the user of device removal with other callbacks.
+ * We do this by disabling removal notification while a callback is in process,
+ * and reporting it after the callback completes.
+ */
+struct rdma_id_private {
+ struct rdma_cm_id id;
+
+ struct rdma_bind_list *bind_list;
+ struct hlist_node node;
+ struct list_head list;
+ struct list_head listen_list;
+ struct cma_device *cma_dev;
+
+ enum cma_state state;
+ spinlock_t lock;
+ struct completion comp;
+ atomic_t refcount;
+ wait_queue_head_t wait_remove;
+ atomic_t dev_remove;
+
+ int backlog;
+ int timeout_ms;
+ struct ib_sa_query *query;
+ int query_id;
+ union {
+ struct ib_cm_id *ib;
+ } cm_id;
+
+ u32 seq_num;
+ u32 qp_num;
+ enum ib_qp_type qp_type;
+ u8 srq;
+};
+
+struct cma_work {
+ struct work_struct work;
+ struct rdma_id_private *id;
+ enum cma_state old_state;
+ enum cma_state new_state;
+ struct rdma_cm_event event;
+};
+
+union cma_ip_addr {
+ struct in6_addr ip6;
+ struct {
+ __u32 pad[3];
+ __u32 addr;
+ } ip4;
+};
+
+struct cma_hdr {
+ u8 cma_version;
+ u8 ip_version; /* IP version: 7:4 */
+ __u16 port;
+ union cma_ip_addr src_addr;
+ union cma_ip_addr dst_addr;
+};
+
+struct sdp_hh {
+ u8 bsdh[16];
+ u8 sdp_version; /* Major version: 7:4 */
+ u8 ip_version; /* IP version: 7:4 */
+ u8 sdp_specific1[10];
+ __u16 port;
+ __u16 sdp_specific2;
+ union cma_ip_addr src_addr;
+ union cma_ip_addr dst_addr;
+};
+
+struct sdp_hah {
+ u8 bsdh[16];
+ u8 sdp_version;
+};
+
+#define CMA_VERSION 0x00
+#define SDP_MAJ_VERSION 0x2
+
+static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&id_priv->lock, flags);
+ ret = (id_priv->state == comp);
+ spin_unlock_irqrestore(&id_priv->lock, flags);
+ return ret;
+}
+
+static int cma_comp_exch(struct rdma_id_private *id_priv,
+ enum cma_state comp, enum cma_state exch)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&id_priv->lock, flags);
+ if ((ret = (id_priv->state == comp)))
+ id_priv->state = exch;
+ spin_unlock_irqrestore(&id_priv->lock, flags);
+ return ret;
+}
+
+static enum cma_state cma_exch(struct rdma_id_private *id_priv,
+ enum cma_state exch)
+{
+ unsigned long flags;
+ enum cma_state old;
+
+ spin_lock_irqsave(&id_priv->lock, flags);
+ old = id_priv->state;
+ id_priv->state = exch;
+ spin_unlock_irqrestore(&id_priv->lock, flags);
+ return old;
+}
+
+static inline u8 cma_get_ip_ver(struct cma_hdr *hdr)
+{
+ return hdr->ip_version >> 4;
+}
+
+static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
+{
+ hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
+}
+
+static inline u8 sdp_get_majv(u8 sdp_version)
+{
+ return sdp_version >> 4;
+}
+
+static inline u8 sdp_get_ip_ver(struct sdp_hh *hh)
+{
+ return hh->ip_version >> 4;
+}
+
+static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
+{
+ hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
+}
+
+static void cma_attach_to_dev(struct rdma_id_private *id_priv,
+ struct cma_device *cma_dev)
+{
+ atomic_inc(&cma_dev->refcount);
+ id_priv->cma_dev = cma_dev;
+ id_priv->id.device = cma_dev->device;
+ list_add_tail(&id_priv->list, &cma_dev->id_list);
+}
+
+static inline void cma_deref_dev(struct cma_device *cma_dev)
+{
+ if (atomic_dec_and_test(&cma_dev->refcount))
+ complete(&cma_dev->comp);
+}
+
+static void cma_detach_from_dev(struct rdma_id_private *id_priv)
+{
+ list_del(&id_priv->list);
+ cma_deref_dev(id_priv->cma_dev);
+ id_priv->cma_dev = NULL;
+}
+
+static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
+{
+ struct cma_device *cma_dev;
+ union ib_gid *gid;
+ int ret = -ENODEV;
+
+ gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
+
+ mutex_lock(&lock);
+ list_for_each_entry(cma_dev, &dev_list, list) {
+ ret = ib_find_cached_gid(cma_dev->device, gid,
+ &id_priv->id.port_num, NULL);
+ if (!ret) {
+ cma_attach_to_dev(id_priv, cma_dev);
+ break;
+ }
+ }
+ mutex_unlock(&lock);
+ return ret;
+}
+
+static int cma_acquire_dev(struct rdma_id_private *id_priv)
+{
+ switch (id_priv->id.route.addr.dev_addr.dev_type) {
+ case IB_NODE_CA:
+ return cma_acquire_ib_dev(id_priv);
+ default:
+ return -ENODEV;
+ }
+}
+
+static void cma_deref_id(struct rdma_id_private *id_priv)
+{
+ if (atomic_dec_and_test(&id_priv->refcount))
+ complete(&id_priv->comp);
+}
+
+static void cma_release_remove(struct rdma_id_private *id_priv)
+{
+ if (atomic_dec_and_test(&id_priv->dev_remove))
+ wake_up(&id_priv->wait_remove);
+}
+
+struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+ void *context, enum rdma_port_space ps)
+{
+ struct rdma_id_private *id_priv;
+
+ id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL);
+ if (!id_priv)
+ return ERR_PTR(-ENOMEM);
+
+ id_priv->state = CMA_IDLE;
+ id_priv->id.context = context;
+ id_priv->id.event_handler = event_handler;
+ id_priv->id.ps = ps;
+ spin_lock_init(&id_priv->lock);
+ init_completion(&id_priv->comp);
+ atomic_set(&id_priv->refcount, 1);
+ init_waitqueue_head(&id_priv->wait_remove);
+ atomic_set(&id_priv->dev_remove, 0);
+ INIT_LIST_HEAD(&id_priv->listen_list);
+ get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
+
+ return &id_priv->id;
+}
+EXPORT_SYMBOL(rdma_create_id);
+
+static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
+{
+ struct ib_qp_attr qp_attr;
+ struct rdma_dev_addr *dev_addr;
+ int ret;
+
+ dev_addr = &id_priv->id.route.addr.dev_addr;
+ ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
+ ib_addr_get_pkey(dev_addr),
+ &qp_attr.pkey_index);
+ if (ret)
+ return ret;
+
+ qp_attr.qp_state = IB_QPS_INIT;
+ qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ qp_attr.port_num = id_priv->id.port_num;
+ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX | IB_QP_PORT);
+}
+
+int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ struct rdma_id_private *id_priv;
+ struct ib_qp *qp;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (id->device != pd->device)
+ return -EINVAL;
+
+ qp = ib_create_qp(pd, qp_init_attr);
+ if (IS_ERR(qp))
+ return PTR_ERR(qp);
+
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ ret = cma_init_ib_qp(id_priv, qp);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ if (ret)
+ goto err;
+
+ id->qp = qp;
+ id_priv->qp_num = qp->qp_num;
+ id_priv->qp_type = qp->qp_type;
+ id_priv->srq = (qp->srq != NULL);
+ return 0;
+err:
+ ib_destroy_qp(qp);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_create_qp);
+
+void rdma_destroy_qp(struct rdma_cm_id *id)
+{
+ ib_destroy_qp(id->qp);
+}
+EXPORT_SYMBOL(rdma_destroy_qp);
+
+static int cma_modify_qp_rtr(struct rdma_cm_id *id)
+{
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+
+ if (!id->qp)
+ return 0;
+
+ /* Need to update QP attributes from default values. */
+ qp_attr.qp_state = IB_QPS_INIT;
+ ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ if (ret)
+ return ret;
+
+ ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+ if (ret)
+ return ret;
+
+ qp_attr.qp_state = IB_QPS_RTR;
+ ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ if (ret)
+ return ret;
+
+ return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+}
+
+static int cma_modify_qp_rts(struct rdma_cm_id *id)
+{
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+
+ if (!id->qp)
+ return 0;
+
+ qp_attr.qp_state = IB_QPS_RTS;
+ ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ if (ret)
+ return ret;
+
+ return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+}
+
+static int cma_modify_qp_err(struct rdma_cm_id *id)
+{
+ struct ib_qp_attr qp_attr;
+
+ if (!id->qp)
+ return 0;
+
+ qp_attr.qp_state = IB_QPS_ERR;
+ return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE);
+}
+
+int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
+ int *qp_attr_mask)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ switch (id_priv->id.device->node_type) {
+ case IB_NODE_CA:
+ ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
+ qp_attr_mask);
+ if (qp_attr->qp_state == IB_QPS_RTR)
+ qp_attr->rq_psn = id_priv->seq_num;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rdma_init_qp_attr);
+
+static inline int cma_zero_addr(struct sockaddr *addr)
+{
+ struct in6_addr *ip6;
+
+ if (addr->sa_family == AF_INET)
+ return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+ else {
+ ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
+ return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
+ ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0;
+ }
+}
+
+static inline int cma_loopback_addr(struct sockaddr *addr)
+{
+ return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+}
+
+static inline int cma_any_addr(struct sockaddr *addr)
+{
+ return cma_zero_addr(addr) || cma_loopback_addr(addr);
+}
+
+static inline int cma_any_port(struct sockaddr *addr)
+{
+ return !((struct sockaddr_in *) addr)->sin_port;
+}
+
+static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
+ u8 *ip_ver, __u16 *port,
+ union cma_ip_addr **src, union cma_ip_addr **dst)
+{
+ switch (ps) {
+ case RDMA_PS_SDP:
+ if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) !=
+ SDP_MAJ_VERSION)
+ return -EINVAL;
+
+ *ip_ver = sdp_get_ip_ver(hdr);
+ *port = ((struct sdp_hh *) hdr)->port;
+ *src = &((struct sdp_hh *) hdr)->src_addr;
+ *dst = &((struct sdp_hh *) hdr)->dst_addr;
+ break;
+ default:
+ if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION)
+ return -EINVAL;
+
+ *ip_ver = cma_get_ip_ver(hdr);
+ *port = ((struct cma_hdr *) hdr)->port;
+ *src = &((struct cma_hdr *) hdr)->src_addr;
+ *dst = &((struct cma_hdr *) hdr)->dst_addr;
+ break;
+ }
+
+ if (*ip_ver != 4 && *ip_ver != 6)
+ return -EINVAL;
+ return 0;
+}
+
+static void cma_save_net_info(struct rdma_addr *addr,
+ struct rdma_addr *listen_addr,
+ u8 ip_ver, __u16 port,
+ union cma_ip_addr *src, union cma_ip_addr *dst)
+{
+ struct sockaddr_in *listen4, *ip4;
+ struct sockaddr_in6 *listen6, *ip6;
+
+ switch (ip_ver) {
+ case 4:
+ listen4 = (struct sockaddr_in *) &listen_addr->src_addr;
+ ip4 = (struct sockaddr_in *) &addr->src_addr;
+ ip4->sin_family = listen4->sin_family;
+ ip4->sin_addr.s_addr = dst->ip4.addr;
+ ip4->sin_port = listen4->sin_port;
+
+ ip4 = (struct sockaddr_in *) &addr->dst_addr;
+ ip4->sin_family = listen4->sin_family;
+ ip4->sin_addr.s_addr = src->ip4.addr;
+ ip4->sin_port = port;
+ break;
+ case 6:
+ listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr;
+ ip6 = (struct sockaddr_in6 *) &addr->src_addr;
+ ip6->sin6_family = listen6->sin6_family;
+ ip6->sin6_addr = dst->ip6;
+ ip6->sin6_port = listen6->sin6_port;
+
+ ip6 = (struct sockaddr_in6 *) &addr->dst_addr;
+ ip6->sin6_family = listen6->sin6_family;
+ ip6->sin6_addr = src->ip6;
+ ip6->sin6_port = port;
+ break;
+ default:
+ break;
+ }
+}
+
+static inline int cma_user_data_offset(enum rdma_port_space ps)
+{
+ switch (ps) {
+ case RDMA_PS_SDP:
+ return 0;
+ default:
+ return sizeof(struct cma_hdr);
+ }
+}
+
+static int cma_notify_user(struct rdma_id_private *id_priv,
+ enum rdma_cm_event_type type, int status,
+ void *data, u8 data_len)
+{
+ struct rdma_cm_event event;
+
+ event.event = type;
+ event.status = status;
+ event.private_data = data;
+ event.private_data_len = data_len;
+
+ return id_priv->id.event_handler(&id_priv->id, &event);
+}
+
+static void cma_cancel_route(struct rdma_id_private *id_priv)
+{
+ switch (id_priv->id.device->node_type) {
+ case IB_NODE_CA:
+ if (id_priv->query)
+ ib_sa_cancel_query(id_priv->query_id, id_priv->query);
+ break;
+ default:
+ break;
+ }
+}
+
+static inline int cma_internal_listen(struct rdma_id_private *id_priv)
+{
+ return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev &&
+ cma_any_addr(&id_priv->id.route.addr.src_addr);
+}
+
+static void cma_destroy_listen(struct rdma_id_private *id_priv)
+{
+ cma_exch(id_priv, CMA_DESTROYING);
+
+ if (id_priv->cma_dev) {
+ switch (id_priv->id.device->node_type) {
+ case IB_NODE_CA:
+ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ break;
+ default:
+ break;
+ }
+ cma_detach_from_dev(id_priv);
+ }
+ list_del(&id_priv->listen_list);
+
+ cma_deref_id(id_priv);
+ wait_for_completion(&id_priv->comp);
+
+ kfree(id_priv);
+}
+
+static void cma_cancel_listens(struct rdma_id_private *id_priv)
+{
+ struct rdma_id_private *dev_id_priv;
+
+ mutex_lock(&lock);
+ list_del(&id_priv->list);
+
+ while (!list_empty(&id_priv->listen_list)) {
+ dev_id_priv = list_entry(id_priv->listen_list.next,
+ struct rdma_id_private, listen_list);
+ cma_destroy_listen(dev_id_priv);
+ }
+ mutex_unlock(&lock);
+}
+
+static void cma_cancel_operation(struct rdma_id_private *id_priv,
+ enum cma_state state)
+{
+ switch (state) {
+ case CMA_ADDR_QUERY:
+ rdma_addr_cancel(&id_priv->id.route.addr.dev_addr);
+ break;
+ case CMA_ROUTE_QUERY:
+ cma_cancel_route(id_priv);
+ break;
+ case CMA_LISTEN:
+ if (cma_any_addr(&id_priv->id.route.addr.src_addr) &&
+ !id_priv->cma_dev)
+ cma_cancel_listens(id_priv);
+ break;
+ default:
+ break;
+ }
+}
+
+static void cma_release_port(struct rdma_id_private *id_priv)
+{
+ struct rdma_bind_list *bind_list = id_priv->bind_list;
+
+ if (!bind_list)
+ return;
+
+ mutex_lock(&lock);
+ hlist_del(&id_priv->node);
+ if (hlist_empty(&bind_list->owners)) {
+ idr_remove(bind_list->ps, bind_list->port);
+ kfree(bind_list);
+ }
+ mutex_unlock(&lock);
+}
+
+void rdma_destroy_id(struct rdma_cm_id *id)
+{
+ struct rdma_id_private *id_priv;
+ enum cma_state state;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ state = cma_exch(id_priv, CMA_DESTROYING);
+ cma_cancel_operation(id_priv, state);
+
+ if (id_priv->cma_dev) {
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ break;
+ default:
+ break;
+ }
+ mutex_lock(&lock);
+ cma_detach_from_dev(id_priv);
+ mutex_unlock(&lock);
+ }
+
+ cma_release_port(id_priv);
+ cma_deref_id(id_priv);
+ wait_for_completion(&id_priv->comp);
+
+ kfree(id_priv->id.route.path_rec);
+ kfree(id_priv);
+}
+EXPORT_SYMBOL(rdma_destroy_id);
+
+static int cma_rep_recv(struct rdma_id_private *id_priv)
+{
+ int ret;
+
+ ret = cma_modify_qp_rtr(&id_priv->id);
+ if (ret)
+ goto reject;
+
+ ret = cma_modify_qp_rts(&id_priv->id);
+ if (ret)
+ goto reject;
+
+ ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0);
+ if (ret)
+ goto reject;
+
+ return 0;
+reject:
+ cma_modify_qp_err(&id_priv->id);
+ ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ return ret;
+}
+
+static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
+{
+ if (id_priv->id.ps == RDMA_PS_SDP &&
+ sdp_get_majv(((struct sdp_hah *) data)->sdp_version) !=
+ SDP_MAJ_VERSION)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int cma_rtu_recv(struct rdma_id_private *id_priv)
+{
+ int ret;
+
+ ret = cma_modify_qp_rts(&id_priv->id);
+ if (ret)
+ goto reject;
+
+ return 0;
+reject:
+ cma_modify_qp_err(&id_priv->id);
+ ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ return ret;
+}
+
+static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
+{
+ struct rdma_id_private *id_priv = cm_id->context;
+ enum rdma_cm_event_type event;
+ u8 private_data_len = 0;
+ int ret = 0, status = 0;
+
+ atomic_inc(&id_priv->dev_remove);
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ goto out;
+
+ switch (ib_event->event) {
+ case IB_CM_REQ_ERROR:
+ case IB_CM_REP_ERROR:
+ event = RDMA_CM_EVENT_UNREACHABLE;
+ status = -ETIMEDOUT;
+ break;
+ case IB_CM_REP_RECEIVED:
+ status = cma_verify_rep(id_priv, ib_event->private_data);
+ if (status)
+ event = RDMA_CM_EVENT_CONNECT_ERROR;
+ else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
+ status = cma_rep_recv(id_priv);
+ event = status ? RDMA_CM_EVENT_CONNECT_ERROR :
+ RDMA_CM_EVENT_ESTABLISHED;
+ } else
+ event = RDMA_CM_EVENT_CONNECT_RESPONSE;
+ private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
+ break;
+ case IB_CM_RTU_RECEIVED:
+ status = cma_rtu_recv(id_priv);
+ event = status ? RDMA_CM_EVENT_CONNECT_ERROR :
+ RDMA_CM_EVENT_ESTABLISHED;
+ break;
+ case IB_CM_DREQ_ERROR:
+ status = -ETIMEDOUT; /* fall through */
+ case IB_CM_DREQ_RECEIVED:
+ case IB_CM_DREP_RECEIVED:
+ if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT))
+ goto out;
+ event = RDMA_CM_EVENT_DISCONNECTED;
+ break;
+ case IB_CM_TIMEWAIT_EXIT:
+ case IB_CM_MRA_RECEIVED:
+ /* ignore event */
+ goto out;
+ case IB_CM_REJ_RECEIVED:
+ cma_modify_qp_err(&id_priv->id);
+ status = ib_event->param.rej_rcvd.reason;
+ event = RDMA_CM_EVENT_REJECTED;
+ break;
+ default:
+ printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
+ ib_event->event);
+ goto out;
+ }
+
+ ret = cma_notify_user(id_priv, event, status, ib_event->private_data,
+ private_data_len);
+ if (ret) {
+ /* Destroy the CM ID by returning a non-zero value. */
+ id_priv->cm_id.ib = NULL;
+ cma_exch(id_priv, CMA_DESTROYING);
+ cma_release_remove(id_priv);
+ rdma_destroy_id(&id_priv->id);
+ return ret;
+ }
+out:
+ cma_release_remove(id_priv);
+ return ret;
+}
+
+static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
+ struct ib_cm_event *ib_event)
+{
+ struct rdma_id_private *id_priv;
+ struct rdma_cm_id *id;
+ struct rdma_route *rt;
+ union cma_ip_addr *src, *dst;
+ __u16 port;
+ u8 ip_ver;
+
+ id = rdma_create_id(listen_id->event_handler, listen_id->context,
+ listen_id->ps);
+ if (IS_ERR(id))
+ return NULL;
+
+ rt = &id->route;
+ rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
+ rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL);
+ if (!rt->path_rec)
+ goto err;
+
+ if (cma_get_net_info(ib_event->private_data, listen_id->ps,
+ &ip_ver, &port, &src, &dst))
+ goto err;
+
+ cma_save_net_info(&id->route.addr, &listen_id->route.addr,
+ ip_ver, port, src, dst);
+ rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path;
+ if (rt->num_paths == 2)
+ rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
+
+ ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
+ ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
+ ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
+ rt->addr.dev_addr.dev_type = IB_NODE_CA;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ id_priv->state = CMA_CONNECT;
+ return id_priv;
+err:
+ rdma_destroy_id(id);
+ return NULL;
+}
+
+static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
+{
+ struct rdma_id_private *listen_id, *conn_id;
+ int offset, ret;
+
+ listen_id = cm_id->context;
+ atomic_inc(&listen_id->dev_remove);
+ if (!cma_comp(listen_id, CMA_LISTEN)) {
+ ret = -ECONNABORTED;
+ goto out;
+ }
+
+ conn_id = cma_new_id(&listen_id->id, ib_event);
+ if (!conn_id) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ atomic_inc(&conn_id->dev_remove);
+ ret = cma_acquire_ib_dev(conn_id);
+ if (ret) {
+ ret = -ENODEV;
+ cma_release_remove(conn_id);
+ rdma_destroy_id(&conn_id->id);
+ goto out;
+ }
+
+ conn_id->cm_id.ib = cm_id;
+ cm_id->context = conn_id;
+ cm_id->cm_handler = cma_ib_handler;
+
+ offset = cma_user_data_offset(listen_id->id.ps);
+ ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
+ ib_event->private_data + offset,
+ IB_CM_REQ_PRIVATE_DATA_SIZE - offset);
+ if (ret) {
+ /* Destroy the CM ID by returning a non-zero value. */
+ conn_id->cm_id.ib = NULL;
+ cma_exch(conn_id, CMA_DESTROYING);
+ cma_release_remove(conn_id);
+ rdma_destroy_id(&conn_id->id);
+ }
+out:
+ cma_release_remove(listen_id);
+ return ret;
+}
+
+static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
+{
+ return cpu_to_be64(((u64)ps << 16) +
+ be16_to_cpu(((struct sockaddr_in *) addr)->sin_port));
+}
+
+static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
+ struct ib_cm_compare_data *compare)
+{
+ struct cma_hdr *cma_data, *cma_mask;
+ struct sdp_hh *sdp_data, *sdp_mask;
+ __u32 ip4_addr;
+ struct in6_addr ip6_addr;
+
+ memset(compare, 0, sizeof *compare);
+ cma_data = (void *) compare->data;
+ cma_mask = (void *) compare->mask;
+ sdp_data = (void *) compare->data;
+ sdp_mask = (void *) compare->mask;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ if (ps == RDMA_PS_SDP) {
+ sdp_set_ip_ver(sdp_data, 4);
+ sdp_set_ip_ver(sdp_mask, 0xF);
+ sdp_data->dst_addr.ip4.addr = ip4_addr;
+ sdp_mask->dst_addr.ip4.addr = ~0;
+ } else {
+ cma_set_ip_ver(cma_data, 4);
+ cma_set_ip_ver(cma_mask, 0xF);
+ cma_data->dst_addr.ip4.addr = ip4_addr;
+ cma_mask->dst_addr.ip4.addr = ~0;
+ }
+ break;
+ case AF_INET6:
+ ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
+ if (ps == RDMA_PS_SDP) {
+ sdp_set_ip_ver(sdp_data, 6);
+ sdp_set_ip_ver(sdp_mask, 0xF);
+ sdp_data->dst_addr.ip6 = ip6_addr;
+ memset(&sdp_mask->dst_addr.ip6, 0xFF,
+ sizeof sdp_mask->dst_addr.ip6);
+ } else {
+ cma_set_ip_ver(cma_data, 6);
+ cma_set_ip_ver(cma_mask, 0xF);
+ cma_data->dst_addr.ip6 = ip6_addr;
+ memset(&cma_mask->dst_addr.ip6, 0xFF,
+ sizeof cma_mask->dst_addr.ip6);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int cma_ib_listen(struct rdma_id_private *id_priv)
+{
+ struct ib_cm_compare_data compare_data;
+ struct sockaddr *addr;
+ __be64 svc_id;
+ int ret;
+
+ id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler,
+ id_priv);
+ if (IS_ERR(id_priv->cm_id.ib))
+ return PTR_ERR(id_priv->cm_id.ib);
+
+ addr = &id_priv->id.route.addr.src_addr;
+ svc_id = cma_get_service_id(id_priv->id.ps, addr);
+ if (cma_any_addr(addr))
+ ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL);
+ else {
+ cma_set_compare_data(id_priv->id.ps, addr, &compare_data);
+ ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data);
+ }
+
+ if (ret) {
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ id_priv->cm_id.ib = NULL;
+ }
+
+ return ret;
+}
+
+static int cma_listen_handler(struct rdma_cm_id *id,
+ struct rdma_cm_event *event)
+{
+ struct rdma_id_private *id_priv = id->context;
+
+ id->context = id_priv->id.context;
+ id->event_handler = id_priv->id.event_handler;
+ return id_priv->id.event_handler(id, event);
+}
+
+static void cma_listen_on_dev(struct rdma_id_private *id_priv,
+ struct cma_device *cma_dev)
+{
+ struct rdma_id_private *dev_id_priv;
+ struct rdma_cm_id *id;
+ int ret;
+
+ id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps);
+ if (IS_ERR(id))
+ return;
+
+ dev_id_priv = container_of(id, struct rdma_id_private, id);
+
+ dev_id_priv->state = CMA_ADDR_BOUND;
+ memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
+ ip_addr_size(&id_priv->id.route.addr.src_addr));
+
+ cma_attach_to_dev(dev_id_priv, cma_dev);
+ list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
+
+ ret = rdma_listen(id, id_priv->backlog);
+ if (ret)
+ goto err;
+
+ return;
+err:
+ cma_destroy_listen(dev_id_priv);
+}
+
+static void cma_listen_on_all(struct rdma_id_private *id_priv)
+{
+ struct cma_device *cma_dev;
+
+ mutex_lock(&lock);
+ list_add_tail(&id_priv->list, &listen_any_list);
+ list_for_each_entry(cma_dev, &dev_list, list)
+ cma_listen_on_dev(id_priv, cma_dev);
+ mutex_unlock(&lock);
+}
+
+static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af)
+{
+ struct sockaddr_in addr_in;
+
+ memset(&addr_in, 0, sizeof addr_in);
+ addr_in.sin_family = af;
+ return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
+}
+
+int rdma_listen(struct rdma_cm_id *id, int backlog)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (id_priv->state == CMA_IDLE) {
+ ret = cma_bind_any(id, AF_INET);
+ if (ret)
+ return ret;
+ }
+
+ if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN))
+ return -EINVAL;
+
+ id_priv->backlog = backlog;
+ if (id->device) {
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ ret = cma_ib_listen(id_priv);
+ if (ret)
+ goto err;
+ break;
+ default:
+ ret = -ENOSYS;
+ goto err;
+ }
+ } else
+ cma_listen_on_all(id_priv);
+
+ return 0;
+err:
+ id_priv->backlog = 0;
+ cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_listen);
+
+static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
+ void *context)
+{
+ struct cma_work *work = context;
+ struct rdma_route *route;
+
+ route = &work->id->id.route;
+
+ if (!status) {
+ route->num_paths = 1;
+ *route->path_rec = *path_rec;
+ } else {
+ work->old_state = CMA_ROUTE_QUERY;
+ work->new_state = CMA_ADDR_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
+ }
+
+ queue_work(cma_wq, &work->work);
+}
+
+static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
+ struct cma_work *work)
+{
+ struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr;
+ struct ib_sa_path_rec path_rec;
+
+ memset(&path_rec, 0, sizeof path_rec);
+ path_rec.sgid = *ib_addr_get_sgid(addr);
+ path_rec.dgid = *ib_addr_get_dgid(addr);
+ path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
+ path_rec.numb_path = 1;
+
+ id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device,
+ id_priv->id.port_num, &path_rec,
+ IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
+ IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
+ timeout_ms, GFP_KERNEL,
+ cma_query_handler, work, &id_priv->query);
+
+ return (id_priv->query_id < 0) ? id_priv->query_id : 0;
+}
+
+static void cma_work_handler(void *data)
+{
+ struct cma_work *work = data;
+ struct rdma_id_private *id_priv = work->id;
+ int destroy = 0;
+
+ atomic_inc(&id_priv->dev_remove);
+ if (!cma_comp_exch(id_priv, work->old_state, work->new_state))
+ goto out;
+
+ if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
+ cma_exch(id_priv, CMA_DESTROYING);
+ destroy = 1;
+ }
+out:
+ cma_release_remove(id_priv);
+ cma_deref_id(id_priv);
+ if (destroy)
+ rdma_destroy_id(&id_priv->id);
+ kfree(work);
+}
+
+static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
+{
+ struct rdma_route *route = &id_priv->id.route;
+ struct cma_work *work;
+ int ret;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ work->id = id_priv;
+ INIT_WORK(&work->work, cma_work_handler, work);
+ work->old_state = CMA_ROUTE_QUERY;
+ work->new_state = CMA_ROUTE_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+
+ route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
+ if (!route->path_rec) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ ret = cma_query_ib_route(id_priv, timeout_ms, work);
+ if (ret)
+ goto err2;
+
+ return 0;
+err2:
+ kfree(route->path_rec);
+ route->path_rec = NULL;
+err1:
+ kfree(work);
+ return ret;
+}
+
+int rdma_set_ib_paths(struct rdma_cm_id *id,
+ struct ib_sa_path_rec *path_rec, int num_paths)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED))
+ return -EINVAL;
+
+ id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL);
+ if (!id->route.path_rec) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths);
+ return 0;
+err:
+ cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_set_ib_paths);
+
+int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY))
+ return -EINVAL;
+
+ atomic_inc(&id_priv->refcount);
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ ret = cma_resolve_ib_route(id_priv, timeout_ms);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED);
+ cma_deref_id(id_priv);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_resolve_route);
+
+static int cma_bind_loopback(struct rdma_id_private *id_priv)
+{
+ struct cma_device *cma_dev;
+ struct ib_port_attr port_attr;
+ union ib_gid *gid;
+ u16 pkey;
+ int ret;
+ u8 p;
+
+ mutex_lock(&lock);
+ list_for_each_entry(cma_dev, &dev_list, list)
+ for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p)
+ if (!ib_query_port (cma_dev->device, p, &port_attr) &&
+ port_attr.state == IB_PORT_ACTIVE)
+ goto port_found;
+
+ if (!list_empty(&dev_list)) {
+ p = 1;
+ cma_dev = list_entry(dev_list.next, struct cma_device, list);
+ } else {
+ ret = -ENODEV;
+ goto out;
+ }
+
+port_found:
+ gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
+ ret = ib_get_cached_gid(cma_dev->device, p, 0, gid);
+ if (ret)
+ goto out;
+
+ ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey);
+ if (ret)
+ goto out;
+
+ ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
+ id_priv->id.port_num = p;
+ cma_attach_to_dev(id_priv, cma_dev);
+out:
+ mutex_unlock(&lock);
+ return ret;
+}
+
+static void addr_handler(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *dev_addr, void *context)
+{
+ struct rdma_id_private *id_priv = context;
+ enum rdma_cm_event_type event;
+
+ atomic_inc(&id_priv->dev_remove);
+ if (!id_priv->cma_dev && !status)
+ status = cma_acquire_dev(id_priv);
+
+ if (status) {
+ if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND))
+ goto out;
+ event = RDMA_CM_EVENT_ADDR_ERROR;
+ } else {
+ if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
+ goto out;
+ memcpy(&id_priv->id.route.addr.src_addr, src_addr,
+ ip_addr_size(src_addr));
+ event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ }
+
+ if (cma_notify_user(id_priv, event, status, NULL, 0)) {
+ cma_exch(id_priv, CMA_DESTROYING);
+ cma_release_remove(id_priv);
+ cma_deref_id(id_priv);
+ rdma_destroy_id(&id_priv->id);
+ return;
+ }
+out:
+ cma_release_remove(id_priv);
+ cma_deref_id(id_priv);
+}
+
+static int cma_resolve_loopback(struct rdma_id_private *id_priv)
+{
+ struct cma_work *work;
+ struct sockaddr_in *src_in, *dst_in;
+ int ret;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ if (!id_priv->cma_dev) {
+ ret = cma_bind_loopback(id_priv);
+ if (ret)
+ goto err;
+ }
+
+ ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
+
+ if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
+ src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
+ dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr;
+ src_in->sin_family = dst_in->sin_family;
+ src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr;
+ }
+
+ work->id = id_priv;
+ INIT_WORK(&work->work, cma_work_handler, work);
+ work->old_state = CMA_ADDR_QUERY;
+ work->new_state = CMA_ADDR_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ queue_work(cma_wq, &work->work);
+ return 0;
+err:
+ kfree(work);
+ return ret;
+}
+
+static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ struct sockaddr *dst_addr)
+{
+ if (src_addr && src_addr->sa_family)
+ return rdma_bind_addr(id, src_addr);
+ else
+ return cma_bind_any(id, dst_addr->sa_family);
+}
+
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ struct sockaddr *dst_addr, int timeout_ms)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (id_priv->state == CMA_IDLE) {
+ ret = cma_bind_addr(id, src_addr, dst_addr);
+ if (ret)
+ return ret;
+ }
+
+ if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY))
+ return -EINVAL;
+
+ atomic_inc(&id_priv->refcount);
+ memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
+ if (cma_any_addr(dst_addr))
+ ret = cma_resolve_loopback(id_priv);
+ else
+ ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr,
+ &id->route.addr.dev_addr,
+ timeout_ms, addr_handler, id_priv);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND);
+ cma_deref_id(id_priv);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_resolve_addr);
+
+static void cma_bind_port(struct rdma_bind_list *bind_list,
+ struct rdma_id_private *id_priv)
+{
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ sin->sin_port = htons(bind_list->port);
+ id_priv->bind_list = bind_list;
+ hlist_add_head(&id_priv->node, &bind_list->owners);
+}
+
+static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
+ unsigned short snum)
+{
+ struct rdma_bind_list *bind_list;
+ int port, start, ret;
+
+ bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
+ if (!bind_list)
+ return -ENOMEM;
+
+ start = snum ? snum : sysctl_local_port_range[0];
+
+ do {
+ ret = idr_get_new_above(ps, bind_list, start, &port);
+ } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
+
+ if (ret)
+ goto err;
+
+ if ((snum && port != snum) ||
+ (!snum && port > sysctl_local_port_range[1])) {
+ idr_remove(ps, port);
+ ret = -EADDRNOTAVAIL;
+ goto err;
+ }
+
+ bind_list->ps = ps;
+ bind_list->port = (unsigned short) port;
+ cma_bind_port(bind_list, id_priv);
+ return 0;
+err:
+ kfree(bind_list);
+ return ret;
+}
+
+static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+{
+ struct rdma_id_private *cur_id;
+ struct sockaddr_in *sin, *cur_sin;
+ struct rdma_bind_list *bind_list;
+ struct hlist_node *node;
+ unsigned short snum;
+
+ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ snum = ntohs(sin->sin_port);
+ if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+ return -EACCES;
+
+ bind_list = idr_find(ps, snum);
+ if (!bind_list)
+ return cma_alloc_port(ps, id_priv, snum);
+
+ /*
+ * We don't support binding to any address if anyone is bound to
+ * a specific address on the same port.
+ */
+ if (cma_any_addr(&id_priv->id.route.addr.src_addr))
+ return -EADDRNOTAVAIL;
+
+ hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
+ if (cma_any_addr(&cur_id->id.route.addr.src_addr))
+ return -EADDRNOTAVAIL;
+
+ cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr;
+ if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr)
+ return -EADDRINUSE;
+ }
+
+ cma_bind_port(bind_list, id_priv);
+ return 0;
+}
+
+static int cma_get_port(struct rdma_id_private *id_priv)
+{
+ struct idr *ps;
+ int ret;
+
+ switch (id_priv->id.ps) {
+ case RDMA_PS_SDP:
+ ps = &sdp_ps;
+ break;
+ case RDMA_PS_TCP:
+ ps = &tcp_ps;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ mutex_lock(&lock);
+ if (cma_any_port(&id_priv->id.route.addr.src_addr))
+ ret = cma_alloc_port(ps, id_priv, 0);
+ else
+ ret = cma_use_port(ps, id_priv);
+ mutex_unlock(&lock);
+
+ return ret;
+}
+
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ if (addr->sa_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
+ return -EINVAL;
+
+ if (!cma_any_addr(addr)) {
+ ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
+ if (!ret)
+ ret = cma_acquire_dev(id_priv);
+ if (ret)
+ goto err;
+ }
+
+ memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
+ ret = cma_get_port(id_priv);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_bind_addr);
+
+static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
+ struct rdma_route *route)
+{
+ struct sockaddr_in *src4, *dst4;
+ struct cma_hdr *cma_hdr;
+ struct sdp_hh *sdp_hdr;
+
+ src4 = (struct sockaddr_in *) &route->addr.src_addr;
+ dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
+
+ switch (ps) {
+ case RDMA_PS_SDP:
+ sdp_hdr = hdr;
+ if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
+ return -EINVAL;
+ sdp_set_ip_ver(sdp_hdr, 4);
+ sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+ sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+ sdp_hdr->port = src4->sin_port;
+ break;
+ default:
+ cma_hdr = hdr;
+ cma_hdr->cma_version = CMA_VERSION;
+ cma_set_ip_ver(cma_hdr, 4);
+ cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+ cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+ cma_hdr->port = src4->sin_port;
+ break;
+ }
+ return 0;
+}
+
+static int cma_connect_ib(struct rdma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ struct ib_cm_req_param req;
+ struct rdma_route *route;
+ void *private_data;
+ int offset, ret;
+
+ memset(&req, 0, sizeof req);
+ offset = cma_user_data_offset(id_priv->id.ps);
+ req.private_data_len = offset + conn_param->private_data_len;
+ private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+ if (!private_data)
+ return -ENOMEM;
+
+ if (conn_param->private_data && conn_param->private_data_len)
+ memcpy(private_data + offset, conn_param->private_data,
+ conn_param->private_data_len);
+
+ id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler,
+ id_priv);
+ if (IS_ERR(id_priv->cm_id.ib)) {
+ ret = PTR_ERR(id_priv->cm_id.ib);
+ goto out;
+ }
+
+ route = &id_priv->id.route;
+ ret = cma_format_hdr(private_data, id_priv->id.ps, route);
+ if (ret)
+ goto out;
+ req.private_data = private_data;
+
+ req.primary_path = &route->path_rec[0];
+ if (route->num_paths == 2)
+ req.alternate_path = &route->path_rec[1];
+
+ req.service_id = cma_get_service_id(id_priv->id.ps,
+ &route->addr.dst_addr);
+ req.qp_num = id_priv->qp_num;
+ req.qp_type = id_priv->qp_type;
+ req.starting_psn = id_priv->seq_num;
+ req.responder_resources = conn_param->responder_resources;
+ req.initiator_depth = conn_param->initiator_depth;
+ req.flow_control = conn_param->flow_control;
+ req.retry_count = conn_param->retry_count;
+ req.rnr_retry_count = conn_param->rnr_retry_count;
+ req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
+ req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
+ req.max_cm_retries = CMA_MAX_CM_RETRIES;
+ req.srq = id_priv->srq ? 1 : 0;
+
+ ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
+out:
+ kfree(private_data);
+ return ret;
+}
+
+int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT))
+ return -EINVAL;
+
+ if (!id->qp) {
+ id_priv->qp_num = conn_param->qp_num;
+ id_priv->qp_type = conn_param->qp_type;
+ id_priv->srq = conn_param->srq;
+ }
+
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ ret = cma_connect_ib(id_priv, conn_param);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_connect);
+
+static int cma_accept_ib(struct rdma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ struct ib_cm_rep_param rep;
+ int ret;
+
+ ret = cma_modify_qp_rtr(&id_priv->id);
+ if (ret)
+ return ret;
+
+ memset(&rep, 0, sizeof rep);
+ rep.qp_num = id_priv->qp_num;
+ rep.starting_psn = id_priv->seq_num;
+ rep.private_data = conn_param->private_data;
+ rep.private_data_len = conn_param->private_data_len;
+ rep.responder_resources = conn_param->responder_resources;
+ rep.initiator_depth = conn_param->initiator_depth;
+ rep.target_ack_delay = CMA_CM_RESPONSE_TIMEOUT;
+ rep.failover_accepted = 0;
+ rep.flow_control = conn_param->flow_control;
+ rep.rnr_retry_count = conn_param->rnr_retry_count;
+ rep.srq = id_priv->srq ? 1 : 0;
+
+ return ib_send_cm_rep(id_priv->cm_id.ib, &rep);
+}
+
+int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ return -EINVAL;
+
+ if (!id->qp && conn_param) {
+ id_priv->qp_num = conn_param->qp_num;
+ id_priv->qp_type = conn_param->qp_type;
+ id_priv->srq = conn_param->srq;
+ }
+
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ if (conn_param)
+ ret = cma_accept_ib(id_priv, conn_param);
+ else
+ ret = cma_rep_recv(id_priv);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ if (ret)
+ goto reject;
+
+ return 0;
+reject:
+ cma_modify_qp_err(id);
+ rdma_reject(id, NULL, 0);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_accept);
+
+int rdma_reject(struct rdma_cm_id *id, const void *private_data,
+ u8 private_data_len)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ return -EINVAL;
+
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ ret = ib_send_cm_rej(id_priv->cm_id.ib,
+ IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
+ private_data, private_data_len);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(rdma_reject);
+
+int rdma_disconnect(struct rdma_cm_id *id)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp(id_priv, CMA_CONNECT) &&
+ !cma_comp(id_priv, CMA_DISCONNECT))
+ return -EINVAL;
+
+ ret = cma_modify_qp_err(id);
+ if (ret)
+ goto out;
+
+ switch (id->device->node_type) {
+ case IB_NODE_CA:
+ /* Initiate or respond to a disconnect. */
+ if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
+ ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
+ break;
+ default:
+ break;
+ }
+out:
+ return ret;
+}
+EXPORT_SYMBOL(rdma_disconnect);
+
+static void cma_add_one(struct ib_device *device)
+{
+ struct cma_device *cma_dev;
+ struct rdma_id_private *id_priv;
+
+ cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL);
+ if (!cma_dev)
+ return;
+
+ cma_dev->device = device;
+ cma_dev->node_guid = device->node_guid;
+ if (!cma_dev->node_guid)
+ goto err;
+
+ init_completion(&cma_dev->comp);
+ atomic_set(&cma_dev->refcount, 1);
+ INIT_LIST_HEAD(&cma_dev->id_list);
+ ib_set_client_data(device, &cma_client, cma_dev);
+
+ mutex_lock(&lock);
+ list_add_tail(&cma_dev->list, &dev_list);
+ list_for_each_entry(id_priv, &listen_any_list, list)
+ cma_listen_on_dev(id_priv, cma_dev);
+ mutex_unlock(&lock);
+ return;
+err:
+ kfree(cma_dev);
+}
+
+static int cma_remove_id_dev(struct rdma_id_private *id_priv)
+{
+ enum cma_state state;
+
+ /* Record that we want to remove the device */
+ state = cma_exch(id_priv, CMA_DEVICE_REMOVAL);
+ if (state == CMA_DESTROYING)
+ return 0;
+
+ cma_cancel_operation(id_priv, state);
+ wait_event(id_priv->wait_remove, !atomic_read(&id_priv->dev_remove));
+
+ /* Check for destruction from another callback. */
+ if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL))
+ return 0;
+
+ return cma_notify_user(id_priv, RDMA_CM_EVENT_DEVICE_REMOVAL,
+ 0, NULL, 0);
+}
+
+static void cma_process_remove(struct cma_device *cma_dev)
+{
+ struct list_head remove_list;
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ INIT_LIST_HEAD(&remove_list);
+
+ mutex_lock(&lock);
+ while (!list_empty(&cma_dev->id_list)) {
+ id_priv = list_entry(cma_dev->id_list.next,
+ struct rdma_id_private, list);
+
+ if (cma_internal_listen(id_priv)) {
+ cma_destroy_listen(id_priv);
+ continue;
+ }
+
+ list_del(&id_priv->list);
+ list_add_tail(&id_priv->list, &remove_list);
+ atomic_inc(&id_priv->refcount);
+ mutex_unlock(&lock);
+
+ ret = cma_remove_id_dev(id_priv);
+ cma_deref_id(id_priv);
+ if (ret)
+ rdma_destroy_id(&id_priv->id);
+
+ mutex_lock(&lock);
+ }
+ mutex_unlock(&lock);
+
+ cma_deref_dev(cma_dev);
+ wait_for_completion(&cma_dev->comp);
+}
+
+static void cma_remove_one(struct ib_device *device)
+{
+ struct cma_device *cma_dev;
+
+ cma_dev = ib_get_client_data(device, &cma_client);
+ if (!cma_dev)
+ return;
+
+ mutex_lock(&lock);
+ list_del(&cma_dev->list);
+ mutex_unlock(&lock);
+
+ cma_process_remove(cma_dev);
+ kfree(cma_dev);
+}
+
+static int cma_init(void)
+{
+ int ret;
+
+ cma_wq = create_singlethread_workqueue("rdma_cm_wq");
+ if (!cma_wq)
+ return -ENOMEM;
+
+ ret = ib_register_client(&cma_client);
+ if (ret)
+ goto err;
+ return 0;
+
+err:
+ destroy_workqueue(cma_wq);
+ return ret;
+}
+
+static void cma_cleanup(void)
+{
+ ib_unregister_client(&cma_client);
+ destroy_workqueue(cma_wq);
+ idr_destroy(&sdp_ps);
+ idr_destroy(&tcp_ps);
+}
+
+module_init(cma_init);
+module_exit(cma_cleanup);
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 838bf54458d2..615fe9cc6c56 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -54,7 +54,7 @@ enum {
/*
* If an FMR is not in use, then the list member will point to either
* its pool's free_list (if the FMR can be mapped again; that is,
- * remap_count < IB_FMR_MAX_REMAPS) or its pool's dirty_list (if the
+ * remap_count < pool->max_remaps) or its pool's dirty_list (if the
* FMR needs to be unmapped before being remapped). In either of
* these cases it is a bug if the ref_count is not 0. In other words,
* if ref_count is > 0, then the list member must not be linked into
@@ -84,6 +84,7 @@ struct ib_fmr_pool {
int pool_size;
int max_pages;
+ int max_remaps;
int dirty_watermark;
int dirty_len;
struct list_head free_list;
@@ -214,8 +215,10 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
{
struct ib_device *device;
struct ib_fmr_pool *pool;
+ struct ib_device_attr *attr;
int i;
int ret;
+ int max_remaps;
if (!params)
return ERR_PTR(-EINVAL);
@@ -228,6 +231,26 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
return ERR_PTR(-ENOSYS);
}
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ if (!attr) {
+ printk(KERN_WARNING "couldn't allocate device attr struct");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = ib_query_device(device, attr);
+ if (ret) {
+ printk(KERN_WARNING "couldn't query device");
+ kfree(attr);
+ return ERR_PTR(ret);
+ }
+
+ if (!attr->max_map_per_fmr)
+ max_remaps = IB_FMR_MAX_REMAPS;
+ else
+ max_remaps = attr->max_map_per_fmr;
+
+ kfree(attr);
+
pool = kmalloc(sizeof *pool, GFP_KERNEL);
if (!pool) {
printk(KERN_WARNING "couldn't allocate pool struct");
@@ -258,6 +281,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
pool->pool_size = 0;
pool->max_pages = params->max_pages_per_fmr;
+ pool->max_remaps = max_remaps;
pool->dirty_watermark = params->dirty_watermark;
pool->dirty_len = 0;
spin_lock_init(&pool->pool_lock);
@@ -279,7 +303,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
struct ib_pool_fmr *fmr;
struct ib_fmr_attr attr = {
.max_pages = params->max_pages_per_fmr,
- .max_maps = IB_FMR_MAX_REMAPS,
+ .max_maps = pool->max_remaps,
.page_shift = params->page_shift
};
@@ -489,7 +513,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
--fmr->ref_count;
if (!fmr->ref_count) {
- if (fmr->remap_count < IB_FMR_MAX_REMAPS) {
+ if (fmr->remap_count < pool->max_remaps) {
list_add_tail(&fmr->list, &pool->free_list);
} else {
list_add_tail(&fmr->list, &pool->dirty_list);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 469b6923a2e2..b38e02a5db35 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -34,6 +34,7 @@
* $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
*/
#include <linux/dma-mapping.h>
+#include <rdma/ib_cache.h>
#include "mad_priv.h"
#include "mad_rmpp.h"
@@ -45,8 +46,7 @@ MODULE_DESCRIPTION("kernel IB MAD API");
MODULE_AUTHOR("Hal Rosenstock");
MODULE_AUTHOR("Sean Hefty");
-
-kmem_cache_t *ib_mad_cache;
+static kmem_cache_t *ib_mad_cache;
static struct list_head ib_mad_port_list;
static u32 ib_mad_client_id = 0;
@@ -352,7 +352,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
INIT_WORK(&mad_agent_priv->local_work, local_completions,
mad_agent_priv);
atomic_set(&mad_agent_priv->refcount, 1);
- init_waitqueue_head(&mad_agent_priv->wait);
+ init_completion(&mad_agent_priv->comp);
return &mad_agent_priv->agent;
@@ -467,7 +467,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device,
mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp;
mad_snoop_priv->agent.port_num = port_num;
mad_snoop_priv->mad_snoop_flags = mad_snoop_flags;
- init_waitqueue_head(&mad_snoop_priv->wait);
+ init_completion(&mad_snoop_priv->comp);
mad_snoop_priv->snoop_index = register_snoop_agent(
&port_priv->qp_info[qpn],
mad_snoop_priv);
@@ -486,6 +486,18 @@ error1:
}
EXPORT_SYMBOL(ib_register_mad_snoop);
+static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
+{
+ if (atomic_dec_and_test(&mad_agent_priv->refcount))
+ complete(&mad_agent_priv->comp);
+}
+
+static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv)
+{
+ if (atomic_dec_and_test(&mad_snoop_priv->refcount))
+ complete(&mad_snoop_priv->comp);
+}
+
static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
{
struct ib_mad_port_private *port_priv;
@@ -509,9 +521,8 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
flush_workqueue(port_priv->wq);
ib_cancel_rmpp_recvs(mad_agent_priv);
- atomic_dec(&mad_agent_priv->refcount);
- wait_event(mad_agent_priv->wait,
- !atomic_read(&mad_agent_priv->refcount));
+ deref_mad_agent(mad_agent_priv);
+ wait_for_completion(&mad_agent_priv->comp);
kfree(mad_agent_priv->reg_req);
ib_dereg_mr(mad_agent_priv->agent.mr);
@@ -529,9 +540,8 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv)
atomic_dec(&qp_info->snoop_count);
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
- atomic_dec(&mad_snoop_priv->refcount);
- wait_event(mad_snoop_priv->wait,
- !atomic_read(&mad_snoop_priv->refcount));
+ deref_snoop_agent(mad_snoop_priv);
+ wait_for_completion(&mad_snoop_priv->comp);
kfree(mad_snoop_priv);
}
@@ -600,8 +610,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info,
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent,
send_buf, mad_send_wc);
- if (atomic_dec_and_test(&mad_snoop_priv->refcount))
- wake_up(&mad_snoop_priv->wait);
+ deref_snoop_agent(mad_snoop_priv);
spin_lock_irqsave(&qp_info->snoop_lock, flags);
}
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
@@ -626,8 +635,7 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info,
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent,
mad_recv_wc);
- if (atomic_dec_and_test(&mad_snoop_priv->refcount))
- wake_up(&mad_snoop_priv->wait);
+ deref_snoop_agent(mad_snoop_priv);
spin_lock_irqsave(&qp_info->snoop_lock, flags);
}
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
@@ -968,8 +976,7 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf)
free_send_rmpp_list(mad_send_wr);
kfree(send_buf->mad);
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
+ deref_mad_agent(mad_agent_priv);
}
EXPORT_SYMBOL(ib_free_send_mad);
@@ -1666,20 +1673,21 @@ static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr,
rwc->recv_buf.mad->mad_hdr.mgmt_class;
}
-static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
+static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv,
+ struct ib_mad_send_wr_private *wr,
struct ib_mad_recv_wc *rwc )
{
struct ib_ah_attr attr;
u8 send_resp, rcv_resp;
+ union ib_gid sgid;
+ struct ib_device *device = mad_agent_priv->agent.device;
+ u8 port_num = mad_agent_priv->agent.port_num;
+ u8 lmc;
send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
mad_hdr.method & IB_MGMT_METHOD_RESP;
rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
- if (!send_resp && rcv_resp)
- /* is request/response. GID/LIDs are both local (same). */
- return 1;
-
if (send_resp == rcv_resp)
/* both requests, or both responses. GIDs different */
return 0;
@@ -1688,48 +1696,78 @@ static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
/* Assume not equal, to avoid false positives. */
return 0;
- if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH))
- return attr.dlid == rwc->wc->slid;
- else if ((attr.ah_flags & IB_AH_GRH) &&
- (rwc->wc->wc_flags & IB_WC_GRH))
- return memcmp(attr.grh.dgid.raw,
- rwc->recv_buf.grh->sgid.raw, 16) == 0;
- else
+ if (!!(attr.ah_flags & IB_AH_GRH) !=
+ !!(rwc->wc->wc_flags & IB_WC_GRH))
/* one has GID, other does not. Assume different */
return 0;
+
+ if (!send_resp && rcv_resp) {
+ /* is request/response. */
+ if (!(attr.ah_flags & IB_AH_GRH)) {
+ if (ib_get_cached_lmc(device, port_num, &lmc))
+ return 0;
+ return (!lmc || !((attr.src_path_bits ^
+ rwc->wc->dlid_path_bits) &
+ ((1 << lmc) - 1)));
+ } else {
+ if (ib_get_cached_gid(device, port_num,
+ attr.grh.sgid_index, &sgid))
+ return 0;
+ return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw,
+ 16);
+ }
+ }
+
+ if (!(attr.ah_flags & IB_AH_GRH))
+ return attr.dlid == rwc->wc->slid;
+ else
+ return !memcmp(attr.grh.dgid.raw, rwc->recv_buf.grh->sgid.raw,
+ 16);
}
+
+static inline int is_direct(u8 class)
+{
+ return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE);
+}
+
struct ib_mad_send_wr_private*
ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
- struct ib_mad_recv_wc *mad_recv_wc)
+ struct ib_mad_recv_wc *wc)
{
- struct ib_mad_send_wr_private *mad_send_wr;
+ struct ib_mad_send_wr_private *wr;
struct ib_mad *mad;
- mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad;
+ mad = (struct ib_mad *)wc->recv_buf.mad;
- list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
- agent_list) {
- if ((mad_send_wr->tid == mad->mad_hdr.tid) &&
- rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
- rcv_has_same_gid(mad_send_wr, mad_recv_wc))
- return mad_send_wr;
+ list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) {
+ if ((wr->tid == mad->mad_hdr.tid) &&
+ rcv_has_same_class(wr, wc) &&
+ /*
+ * Don't check GID for direct routed MADs.
+ * These might have permissive LIDs.
+ */
+ (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) ||
+ rcv_has_same_gid(mad_agent_priv, wr, wc)))
+ return wr;
}
/*
* It's possible to receive the response before we've
* been notified that the send has completed
*/
- list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
- agent_list) {
- if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
- mad_send_wr->tid == mad->mad_hdr.tid &&
- mad_send_wr->timeout &&
- rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
- rcv_has_same_gid(mad_send_wr, mad_recv_wc)) {
+ list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) {
+ if (is_data_mad(mad_agent_priv, wr->send_buf.mad) &&
+ wr->tid == mad->mad_hdr.tid &&
+ wr->timeout &&
+ rcv_has_same_class(wr, wc) &&
+ /*
+ * Don't check GID for direct routed MADs.
+ * These might have permissive LIDs.
+ */
+ (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) ||
+ rcv_has_same_gid(mad_agent_priv, wr, wc)))
/* Verify request has not been canceled */
- return (mad_send_wr->status == IB_WC_SUCCESS) ?
- mad_send_wr : NULL;
- }
+ return (wr->status == IB_WC_SUCCESS) ? wr : NULL;
}
return NULL;
}
@@ -1757,8 +1795,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv,
mad_recv_wc);
if (!mad_recv_wc) {
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
+ deref_mad_agent(mad_agent_priv);
return;
}
}
@@ -1770,8 +1807,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
if (!mad_send_wr) {
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
ib_free_recv_mad(mad_recv_wc);
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
+ deref_mad_agent(mad_agent_priv);
return;
}
ib_mark_mad_done(mad_send_wr);
@@ -1790,8 +1826,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
} else {
mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent,
mad_recv_wc);
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
+ deref_mad_agent(mad_agent_priv);
}
}
@@ -2021,8 +2056,7 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
mad_send_wc);
/* Release reference on agent taken when sending */
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
+ deref_mad_agent(mad_agent_priv);
return;
done:
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index 6c9c133d71ef..d147f3bad2ce 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -37,6 +37,7 @@
#ifndef __IB_MAD_PRIV_H__
#define __IB_MAD_PRIV_H__
+#include <linux/completion.h>
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
@@ -108,7 +109,7 @@ struct ib_mad_agent_private {
struct list_head rmpp_list;
atomic_t refcount;
- wait_queue_head_t wait;
+ struct completion comp;
};
struct ib_mad_snoop_private {
@@ -117,7 +118,7 @@ struct ib_mad_snoop_private {
int snoop_index;
int mad_snoop_flags;
atomic_t refcount;
- wait_queue_head_t wait;
+ struct completion comp;
};
struct ib_mad_send_wr_private {
@@ -211,8 +212,6 @@ struct ib_mad_port_private {
struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE];
};
-extern kmem_cache_t *ib_mad_cache;
-
int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
struct ib_mad_send_wr_private *
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index dfd4e588ce03..d4704e054e30 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -49,7 +49,7 @@ struct mad_rmpp_recv {
struct list_head list;
struct work_struct timeout_work;
struct work_struct cleanup_work;
- wait_queue_head_t wait;
+ struct completion comp;
enum rmpp_state state;
spinlock_t lock;
atomic_t refcount;
@@ -69,10 +69,16 @@ struct mad_rmpp_recv {
u8 method;
};
+static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)
+{
+ if (atomic_dec_and_test(&rmpp_recv->refcount))
+ complete(&rmpp_recv->comp);
+}
+
static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)
{
- atomic_dec(&rmpp_recv->refcount);
- wait_event(rmpp_recv->wait, !atomic_read(&rmpp_recv->refcount));
+ deref_rmpp_recv(rmpp_recv);
+ wait_for_completion(&rmpp_recv->comp);
ib_destroy_ah(rmpp_recv->ah);
kfree(rmpp_recv);
}
@@ -253,7 +259,7 @@ create_rmpp_recv(struct ib_mad_agent_private *agent,
goto error;
rmpp_recv->agent = agent;
- init_waitqueue_head(&rmpp_recv->wait);
+ init_completion(&rmpp_recv->comp);
INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv);
INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv);
spin_lock_init(&rmpp_recv->lock);
@@ -279,12 +285,6 @@ error: kfree(rmpp_recv);
return NULL;
}
-static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)
-{
- if (atomic_dec_and_test(&rmpp_recv->refcount))
- wake_up(&rmpp_recv->wait);
-}
-
static struct mad_rmpp_recv *
find_rmpp_recv(struct ib_mad_agent_private *agent,
struct ib_mad_recv_wc *mad_recv_wc)
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 501cc054cb3b..e911c99ff843 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -47,6 +47,7 @@
#include <rdma/ib_pack.h>
#include <rdma/ib_sa.h>
+#include <rdma/ib_cache.h>
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand subnet administration query support");
@@ -441,6 +442,36 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query)
}
EXPORT_SYMBOL(ib_sa_cancel_query);
+int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
+ struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr)
+{
+ int ret;
+ u16 gid_index;
+
+ memset(ah_attr, 0, sizeof *ah_attr);
+ ah_attr->dlid = be16_to_cpu(rec->dlid);
+ ah_attr->sl = rec->sl;
+ ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f;
+ ah_attr->port_num = port_num;
+
+ if (rec->hop_limit > 1) {
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.dgid = rec->dgid;
+
+ ret = ib_find_cached_gid(device, &rec->sgid, &port_num,
+ &gid_index);
+ if (ret)
+ return ret;
+
+ ah_attr->grh.sgid_index = gid_index;
+ ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label);
+ ah_attr->grh.hop_limit = rec->hop_limit;
+ ah_attr->grh.traffic_class = rec->traffic_class;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ib_init_ah_from_path);
+
static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
{
unsigned long flags;
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 15121cb5a1f6..21f9282c1b25 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -336,7 +336,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
switch (width) {
case 4:
ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >>
- (offset % 4)) & 0xf);
+ (4 - (offset % 8))) & 0xf);
break;
case 8:
ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index f6a05965a4e8..c1c6fda9452c 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -30,8 +30,10 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $
+ * $Id: ucm.c 4311 2005-12-05 18:42:01Z sean.hefty $
*/
+
+#include <linux/completion.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/module.h>
@@ -48,6 +50,7 @@
#include <rdma/ib_cm.h>
#include <rdma/ib_user_cm.h>
+#include <rdma/ib_marshall.h>
MODULE_AUTHOR("Libor Michalek");
MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access");
@@ -61,7 +64,7 @@ struct ib_ucm_device {
};
struct ib_ucm_file {
- struct semaphore mutex;
+ struct mutex file_mutex;
struct file *filp;
struct ib_ucm_device *device;
@@ -72,7 +75,7 @@ struct ib_ucm_file {
struct ib_ucm_context {
int id;
- wait_queue_head_t wait;
+ struct completion comp;
atomic_t ref;
int events_reported;
@@ -138,7 +141,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)
static void ib_ucm_ctx_put(struct ib_ucm_context *ctx)
{
if (atomic_dec_and_test(&ctx->ref))
- wake_up(&ctx->wait);
+ complete(&ctx->comp);
}
static inline int ib_ucm_new_cm_id(int event)
@@ -150,7 +153,7 @@ static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx)
{
struct ib_ucm_event *uevent;
- down(&ctx->file->mutex);
+ mutex_lock(&ctx->file->file_mutex);
list_del(&ctx->file_list);
while (!list_empty(&ctx->events)) {
@@ -165,7 +168,7 @@ static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx)
kfree(uevent);
}
- up(&ctx->file->mutex);
+ mutex_unlock(&ctx->file->file_mutex);
}
static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
@@ -178,7 +181,7 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
return NULL;
atomic_set(&ctx->ref, 1);
- init_waitqueue_head(&ctx->wait);
+ init_completion(&ctx->comp);
ctx->file = file;
INIT_LIST_HEAD(&ctx->events);
@@ -203,36 +206,6 @@ error:
return NULL;
}
-static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath,
- struct ib_sa_path_rec *kpath)
-{
- if (!kpath || !upath)
- return;
-
- memcpy(upath->dgid, kpath->dgid.raw, sizeof *upath->dgid);
- memcpy(upath->sgid, kpath->sgid.raw, sizeof *upath->sgid);
-
- upath->dlid = kpath->dlid;
- upath->slid = kpath->slid;
- upath->raw_traffic = kpath->raw_traffic;
- upath->flow_label = kpath->flow_label;
- upath->hop_limit = kpath->hop_limit;
- upath->traffic_class = kpath->traffic_class;
- upath->reversible = kpath->reversible;
- upath->numb_path = kpath->numb_path;
- upath->pkey = kpath->pkey;
- upath->sl = kpath->sl;
- upath->mtu_selector = kpath->mtu_selector;
- upath->mtu = kpath->mtu;
- upath->rate_selector = kpath->rate_selector;
- upath->rate = kpath->rate;
- upath->packet_life_time = kpath->packet_life_time;
- upath->preference = kpath->preference;
-
- upath->packet_life_time_selector =
- kpath->packet_life_time_selector;
-}
-
static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,
struct ib_cm_req_event_param *kreq)
{
@@ -251,8 +224,10 @@ static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,
ureq->srq = kreq->srq;
ureq->port = kreq->port;
- ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path);
- ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path);
+ ib_copy_path_rec_to_user(&ureq->primary_path, kreq->primary_path);
+ if (kreq->alternate_path)
+ ib_copy_path_rec_to_user(&ureq->alternate_path,
+ kreq->alternate_path);
}
static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep,
@@ -322,8 +297,8 @@ static int ib_ucm_event_process(struct ib_cm_event *evt,
info = evt->param.rej_rcvd.ari;
break;
case IB_CM_LAP_RECEIVED:
- ib_ucm_event_path_get(&uvt->resp.u.lap_resp.path,
- evt->param.lap_rcvd.alternate_path);
+ ib_copy_path_rec_to_user(&uvt->resp.u.lap_resp.path,
+ evt->param.lap_rcvd.alternate_path);
uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE;
uvt->resp.present = IB_UCM_PRES_ALTERNATE;
break;
@@ -400,11 +375,11 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id,
if (result)
goto err2;
- down(&ctx->file->mutex);
+ mutex_lock(&ctx->file->file_mutex);
list_add_tail(&uevent->file_list, &ctx->file->events);
list_add_tail(&uevent->ctx_list, &ctx->events);
wake_up_interruptible(&ctx->file->poll_wait);
- up(&ctx->file->mutex);
+ mutex_unlock(&ctx->file->file_mutex);
return 0;
err2:
@@ -430,7 +405,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file,
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- down(&file->mutex);
+ mutex_lock(&file->file_mutex);
while (list_empty(&file->events)) {
if (file->filp->f_flags & O_NONBLOCK) {
@@ -445,9 +420,9 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file,
prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE);
- up(&file->mutex);
+ mutex_unlock(&file->file_mutex);
schedule();
- down(&file->mutex);
+ mutex_lock(&file->file_mutex);
finish_wait(&file->poll_wait, &wait);
}
@@ -507,7 +482,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file,
kfree(uevent->info);
kfree(uevent);
done:
- up(&file->mutex);
+ mutex_unlock(&file->file_mutex);
return result;
}
@@ -526,9 +501,9 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- down(&file->mutex);
+ mutex_lock(&file->file_mutex);
ctx = ib_ucm_ctx_alloc(file);
- up(&file->mutex);
+ mutex_unlock(&file->file_mutex);
if (!ctx)
return -ENOMEM;
@@ -586,8 +561,8 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- atomic_dec(&ctx->ref);
- wait_event(ctx->wait, !atomic_read(&ctx->ref));
+ ib_ucm_ctx_put(ctx);
+ wait_for_completion(&ctx->comp);
/* No new events will be generated after destroying the cm_id. */
ib_destroy_cm_id(ctx->cm_id);
@@ -635,65 +610,11 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,
return result;
}
-static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr,
- struct ib_ah_attr *src_attr)
-{
- memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw,
- sizeof src_attr->grh.dgid);
- dest_attr->grh_flow_label = src_attr->grh.flow_label;
- dest_attr->grh_sgid_index = src_attr->grh.sgid_index;
- dest_attr->grh_hop_limit = src_attr->grh.hop_limit;
- dest_attr->grh_traffic_class = src_attr->grh.traffic_class;
-
- dest_attr->dlid = src_attr->dlid;
- dest_attr->sl = src_attr->sl;
- dest_attr->src_path_bits = src_attr->src_path_bits;
- dest_attr->static_rate = src_attr->static_rate;
- dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH);
- dest_attr->port_num = src_attr->port_num;
-}
-
-static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr,
- struct ib_qp_attr *src_attr)
-{
- dest_attr->cur_qp_state = src_attr->cur_qp_state;
- dest_attr->path_mtu = src_attr->path_mtu;
- dest_attr->path_mig_state = src_attr->path_mig_state;
- dest_attr->qkey = src_attr->qkey;
- dest_attr->rq_psn = src_attr->rq_psn;
- dest_attr->sq_psn = src_attr->sq_psn;
- dest_attr->dest_qp_num = src_attr->dest_qp_num;
- dest_attr->qp_access_flags = src_attr->qp_access_flags;
-
- dest_attr->max_send_wr = src_attr->cap.max_send_wr;
- dest_attr->max_recv_wr = src_attr->cap.max_recv_wr;
- dest_attr->max_send_sge = src_attr->cap.max_send_sge;
- dest_attr->max_recv_sge = src_attr->cap.max_recv_sge;
- dest_attr->max_inline_data = src_attr->cap.max_inline_data;
-
- ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr);
- ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr);
-
- dest_attr->pkey_index = src_attr->pkey_index;
- dest_attr->alt_pkey_index = src_attr->alt_pkey_index;
- dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify;
- dest_attr->sq_draining = src_attr->sq_draining;
- dest_attr->max_rd_atomic = src_attr->max_rd_atomic;
- dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic;
- dest_attr->min_rnr_timer = src_attr->min_rnr_timer;
- dest_attr->port_num = src_attr->port_num;
- dest_attr->timeout = src_attr->timeout;
- dest_attr->retry_cnt = src_attr->retry_cnt;
- dest_attr->rnr_retry = src_attr->rnr_retry;
- dest_attr->alt_port_num = src_attr->alt_port_num;
- dest_attr->alt_timeout = src_attr->alt_timeout;
-}
-
static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,
const char __user *inbuf,
int in_len, int out_len)
{
- struct ib_ucm_init_qp_attr_resp resp;
+ struct ib_uverbs_qp_attr resp;
struct ib_ucm_init_qp_attr cmd;
struct ib_ucm_context *ctx;
struct ib_qp_attr qp_attr;
@@ -716,7 +637,7 @@ static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,
if (result)
goto out;
- ib_ucm_copy_qp_attr(&resp, &qp_attr);
+ ib_copy_qp_attr_to_user(&resp, &qp_attr);
if (copy_to_user((void __user *)(unsigned long)cmd.response,
&resp, sizeof(resp)))
@@ -727,6 +648,17 @@ out:
return result;
}
+static int ucm_validate_listen(__be64 service_id, __be64 service_mask)
+{
+ service_id &= service_mask;
+
+ if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||
+ ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))
+ return -EINVAL;
+
+ return 0;
+}
+
static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
const char __user *inbuf,
int in_len, int out_len)
@@ -742,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask);
+ result = ucm_validate_listen(cmd.service_id, cmd.service_mask);
+ if (result)
+ goto out;
+
+ result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask,
+ NULL);
+out:
ib_ucm_ctx_put(ctx);
return result;
}
@@ -791,7 +729,7 @@ static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len)
static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src)
{
- struct ib_ucm_path_rec ucm_path;
+ struct ib_user_path_rec upath;
struct ib_sa_path_rec *sa_path;
*path = NULL;
@@ -803,36 +741,14 @@ static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src)
if (!sa_path)
return -ENOMEM;
- if (copy_from_user(&ucm_path, (void __user *)(unsigned long)src,
- sizeof(ucm_path))) {
+ if (copy_from_user(&upath, (void __user *)(unsigned long)src,
+ sizeof(upath))) {
kfree(sa_path);
return -EFAULT;
}
- memcpy(sa_path->dgid.raw, ucm_path.dgid, sizeof sa_path->dgid);
- memcpy(sa_path->sgid.raw, ucm_path.sgid, sizeof sa_path->sgid);
-
- sa_path->dlid = ucm_path.dlid;
- sa_path->slid = ucm_path.slid;
- sa_path->raw_traffic = ucm_path.raw_traffic;
- sa_path->flow_label = ucm_path.flow_label;
- sa_path->hop_limit = ucm_path.hop_limit;
- sa_path->traffic_class = ucm_path.traffic_class;
- sa_path->reversible = ucm_path.reversible;
- sa_path->numb_path = ucm_path.numb_path;
- sa_path->pkey = ucm_path.pkey;
- sa_path->sl = ucm_path.sl;
- sa_path->mtu_selector = ucm_path.mtu_selector;
- sa_path->mtu = ucm_path.mtu;
- sa_path->rate_selector = ucm_path.rate_selector;
- sa_path->rate = ucm_path.rate;
- sa_path->packet_life_time = ucm_path.packet_life_time;
- sa_path->preference = ucm_path.preference;
-
- sa_path->packet_life_time_selector =
- ucm_path.packet_life_time_selector;
-
+ ib_copy_path_rec_from_user(sa_path, &upath);
*path = sa_path;
return 0;
}
@@ -1128,7 +1044,6 @@ static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file,
param.service_id = cmd.sid;
param.timeout_ms = cmd.timeout;
param.max_cm_retries = cmd.max_cm_retries;
- param.pkey = cmd.pkey;
ctx = ib_ucm_ctx_get(file, cmd.id);
if (!IS_ERR(ctx)) {
@@ -1261,7 +1176,7 @@ static int ib_ucm_open(struct inode *inode, struct file *filp)
INIT_LIST_HEAD(&file->ctxs);
init_waitqueue_head(&file->poll_wait);
- init_MUTEX(&file->mutex);
+ mutex_init(&file->file_mutex);
filp->private_data = file;
file->filp = filp;
@@ -1275,11 +1190,11 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
struct ib_ucm_file *file = filp->private_data;
struct ib_ucm_context *ctx;
- down(&file->mutex);
+ mutex_lock(&file->file_mutex);
while (!list_empty(&file->ctxs)) {
ctx = list_entry(file->ctxs.next,
struct ib_ucm_context, file_list);
- up(&file->mutex);
+ mutex_unlock(&file->file_mutex);
mutex_lock(&ctx_id_mutex);
idr_remove(&ctx_id_table, ctx->id);
@@ -1289,9 +1204,9 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
ib_ucm_cleanup_events(ctx);
kfree(ctx);
- down(&file->mutex);
+ mutex_lock(&file->file_mutex);
}
- up(&file->mutex);
+ mutex_unlock(&file->file_mutex);
kfree(file);
return 0;
}
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 3372d67ff139..bb9bee56a824 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -132,7 +132,7 @@ struct ib_ucq_object {
u32 async_events_reported;
};
-extern struct mutex ib_uverbs_idr_mutex;
+extern spinlock_t ib_uverbs_idr_lock;
extern struct idr ib_uverbs_pd_idr;
extern struct idr ib_uverbs_mr_idr;
extern struct idr ib_uverbs_mw_idr;
@@ -141,6 +141,8 @@ extern struct idr ib_uverbs_cq_idr;
extern struct idr ib_uverbs_qp_idr;
extern struct idr ib_uverbs_srq_idr;
+void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
+
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd);
void ib_uverbs_release_event_file(struct kref *ref);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 9f69bd48eb1b..76bf61e9b552 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -50,6 +50,196 @@
(udata)->outlen = (olen); \
} while (0)
+/*
+ * The ib_uobject locking scheme is as follows:
+ *
+ * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it
+ * needs to be held during all idr operations. When an object is
+ * looked up, a reference must be taken on the object's kref before
+ * dropping this lock.
+ *
+ * - Each object also has an rwsem. This rwsem must be held for
+ * reading while an operation that uses the object is performed.
+ * For example, while registering an MR, the associated PD's
+ * uobject.mutex must be held for reading. The rwsem must be held
+ * for writing while initializing or destroying an object.
+ *
+ * - In addition, each object has a "live" flag. If this flag is not
+ * set, then lookups of the object will fail even if it is found in
+ * the idr. This handles a reader that blocks and does not acquire
+ * the rwsem until after the object is destroyed. The destroy
+ * operation will set the live flag to 0 and then drop the rwsem;
+ * this will allow the reader to acquire the rwsem, see that the
+ * live flag is 0, and then drop the rwsem and its reference to
+ * object. The underlying storage will not be freed until the last
+ * reference to the object is dropped.
+ */
+
+static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
+ struct ib_ucontext *context)
+{
+ uobj->user_handle = user_handle;
+ uobj->context = context;
+ kref_init(&uobj->ref);
+ init_rwsem(&uobj->mutex);
+ uobj->live = 0;
+}
+
+static void release_uobj(struct kref *kref)
+{
+ kfree(container_of(kref, struct ib_uobject, ref));
+}
+
+static void put_uobj(struct ib_uobject *uobj)
+{
+ kref_put(&uobj->ref, release_uobj);
+}
+
+static void put_uobj_read(struct ib_uobject *uobj)
+{
+ up_read(&uobj->mutex);
+ put_uobj(uobj);
+}
+
+static void put_uobj_write(struct ib_uobject *uobj)
+{
+ up_write(&uobj->mutex);
+ put_uobj(uobj);
+}
+
+static int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj)
+{
+ int ret;
+
+retry:
+ if (!idr_pre_get(idr, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(&ib_uverbs_idr_lock);
+ ret = idr_get_new(idr, uobj, &uobj->id);
+ spin_unlock(&ib_uverbs_idr_lock);
+
+ if (ret == -EAGAIN)
+ goto retry;
+
+ return ret;
+}
+
+void idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj)
+{
+ spin_lock(&ib_uverbs_idr_lock);
+ idr_remove(idr, uobj->id);
+ spin_unlock(&ib_uverbs_idr_lock);
+}
+
+static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
+ struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj;
+
+ spin_lock(&ib_uverbs_idr_lock);
+ uobj = idr_find(idr, id);
+ if (uobj)
+ kref_get(&uobj->ref);
+ spin_unlock(&ib_uverbs_idr_lock);
+
+ return uobj;
+}
+
+static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
+ struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj;
+
+ uobj = __idr_get_uobj(idr, id, context);
+ if (!uobj)
+ return NULL;
+
+ down_read(&uobj->mutex);
+ if (!uobj->live) {
+ put_uobj_read(uobj);
+ return NULL;
+ }
+
+ return uobj;
+}
+
+static struct ib_uobject *idr_write_uobj(struct idr *idr, int id,
+ struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj;
+
+ uobj = __idr_get_uobj(idr, id, context);
+ if (!uobj)
+ return NULL;
+
+ down_write(&uobj->mutex);
+ if (!uobj->live) {
+ put_uobj_write(uobj);
+ return NULL;
+ }
+
+ return uobj;
+}
+
+static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj;
+
+ uobj = idr_read_uobj(idr, id, context);
+ return uobj ? uobj->object : NULL;
+}
+
+static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
+{
+ return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context);
+}
+
+static void put_pd_read(struct ib_pd *pd)
+{
+ put_uobj_read(pd->uobject);
+}
+
+static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context)
+{
+ return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context);
+}
+
+static void put_cq_read(struct ib_cq *cq)
+{
+ put_uobj_read(cq->uobject);
+}
+
+static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
+{
+ return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context);
+}
+
+static void put_ah_read(struct ib_ah *ah)
+{
+ put_uobj_read(ah->uobject);
+}
+
+static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
+{
+ return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context);
+}
+
+static void put_qp_read(struct ib_qp *qp)
+{
+ put_uobj_read(qp->uobject);
+}
+
+static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
+{
+ return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context);
+}
+
+static void put_srq_read(struct ib_srq *srq)
+{
+ put_uobj_read(srq->uobject);
+}
+
ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
const char __user *buf,
int in_len, int out_len)
@@ -80,8 +270,10 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
in_len - sizeof cmd, out_len - sizeof resp);
ucontext = ibdev->alloc_ucontext(ibdev, &udata);
- if (IS_ERR(ucontext))
- return PTR_ERR(file->ucontext);
+ if (IS_ERR(ucontext)) {
+ ret = PTR_ERR(file->ucontext);
+ goto err;
+ }
ucontext->device = ibdev;
INIT_LIST_HEAD(&ucontext->pd_list);
@@ -278,7 +470,8 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- uobj->context = file->ucontext;
+ init_uobj(uobj, 0, file->ucontext);
+ down_write(&uobj->mutex);
pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
file->ucontext, &udata);
@@ -291,20 +484,10 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
pd->uobject = uobj;
atomic_set(&pd->usecnt, 0);
- mutex_lock(&ib_uverbs_idr_mutex);
-
-retry:
- if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_up;
- }
-
- ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id);
-
- if (ret == -EAGAIN)
- goto retry;
+ uobj->object = pd;
+ ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj);
if (ret)
- goto err_up;
+ goto err_idr;
memset(&resp, 0, sizeof resp);
resp.pd_handle = uobj->id;
@@ -312,26 +495,27 @@ retry:
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
mutex_lock(&file->mutex);
list_add_tail(&uobj->list, &file->ucontext->pd_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ uobj->live = 1;
+
+ up_write(&uobj->mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_pd_idr, uobj->id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
+err_idr:
ib_dealloc_pd(pd);
err:
- kfree(uobj);
+ put_uobj_write(uobj);
return ret;
}
@@ -340,37 +524,34 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
int in_len, int out_len)
{
struct ib_uverbs_dealloc_pd cmd;
- struct ib_pd *pd;
struct ib_uobject *uobj;
- int ret = -EINVAL;
+ int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
+ uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
- pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
- if (!pd || pd->uobject->context != file->ucontext)
- goto out;
+ ret = ib_dealloc_pd(uobj->object);
+ if (!ret)
+ uobj->live = 0;
- uobj = pd->uobject;
+ put_uobj_write(uobj);
- ret = ib_dealloc_pd(pd);
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
+ idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
mutex_lock(&file->mutex);
list_del(&uobj->list);
mutex_unlock(&file->mutex);
- kfree(uobj);
-
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ put_uobj(uobj);
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
@@ -410,7 +591,8 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- obj->uobject.context = file->ucontext;
+ init_uobj(&obj->uobject, 0, file->ucontext);
+ down_write(&obj->uobject.mutex);
/*
* We ask for writable memory if any access flags other than
@@ -427,23 +609,14 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
obj->umem.virt_base = cmd.hca_va;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
- if (!pd || pd->uobject->context != file->ucontext) {
- ret = -EINVAL;
- goto err_up;
- }
-
- if (!pd->device->reg_user_mr) {
- ret = -ENOSYS;
- goto err_up;
- }
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ if (!pd)
+ goto err_release;
mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
if (IS_ERR(mr)) {
ret = PTR_ERR(mr);
- goto err_up;
+ goto err_put;
}
mr->device = pd->device;
@@ -452,53 +625,48 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
- memset(&resp, 0, sizeof resp);
- resp.lkey = mr->lkey;
- resp.rkey = mr->rkey;
-
-retry:
- if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_unreg;
- }
-
- ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id);
-
- if (ret == -EAGAIN)
- goto retry;
+ obj->uobject.object = mr;
+ ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uobject);
if (ret)
goto err_unreg;
+ memset(&resp, 0, sizeof resp);
+ resp.lkey = mr->lkey;
+ resp.rkey = mr->rkey;
resp.mr_handle = obj->uobject.id;
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
+ put_pd_read(pd);
+
mutex_lock(&file->mutex);
list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ obj->uobject.live = 1;
+
+ up_write(&obj->uobject.mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_mr_idr, obj->uobject.id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uobject);
err_unreg:
ib_dereg_mr(mr);
- atomic_dec(&pd->usecnt);
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
+err_put:
+ put_pd_read(pd);
+err_release:
ib_umem_release(file->device->ib_dev, &obj->umem);
err_free:
- kfree(obj);
+ put_uobj_write(&obj->uobject);
return ret;
}
@@ -508,37 +676,40 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
{
struct ib_uverbs_dereg_mr cmd;
struct ib_mr *mr;
+ struct ib_uobject *uobj;
struct ib_umem_object *memobj;
int ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
- if (!mr || mr->uobject->context != file->ucontext)
- goto out;
+ uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
- memobj = container_of(mr->uobject, struct ib_umem_object, uobject);
+ memobj = container_of(uobj, struct ib_umem_object, uobject);
+ mr = uobj->object;
ret = ib_dereg_mr(mr);
+ if (!ret)
+ uobj->live = 0;
+
+ put_uobj_write(uobj);
+
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
+ idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
mutex_lock(&file->mutex);
- list_del(&memobj->uobject.list);
+ list_del(&uobj->list);
mutex_unlock(&file->mutex);
ib_umem_release(file->device->ib_dev, &memobj->umem);
- kfree(memobj);
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ put_uobj(uobj);
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
@@ -577,7 +748,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
struct ib_uverbs_create_cq cmd;
struct ib_uverbs_create_cq_resp resp;
struct ib_udata udata;
- struct ib_ucq_object *uobj;
+ struct ib_ucq_object *obj;
struct ib_uverbs_event_file *ev_file = NULL;
struct ib_cq *cq;
int ret;
@@ -595,10 +766,13 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
if (cmd.comp_vector >= file->device->num_comp_vectors)
return -EINVAL;
- uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
- if (!uobj)
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
return -ENOMEM;
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext);
+ down_write(&obj->uobject.mutex);
+
if (cmd.comp_channel >= 0) {
ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
if (!ev_file) {
@@ -607,72 +781,64 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
}
}
- uobj->uobject.user_handle = cmd.user_handle;
- uobj->uobject.context = file->ucontext;
- uobj->uverbs_file = file;
- uobj->comp_events_reported = 0;
- uobj->async_events_reported = 0;
- INIT_LIST_HEAD(&uobj->comp_list);
- INIT_LIST_HEAD(&uobj->async_list);
+ obj->uverbs_file = file;
+ obj->comp_events_reported = 0;
+ obj->async_events_reported = 0;
+ INIT_LIST_HEAD(&obj->comp_list);
+ INIT_LIST_HEAD(&obj->async_list);
cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
file->ucontext, &udata);
if (IS_ERR(cq)) {
ret = PTR_ERR(cq);
- goto err;
+ goto err_file;
}
cq->device = file->device->ib_dev;
- cq->uobject = &uobj->uobject;
+ cq->uobject = &obj->uobject;
cq->comp_handler = ib_uverbs_comp_handler;
cq->event_handler = ib_uverbs_cq_event_handler;
cq->cq_context = ev_file;
atomic_set(&cq->usecnt, 0);
- mutex_lock(&ib_uverbs_idr_mutex);
-
-retry:
- if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_up;
- }
-
- ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id);
-
- if (ret == -EAGAIN)
- goto retry;
+ obj->uobject.object = cq;
+ ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject);
if (ret)
- goto err_up;
+ goto err_free;
memset(&resp, 0, sizeof resp);
- resp.cq_handle = uobj->uobject.id;
+ resp.cq_handle = obj->uobject.id;
resp.cqe = cq->cqe;
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
mutex_lock(&file->mutex);
- list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list);
+ list_add_tail(&obj->uobject.list, &file->ucontext->cq_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ obj->uobject.live = 1;
+
+ up_write(&obj->uobject.mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject);
+
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
+err_free:
ib_destroy_cq(cq);
-err:
+err_file:
if (ev_file)
- ib_uverbs_release_ucq(file, ev_file, uobj);
- kfree(uobj);
+ ib_uverbs_release_ucq(file, ev_file, obj);
+
+err:
+ put_uobj_write(&obj->uobject);
return ret;
}
@@ -693,11 +859,9 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
- mutex_lock(&ib_uverbs_idr_mutex);
-
- cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
- if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
- goto out;
+ cq = idr_read_cq(cmd.cq_handle, file->ucontext);
+ if (!cq)
+ return -EINVAL;
ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
if (ret)
@@ -711,7 +875,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
ret = -EFAULT;
out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ put_cq_read(cq);
return ret ? ret : in_len;
}
@@ -722,6 +886,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
{
struct ib_uverbs_poll_cq cmd;
struct ib_uverbs_poll_cq_resp *resp;
+ struct ib_uobject *uobj;
struct ib_cq *cq;
struct ib_wc *wc;
int ret = 0;
@@ -742,15 +907,17 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
goto out_wc;
}
- mutex_lock(&ib_uverbs_idr_mutex);
- cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
- if (!cq || cq->uobject->context != file->ucontext) {
+ uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+ if (!uobj) {
ret = -EINVAL;
goto out;
}
+ cq = uobj->object;
resp->count = ib_poll_cq(cq, cmd.ne, wc);
+ put_uobj_read(uobj);
+
for (i = 0; i < resp->count; i++) {
resp->wc[i].wr_id = wc[i].wr_id;
resp->wc[i].status = wc[i].status;
@@ -772,7 +939,6 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
ret = -EFAULT;
out:
- mutex_unlock(&ib_uverbs_idr_mutex);
kfree(resp);
out_wc:
@@ -785,22 +951,23 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
int out_len)
{
struct ib_uverbs_req_notify_cq cmd;
+ struct ib_uobject *uobj;
struct ib_cq *cq;
- int ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
- cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
- if (cq && cq->uobject->context == file->ucontext) {
- ib_req_notify_cq(cq, cmd.solicited_only ?
- IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
- ret = in_len;
- }
- mutex_unlock(&ib_uverbs_idr_mutex);
+ uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
+ cq = uobj->object;
- return ret;
+ ib_req_notify_cq(cq, cmd.solicited_only ?
+ IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
+
+ put_uobj_read(uobj);
+
+ return in_len;
}
ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
@@ -809,52 +976,50 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
{
struct ib_uverbs_destroy_cq cmd;
struct ib_uverbs_destroy_cq_resp resp;
+ struct ib_uobject *uobj;
struct ib_cq *cq;
- struct ib_ucq_object *uobj;
+ struct ib_ucq_object *obj;
struct ib_uverbs_event_file *ev_file;
- u64 user_handle;
int ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- memset(&resp, 0, sizeof resp);
-
- mutex_lock(&ib_uverbs_idr_mutex);
+ uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
+ cq = uobj->object;
+ ev_file = cq->cq_context;
+ obj = container_of(cq->uobject, struct ib_ucq_object, uobject);
- cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
- if (!cq || cq->uobject->context != file->ucontext)
- goto out;
+ ret = ib_destroy_cq(cq);
+ if (!ret)
+ uobj->live = 0;
- user_handle = cq->uobject->user_handle;
- uobj = container_of(cq->uobject, struct ib_ucq_object, uobject);
- ev_file = cq->cq_context;
+ put_uobj_write(uobj);
- ret = ib_destroy_cq(cq);
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
+ idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
mutex_lock(&file->mutex);
- list_del(&uobj->uobject.list);
+ list_del(&uobj->list);
mutex_unlock(&file->mutex);
- ib_uverbs_release_ucq(file, ev_file, uobj);
+ ib_uverbs_release_ucq(file, ev_file, obj);
- resp.comp_events_reported = uobj->comp_events_reported;
- resp.async_events_reported = uobj->async_events_reported;
+ memset(&resp, 0, sizeof resp);
+ resp.comp_events_reported = obj->comp_events_reported;
+ resp.async_events_reported = obj->async_events_reported;
- kfree(uobj);
+ put_uobj(uobj);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
- ret = -EFAULT;
-
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ return -EFAULT;
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
@@ -864,7 +1029,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
struct ib_uverbs_create_qp cmd;
struct ib_uverbs_create_qp_resp resp;
struct ib_udata udata;
- struct ib_uqp_object *uobj;
+ struct ib_uqp_object *obj;
struct ib_pd *pd;
struct ib_cq *scq, *rcq;
struct ib_srq *srq;
@@ -882,23 +1047,21 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
- uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
- if (!uobj)
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
return -ENOMEM;
- mutex_lock(&ib_uverbs_idr_mutex);
+ init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext);
+ down_write(&obj->uevent.uobject.mutex);
- pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
- scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
- rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
- srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL;
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ scq = idr_read_cq(cmd.send_cq_handle, file->ucontext);
+ rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext);
+ srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
- if (!pd || pd->uobject->context != file->ucontext ||
- !scq || scq->uobject->context != file->ucontext ||
- !rcq || rcq->uobject->context != file->ucontext ||
- (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) {
+ if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) {
ret = -EINVAL;
- goto err_up;
+ goto err_put;
}
attr.event_handler = ib_uverbs_qp_event_handler;
@@ -915,16 +1078,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
attr.cap.max_recv_sge = cmd.max_recv_sge;
attr.cap.max_inline_data = cmd.max_inline_data;
- uobj->uevent.uobject.user_handle = cmd.user_handle;
- uobj->uevent.uobject.context = file->ucontext;
- uobj->uevent.events_reported = 0;
- INIT_LIST_HEAD(&uobj->uevent.event_list);
- INIT_LIST_HEAD(&uobj->mcast_list);
+ obj->uevent.events_reported = 0;
+ INIT_LIST_HEAD(&obj->uevent.event_list);
+ INIT_LIST_HEAD(&obj->mcast_list);
qp = pd->device->create_qp(pd, &attr, &udata);
if (IS_ERR(qp)) {
ret = PTR_ERR(qp);
- goto err_up;
+ goto err_put;
}
qp->device = pd->device;
@@ -932,7 +1093,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
qp->send_cq = attr.send_cq;
qp->recv_cq = attr.recv_cq;
qp->srq = attr.srq;
- qp->uobject = &uobj->uevent.uobject;
+ qp->uobject = &obj->uevent.uobject;
qp->event_handler = attr.event_handler;
qp->qp_context = attr.qp_context;
qp->qp_type = attr.qp_type;
@@ -942,23 +1103,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
if (attr.srq)
atomic_inc(&attr.srq->usecnt);
- memset(&resp, 0, sizeof resp);
- resp.qpn = qp->qp_num;
-
-retry:
- if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_destroy;
- }
-
- ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id);
-
- if (ret == -EAGAIN)
- goto retry;
+ obj->uevent.uobject.object = qp;
+ ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
if (ret)
goto err_destroy;
- resp.qp_handle = uobj->uevent.uobject.id;
+ memset(&resp, 0, sizeof resp);
+ resp.qpn = qp->qp_num;
+ resp.qp_handle = obj->uevent.uobject.id;
resp.max_recv_sge = attr.cap.max_recv_sge;
resp.max_send_sge = attr.cap.max_send_sge;
resp.max_recv_wr = attr.cap.max_recv_wr;
@@ -968,32 +1120,42 @@ retry:
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
+ put_pd_read(pd);
+ put_cq_read(scq);
+ put_cq_read(rcq);
+ if (srq)
+ put_srq_read(srq);
+
mutex_lock(&file->mutex);
- list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
+ list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ obj->uevent.uobject.live = 1;
+
+ up_write(&obj->uevent.uobject.mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
err_destroy:
ib_destroy_qp(qp);
- atomic_dec(&pd->usecnt);
- atomic_dec(&attr.send_cq->usecnt);
- atomic_dec(&attr.recv_cq->usecnt);
- if (attr.srq)
- atomic_dec(&attr.srq->usecnt);
-
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
- kfree(uobj);
+err_put:
+ if (pd)
+ put_pd_read(pd);
+ if (scq)
+ put_cq_read(scq);
+ if (rcq)
+ put_cq_read(rcq);
+ if (srq)
+ put_srq_read(srq);
+
+ put_uobj_write(&obj->uevent.uobject);
return ret;
}
@@ -1018,15 +1180,15 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
goto out;
}
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (qp && qp->uobject->context == file->ucontext)
- ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
- else
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp) {
ret = -EINVAL;
+ goto out;
+ }
- mutex_unlock(&ib_uverbs_idr_mutex);
+ ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+
+ put_qp_read(qp);
if (ret)
goto out;
@@ -1113,10 +1275,8 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
if (!attr)
return -ENOMEM;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext) {
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp) {
ret = -EINVAL;
goto out;
}
@@ -1168,13 +1328,15 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
attr->alt_ah_attr.port_num = cmd.alt_dest.port_num;
ret = ib_modify_qp(qp, attr, cmd.attr_mask);
+
+ put_qp_read(qp);
+
if (ret)
goto out;
ret = in_len;
out:
- mutex_unlock(&ib_uverbs_idr_mutex);
kfree(attr);
return ret;
@@ -1186,8 +1348,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
{
struct ib_uverbs_destroy_qp cmd;
struct ib_uverbs_destroy_qp_resp resp;
+ struct ib_uobject *uobj;
struct ib_qp *qp;
- struct ib_uqp_object *uobj;
+ struct ib_uqp_object *obj;
int ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1195,43 +1358,43 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
memset(&resp, 0, sizeof resp);
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext)
- goto out;
-
- uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
+ uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
+ qp = uobj->object;
+ obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
- if (!list_empty(&uobj->mcast_list)) {
- ret = -EBUSY;
- goto out;
+ if (!list_empty(&obj->mcast_list)) {
+ put_uobj_write(uobj);
+ return -EBUSY;
}
ret = ib_destroy_qp(qp);
+ if (!ret)
+ uobj->live = 0;
+
+ put_uobj_write(uobj);
+
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
+ idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
mutex_lock(&file->mutex);
- list_del(&uobj->uevent.uobject.list);
+ list_del(&uobj->list);
mutex_unlock(&file->mutex);
- ib_uverbs_release_uevent(file, &uobj->uevent);
+ ib_uverbs_release_uevent(file, &obj->uevent);
- resp.events_reported = uobj->uevent.events_reported;
+ resp.events_reported = obj->uevent.events_reported;
- kfree(uobj);
+ put_uobj(uobj);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
- ret = -EFAULT;
-
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ return -EFAULT;
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
@@ -1244,6 +1407,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
struct ib_send_wr *wr = NULL, *last, *next, *bad_wr;
struct ib_qp *qp;
int i, sg_ind;
+ int is_ud;
ssize_t ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1260,12 +1424,11 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
if (!user_wr)
return -ENOMEM;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext)
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp)
goto out;
+ is_ud = qp->qp_type == IB_QPT_UD;
sg_ind = 0;
last = NULL;
for (i = 0; i < cmd.wr_count; ++i) {
@@ -1273,12 +1436,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
buf + sizeof cmd + i * cmd.wqe_size,
cmd.wqe_size)) {
ret = -EFAULT;
- goto out;
+ goto out_put;
}
if (user_wr->num_sge + sg_ind > cmd.sge_count) {
ret = -EINVAL;
- goto out;
+ goto out_put;
}
next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
@@ -1286,7 +1449,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
GFP_KERNEL);
if (!next) {
ret = -ENOMEM;
- goto out;
+ goto out_put;
}
if (!last)
@@ -1302,12 +1465,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
next->send_flags = user_wr->send_flags;
next->imm_data = (__be32 __force) user_wr->imm_data;
- if (qp->qp_type == IB_QPT_UD) {
- next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr,
- user_wr->wr.ud.ah);
+ if (is_ud) {
+ next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah,
+ file->ucontext);
if (!next->wr.ud.ah) {
ret = -EINVAL;
- goto out;
+ goto out_put;
}
next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn;
next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey;
@@ -1344,7 +1507,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
sg_ind * sizeof (struct ib_sge),
next->num_sge * sizeof (struct ib_sge))) {
ret = -EFAULT;
- goto out;
+ goto out_put;
}
sg_ind += next->num_sge;
} else
@@ -1364,10 +1527,13 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
&resp, sizeof resp))
ret = -EFAULT;
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+out_put:
+ put_qp_read(qp);
+out:
while (wr) {
+ if (is_ud && wr->wr.ud.ah)
+ put_ah_read(wr->wr.ud.ah);
next = wr->next;
kfree(wr);
wr = next;
@@ -1482,14 +1648,15 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
if (IS_ERR(wr))
return PTR_ERR(wr);
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext)
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp)
goto out;
resp.bad_wr = 0;
ret = qp->device->post_recv(qp, wr, &bad_wr);
+
+ put_qp_read(qp);
+
if (ret)
for (next = wr; next; next = next->next) {
++resp.bad_wr;
@@ -1503,8 +1670,6 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
ret = -EFAULT;
out:
- mutex_unlock(&ib_uverbs_idr_mutex);
-
while (wr) {
next = wr->next;
kfree(wr);
@@ -1533,14 +1698,15 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
if (IS_ERR(wr))
return PTR_ERR(wr);
- mutex_lock(&ib_uverbs_idr_mutex);
-
- srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
- if (!srq || srq->uobject->context != file->ucontext)
+ srq = idr_read_srq(cmd.srq_handle, file->ucontext);
+ if (!srq)
goto out;
resp.bad_wr = 0;
ret = srq->device->post_srq_recv(srq, wr, &bad_wr);
+
+ put_srq_read(srq);
+
if (ret)
for (next = wr; next; next = next->next) {
++resp.bad_wr;
@@ -1554,8 +1720,6 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
ret = -EFAULT;
out:
- mutex_unlock(&ib_uverbs_idr_mutex);
-
while (wr) {
next = wr->next;
kfree(wr);
@@ -1587,17 +1751,15 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- mutex_lock(&ib_uverbs_idr_mutex);
+ init_uobj(uobj, cmd.user_handle, file->ucontext);
+ down_write(&uobj->mutex);
- pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
- if (!pd || pd->uobject->context != file->ucontext) {
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ if (!pd) {
ret = -EINVAL;
- goto err_up;
+ goto err;
}
- uobj->user_handle = cmd.user_handle;
- uobj->context = file->ucontext;
-
attr.dlid = cmd.attr.dlid;
attr.sl = cmd.attr.sl;
attr.src_path_bits = cmd.attr.src_path_bits;
@@ -1613,21 +1775,13 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
ah = ib_create_ah(pd, &attr);
if (IS_ERR(ah)) {
ret = PTR_ERR(ah);
- goto err_up;
- }
-
- ah->uobject = uobj;
-
-retry:
- if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_destroy;
+ goto err;
}
- ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id);
+ ah->uobject = uobj;
+ uobj->object = ah;
- if (ret == -EAGAIN)
- goto retry;
+ ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj);
if (ret)
goto err_destroy;
@@ -1636,27 +1790,29 @@ retry:
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
+ put_pd_read(pd);
+
mutex_lock(&file->mutex);
list_add_tail(&uobj->list, &file->ucontext->ah_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ uobj->live = 1;
+
+ up_write(&uobj->mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_ah_idr, uobj->id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
err_destroy:
ib_destroy_ah(ah);
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
-
- kfree(uobj);
+err:
+ put_uobj_write(uobj);
return ret;
}
@@ -1666,35 +1822,34 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
struct ib_uverbs_destroy_ah cmd;
struct ib_ah *ah;
struct ib_uobject *uobj;
- int ret = -EINVAL;
+ int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
+ uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
+ ah = uobj->object;
- ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle);
- if (!ah || ah->uobject->context != file->ucontext)
- goto out;
+ ret = ib_destroy_ah(ah);
+ if (!ret)
+ uobj->live = 0;
- uobj = ah->uobject;
+ put_uobj_write(uobj);
- ret = ib_destroy_ah(ah);
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle);
+ idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
mutex_lock(&file->mutex);
list_del(&uobj->list);
mutex_unlock(&file->mutex);
- kfree(uobj);
+ put_uobj(uobj);
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
-
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
@@ -1703,47 +1858,43 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
{
struct ib_uverbs_attach_mcast cmd;
struct ib_qp *qp;
- struct ib_uqp_object *uobj;
+ struct ib_uqp_object *obj;
struct ib_uverbs_mcast_entry *mcast;
- int ret = -EINVAL;
+ int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext)
- goto out;
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp)
+ return -EINVAL;
- uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
+ obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
- list_for_each_entry(mcast, &uobj->mcast_list, list)
+ list_for_each_entry(mcast, &obj->mcast_list, list)
if (cmd.mlid == mcast->lid &&
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
ret = 0;
- goto out;
+ goto out_put;
}
mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
if (!mcast) {
ret = -ENOMEM;
- goto out;
+ goto out_put;
}
mcast->lid = cmd.mlid;
memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
- if (!ret) {
- uobj = container_of(qp->uobject, struct ib_uqp_object,
- uevent.uobject);
- list_add_tail(&mcast->list, &uobj->mcast_list);
- } else
+ if (!ret)
+ list_add_tail(&mcast->list, &obj->mcast_list);
+ else
kfree(mcast);
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+out_put:
+ put_qp_read(qp);
return ret ? ret : in_len;
}
@@ -1753,7 +1904,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
int out_len)
{
struct ib_uverbs_detach_mcast cmd;
- struct ib_uqp_object *uobj;
+ struct ib_uqp_object *obj;
struct ib_qp *qp;
struct ib_uverbs_mcast_entry *mcast;
int ret = -EINVAL;
@@ -1761,19 +1912,17 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
- if (!qp || qp->uobject->context != file->ucontext)
- goto out;
+ qp = idr_read_qp(cmd.qp_handle, file->ucontext);
+ if (!qp)
+ return -EINVAL;
ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
if (ret)
- goto out;
+ goto out_put;
- uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
+ obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
- list_for_each_entry(mcast, &uobj->mcast_list, list)
+ list_for_each_entry(mcast, &obj->mcast_list, list)
if (cmd.mlid == mcast->lid &&
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
list_del(&mcast->list);
@@ -1781,8 +1930,8 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
break;
}
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+out_put:
+ put_qp_read(qp);
return ret ? ret : in_len;
}
@@ -1794,7 +1943,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
struct ib_uverbs_create_srq cmd;
struct ib_uverbs_create_srq_resp resp;
struct ib_udata udata;
- struct ib_uevent_object *uobj;
+ struct ib_uevent_object *obj;
struct ib_pd *pd;
struct ib_srq *srq;
struct ib_srq_init_attr attr;
@@ -1810,17 +1959,17 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
- uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
- if (!uobj)
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
return -ENOMEM;
- mutex_lock(&ib_uverbs_idr_mutex);
+ init_uobj(&obj->uobject, 0, file->ucontext);
+ down_write(&obj->uobject.mutex);
- pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
-
- if (!pd || pd->uobject->context != file->ucontext) {
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ if (!pd) {
ret = -EINVAL;
- goto err_up;
+ goto err;
}
attr.event_handler = ib_uverbs_srq_event_handler;
@@ -1829,69 +1978,59 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
attr.attr.max_sge = cmd.max_sge;
attr.attr.srq_limit = cmd.srq_limit;
- uobj->uobject.user_handle = cmd.user_handle;
- uobj->uobject.context = file->ucontext;
- uobj->events_reported = 0;
- INIT_LIST_HEAD(&uobj->event_list);
+ obj->events_reported = 0;
+ INIT_LIST_HEAD(&obj->event_list);
srq = pd->device->create_srq(pd, &attr, &udata);
if (IS_ERR(srq)) {
ret = PTR_ERR(srq);
- goto err_up;
+ goto err;
}
srq->device = pd->device;
srq->pd = pd;
- srq->uobject = &uobj->uobject;
+ srq->uobject = &obj->uobject;
srq->event_handler = attr.event_handler;
srq->srq_context = attr.srq_context;
atomic_inc(&pd->usecnt);
atomic_set(&srq->usecnt, 0);
- memset(&resp, 0, sizeof resp);
-
-retry:
- if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_destroy;
- }
-
- ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id);
-
- if (ret == -EAGAIN)
- goto retry;
+ obj->uobject.object = srq;
+ ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject);
if (ret)
goto err_destroy;
- resp.srq_handle = uobj->uobject.id;
+ memset(&resp, 0, sizeof resp);
+ resp.srq_handle = obj->uobject.id;
resp.max_wr = attr.attr.max_wr;
resp.max_sge = attr.attr.max_sge;
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
- goto err_idr;
+ goto err_copy;
}
+ put_pd_read(pd);
+
mutex_lock(&file->mutex);
- list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list);
+ list_add_tail(&obj->uobject.list, &file->ucontext->srq_list);
mutex_unlock(&file->mutex);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ obj->uobject.live = 1;
+
+ up_write(&obj->uobject.mutex);
return in_len;
-err_idr:
- idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id);
+err_copy:
+ idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject);
err_destroy:
ib_destroy_srq(srq);
- atomic_dec(&pd->usecnt);
-
-err_up:
- mutex_unlock(&ib_uverbs_idr_mutex);
- kfree(uobj);
+err:
+ put_uobj_write(&obj->uobject);
return ret;
}
@@ -1907,21 +2046,16 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
- if (!srq || srq->uobject->context != file->ucontext) {
- ret = -EINVAL;
- goto out;
- }
+ srq = idr_read_srq(cmd.srq_handle, file->ucontext);
+ if (!srq)
+ return -EINVAL;
attr.max_wr = cmd.max_wr;
attr.srq_limit = cmd.srq_limit;
ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
+ put_srq_read(srq);
return ret ? ret : in_len;
}
@@ -1942,18 +2076,16 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
+ srq = idr_read_srq(cmd.srq_handle, file->ucontext);
+ if (!srq)
+ return -EINVAL;
- srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
- if (srq && srq->uobject->context == file->ucontext)
- ret = ib_query_srq(srq, &attr);
- else
- ret = -EINVAL;
+ ret = ib_query_srq(srq, &attr);
- mutex_unlock(&ib_uverbs_idr_mutex);
+ put_srq_read(srq);
if (ret)
- goto out;
+ return ret;
memset(&resp, 0, sizeof resp);
@@ -1963,10 +2095,9 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
- ret = -EFAULT;
+ return -EFAULT;
-out:
- return ret ? ret : in_len;
+ return in_len;
}
ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
@@ -1975,45 +2106,45 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
{
struct ib_uverbs_destroy_srq cmd;
struct ib_uverbs_destroy_srq_resp resp;
+ struct ib_uobject *uobj;
struct ib_srq *srq;
- struct ib_uevent_object *uobj;
+ struct ib_uevent_object *obj;
int ret = -EINVAL;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- mutex_lock(&ib_uverbs_idr_mutex);
-
- memset(&resp, 0, sizeof resp);
+ uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext);
+ if (!uobj)
+ return -EINVAL;
+ srq = uobj->object;
+ obj = container_of(uobj, struct ib_uevent_object, uobject);
- srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
- if (!srq || srq->uobject->context != file->ucontext)
- goto out;
+ ret = ib_destroy_srq(srq);
+ if (!ret)
+ uobj->live = 0;
- uobj = container_of(srq->uobject, struct ib_uevent_object, uobject);
+ put_uobj_write(uobj);
- ret = ib_destroy_srq(srq);
if (ret)
- goto out;
+ return ret;
- idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
+ idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
mutex_lock(&file->mutex);
- list_del(&uobj->uobject.list);
+ list_del(&uobj->list);
mutex_unlock(&file->mutex);
- ib_uverbs_release_uevent(file, uobj);
+ ib_uverbs_release_uevent(file, obj);
- resp.events_reported = uobj->events_reported;
+ memset(&resp, 0, sizeof resp);
+ resp.events_reported = obj->events_reported;
- kfree(uobj);
+ put_uobj(uobj);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
ret = -EFAULT;
-out:
- mutex_unlock(&ib_uverbs_idr_mutex);
-
return ret ? ret : in_len;
}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index ff092a0a94da..5ec2d49e9bb6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -66,7 +66,7 @@ enum {
static struct class *uverbs_class;
-DEFINE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_SPINLOCK(ib_uverbs_idr_lock);
DEFINE_IDR(ib_uverbs_pd_idr);
DEFINE_IDR(ib_uverbs_mr_idr);
DEFINE_IDR(ib_uverbs_mw_idr);
@@ -183,21 +183,21 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
if (!context)
return 0;
- mutex_lock(&ib_uverbs_idr_mutex);
-
list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
- struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id);
- idr_remove(&ib_uverbs_ah_idr, uobj->id);
+ struct ib_ah *ah = uobj->object;
+
+ idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
ib_destroy_ah(ah);
list_del(&uobj->list);
kfree(uobj);
}
list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
- struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id);
+ struct ib_qp *qp = uobj->object;
struct ib_uqp_object *uqp =
container_of(uobj, struct ib_uqp_object, uevent.uobject);
- idr_remove(&ib_uverbs_qp_idr, uobj->id);
+
+ idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
ib_uverbs_detach_umcast(qp, uqp);
ib_destroy_qp(qp);
list_del(&uobj->list);
@@ -206,11 +206,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
}
list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
- struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id);
+ struct ib_cq *cq = uobj->object;
struct ib_uverbs_event_file *ev_file = cq->cq_context;
struct ib_ucq_object *ucq =
container_of(uobj, struct ib_ucq_object, uobject);
- idr_remove(&ib_uverbs_cq_idr, uobj->id);
+
+ idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
ib_destroy_cq(cq);
list_del(&uobj->list);
ib_uverbs_release_ucq(file, ev_file, ucq);
@@ -218,10 +219,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
}
list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
- struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id);
+ struct ib_srq *srq = uobj->object;
struct ib_uevent_object *uevent =
container_of(uobj, struct ib_uevent_object, uobject);
- idr_remove(&ib_uverbs_srq_idr, uobj->id);
+
+ idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
ib_destroy_srq(srq);
list_del(&uobj->list);
ib_uverbs_release_uevent(file, uevent);
@@ -231,11 +233,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
/* XXX Free MWs */
list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
- struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id);
+ struct ib_mr *mr = uobj->object;
struct ib_device *mrdev = mr->device;
struct ib_umem_object *memobj;
- idr_remove(&ib_uverbs_mr_idr, uobj->id);
+ idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
ib_dereg_mr(mr);
memobj = container_of(uobj, struct ib_umem_object, uobject);
@@ -246,15 +248,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
}
list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
- struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id);
- idr_remove(&ib_uverbs_pd_idr, uobj->id);
+ struct ib_pd *pd = uobj->object;
+
+ idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
ib_dealloc_pd(pd);
list_del(&uobj->list);
kfree(uobj);
}
- mutex_unlock(&ib_uverbs_idr_mutex);
-
return context->device->dealloc_ucontext(context);
}
diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c
new file mode 100644
index 000000000000..ce46b13ae02b
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_marshall.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <rdma/ib_marshall.h>
+
+static void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
+ struct ib_ah_attr *src)
+{
+ memcpy(dst->grh.dgid, src->grh.dgid.raw, sizeof src->grh.dgid);
+ dst->grh.flow_label = src->grh.flow_label;
+ dst->grh.sgid_index = src->grh.sgid_index;
+ dst->grh.hop_limit = src->grh.hop_limit;
+ dst->grh.traffic_class = src->grh.traffic_class;
+ dst->dlid = src->dlid;
+ dst->sl = src->sl;
+ dst->src_path_bits = src->src_path_bits;
+ dst->static_rate = src->static_rate;
+ dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0;
+ dst->port_num = src->port_num;
+}
+
+void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
+ struct ib_qp_attr *src)
+{
+ dst->cur_qp_state = src->cur_qp_state;
+ dst->path_mtu = src->path_mtu;
+ dst->path_mig_state = src->path_mig_state;
+ dst->qkey = src->qkey;
+ dst->rq_psn = src->rq_psn;
+ dst->sq_psn = src->sq_psn;
+ dst->dest_qp_num = src->dest_qp_num;
+ dst->qp_access_flags = src->qp_access_flags;
+
+ dst->max_send_wr = src->cap.max_send_wr;
+ dst->max_recv_wr = src->cap.max_recv_wr;
+ dst->max_send_sge = src->cap.max_send_sge;
+ dst->max_recv_sge = src->cap.max_recv_sge;
+ dst->max_inline_data = src->cap.max_inline_data;
+
+ ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr);
+ ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr);
+
+ dst->pkey_index = src->pkey_index;
+ dst->alt_pkey_index = src->alt_pkey_index;
+ dst->en_sqd_async_notify = src->en_sqd_async_notify;
+ dst->sq_draining = src->sq_draining;
+ dst->max_rd_atomic = src->max_rd_atomic;
+ dst->max_dest_rd_atomic = src->max_dest_rd_atomic;
+ dst->min_rnr_timer = src->min_rnr_timer;
+ dst->port_num = src->port_num;
+ dst->timeout = src->timeout;
+ dst->retry_cnt = src->retry_cnt;
+ dst->rnr_retry = src->rnr_retry;
+ dst->alt_port_num = src->alt_port_num;
+ dst->alt_timeout = src->alt_timeout;
+}
+EXPORT_SYMBOL(ib_copy_qp_attr_to_user);
+
+void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst,
+ struct ib_sa_path_rec *src)
+{
+ memcpy(dst->dgid, src->dgid.raw, sizeof src->dgid);
+ memcpy(dst->sgid, src->sgid.raw, sizeof src->sgid);
+
+ dst->dlid = src->dlid;
+ dst->slid = src->slid;
+ dst->raw_traffic = src->raw_traffic;
+ dst->flow_label = src->flow_label;
+ dst->hop_limit = src->hop_limit;
+ dst->traffic_class = src->traffic_class;
+ dst->reversible = src->reversible;
+ dst->numb_path = src->numb_path;
+ dst->pkey = src->pkey;
+ dst->sl = src->sl;
+ dst->mtu_selector = src->mtu_selector;
+ dst->mtu = src->mtu;
+ dst->rate_selector = src->rate_selector;
+ dst->rate = src->rate;
+ dst->packet_life_time = src->packet_life_time;
+ dst->preference = src->preference;
+ dst->packet_life_time_selector = src->packet_life_time_selector;
+}
+EXPORT_SYMBOL(ib_copy_path_rec_to_user);
+
+void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
+ struct ib_user_path_rec *src)
+{
+ memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid);
+ memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid);
+
+ dst->dlid = src->dlid;
+ dst->slid = src->slid;
+ dst->raw_traffic = src->raw_traffic;
+ dst->flow_label = src->flow_label;
+ dst->hop_limit = src->hop_limit;
+ dst->traffic_class = src->traffic_class;
+ dst->reversible = src->reversible;
+ dst->numb_path = src->numb_path;
+ dst->pkey = src->pkey;
+ dst->sl = src->sl;
+ dst->mtu_selector = src->mtu_selector;
+ dst->mtu = src->mtu;
+ dst->rate_selector = src->rate_selector;
+ dst->rate = src->rate;
+ dst->packet_life_time = src->packet_life_time;
+ dst->preference = src->preference;
+ dst->packet_life_time_selector = src->packet_life_time_selector;
+}
+EXPORT_SYMBOL(ib_copy_path_rec_from_user);
diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c
index 36a32c315668..efe147dbeb42 100644
--- a/drivers/infiniband/core/uverbs_mem.c
+++ b/drivers/infiniband/core/uverbs_mem.c
@@ -211,8 +211,10 @@ void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem)
*/
work = kmalloc(sizeof *work, GFP_KERNEL);
- if (!work)
+ if (!work) {
+ mmput(mm);
return;
+ }
INIT_WORK(&work->work, ib_umem_account, work);
work->mm = mm;
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index b78e7dc69330..468999c38803 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -125,35 +125,47 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
}
EXPORT_SYMBOL(ib_create_ah);
-struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
- struct ib_grh *grh, u8 port_num)
+int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
+ struct ib_grh *grh, struct ib_ah_attr *ah_attr)
{
- struct ib_ah_attr ah_attr;
u32 flow_class;
u16 gid_index;
int ret;
- memset(&ah_attr, 0, sizeof ah_attr);
- ah_attr.dlid = wc->slid;
- ah_attr.sl = wc->sl;
- ah_attr.src_path_bits = wc->dlid_path_bits;
- ah_attr.port_num = port_num;
+ memset(ah_attr, 0, sizeof *ah_attr);
+ ah_attr->dlid = wc->slid;
+ ah_attr->sl = wc->sl;
+ ah_attr->src_path_bits = wc->dlid_path_bits;
+ ah_attr->port_num = port_num;
if (wc->wc_flags & IB_WC_GRH) {
- ah_attr.ah_flags = IB_AH_GRH;
- ah_attr.grh.dgid = grh->sgid;
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.dgid = grh->sgid;
- ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num,
+ ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
&gid_index);
if (ret)
- return ERR_PTR(ret);
+ return ret;
- ah_attr.grh.sgid_index = (u8) gid_index;
+ ah_attr->grh.sgid_index = (u8) gid_index;
flow_class = be32_to_cpu(grh->version_tclass_flow);
- ah_attr.grh.flow_label = flow_class & 0xFFFFF;
- ah_attr.grh.traffic_class = (flow_class >> 20) & 0xFF;
- ah_attr.grh.hop_limit = grh->hop_limit;
+ ah_attr->grh.flow_label = flow_class & 0xFFFFF;
+ ah_attr->grh.hop_limit = grh->hop_limit;
+ ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
}
+ return 0;
+}
+EXPORT_SYMBOL(ib_init_ah_from_wc);
+
+struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
+ struct ib_grh *grh, u8 port_num)
+{
+ struct ib_ah_attr ah_attr;
+ int ret;
+
+ ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
+ if (ret)
+ return ERR_PTR(ret);
return ib_create_ah(pd, &ah_attr);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
index 593e28969c69..46762387f5f8 100644
--- a/drivers/infiniband/hw/ipath/ipath_debug.h
+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
@@ -60,11 +60,11 @@
#define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */
#define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */
#define __IPATH_SMADBG 0x8000 /* sma packet debug */
-#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) general debug on */
-#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings on */
-#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors on */
-#define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump on */
-#define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump on */
+#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */
+#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */
+#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */
+#define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump */
+#define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump */
#else /* _IPATH_DEBUGGING */
@@ -79,11 +79,12 @@
#define __IPATH_TRSAMPLE 0x0 /* generate trace buffer sample entries */
#define __IPATH_VERBDBG 0x0 /* very verbose debug */
#define __IPATH_PKTDBG 0x0 /* print packet data */
-#define __IPATH_PROCDBG 0x0 /* print process startup (init)/exit messages */
+#define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */
/* print mmap/nopage stuff, not using VDBG any more */
#define __IPATH_MMDBG 0x0
#define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */
-#define __IPATH_SMADBG 0x0 /* print process startup (init)/exit messages */#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */
+#define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */
+#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */
#define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */
#define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */
#define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 7d3fb6996b41..28ddceb260e8 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -277,13 +277,14 @@ static int ipath_diag_open(struct inode *in, struct file *fp)
bail:
spin_unlock_irqrestore(&ipath_devs_lock, flags);
- mutex_unlock(&ipath_mutex);
/* Only expose a way to reset the device if we
make it into diag mode. */
if (ret == 0)
ipath_expose_reset(&dd->pcidev->dev);
+ mutex_unlock(&ipath_mutex);
+
return ret;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index e7617c3982ea..dddcdae736ac 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -116,10 +116,9 @@ static int __devinit ipath_init_one(struct pci_dev *,
#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
static const struct pci_device_id ipath_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE,
- PCI_DEVICE_ID_INFINIPATH_HT)},
- {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE,
- PCI_DEVICE_ID_INFINIPATH_PE800)},
+ { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, ipath_pci_tbl);
@@ -418,9 +417,19 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (ret) {
- dev_info(&pdev->dev, "pci_set_dma_mask unit %u "
- "fails: %d\n", dd->ipath_unit, ret);
- goto bail_regions;
+ /*
+ * if the 64 bit setup fails, try 32 bit. Some systems
+ * do not setup 64 bit maps on systems with 2GB or less
+ * memory installed.
+ */
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (ret) {
+ dev_info(&pdev->dev, "pci_set_dma_mask unit %u "
+ "fails: %d\n", dd->ipath_unit, ret);
+ goto bail_regions;
+ }
+ else
+ ipath_dbg("No 64bit DMA mask, used 32 bit mask\n");
}
pci_set_master(pdev);
@@ -1896,19 +1905,19 @@ static void __exit infinipath_cleanup(void)
} else
ipath_dbg("irq is 0, not doing free_irq "
"for unit %u\n", dd->ipath_unit);
- dd->pcidev = NULL;
- }
- /*
- * we check for NULL here, because it's outside the kregbase
- * check, and we need to call it after the free_irq. Thus
- * it's possible that the function pointers were never
- * initialized.
- */
- if (dd->ipath_f_cleanup)
- /* clean up chip-specific stuff */
- dd->ipath_f_cleanup(dd);
+ /*
+ * we check for NULL here, because it's outside
+ * the kregbase check, and we need to call it
+ * after the free_irq. Thus it's possible that
+ * the function pointers were never initialized.
+ */
+ if (dd->ipath_f_cleanup)
+ /* clean up chip-specific stuff */
+ dd->ipath_f_cleanup(dd);
+ dd->pcidev = NULL;
+ }
spin_lock_irqsave(&ipath_devs_lock, flags);
}
@@ -1949,7 +1958,7 @@ int ipath_reset_device(int unit)
}
if (dd->ipath_pd)
- for (i = 1; i < dd->ipath_portcnt; i++) {
+ for (i = 1; i < dd->ipath_cfgports; i++) {
if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) {
ipath_dbg("unit %u port %d is in use "
"(PID %u cmd %s), can't reset\n",
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index f11a900e8cd7..a2f1ceafcca9 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -505,11 +505,10 @@ static u8 flash_csum(struct ipath_flash *ifp, int adjust)
* ipath_get_guid - get the GUID from the i2c device
* @dd: the infinipath device
*
- * When we add the multi-chip support, we will probably have to add
- * the ability to use the number of guids field, and get the guid from
- * the first chip's flash, to use for all of them.
+ * We have the capability to use the ipath_nguid field, and get
+ * the guid from the first chip's flash, to use for all of them.
*/
-void ipath_get_guid(struct ipath_devdata *dd)
+void ipath_get_eeprom_info(struct ipath_devdata *dd)
{
void *buf;
struct ipath_flash *ifp;
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index c347191f02bf..ada267e41f6c 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -139,7 +139,7 @@ static int ipath_get_base_info(struct ipath_portdata *pd,
kinfo->spi_piosize = dd->ipath_ibmaxlen;
kinfo->spi_mtu = dd->ipath_ibmaxlen; /* maxlen, not ibmtu */
kinfo->spi_port = pd->port_port;
- kinfo->spi_sw_version = IPATH_USER_SWVERSION;
+ kinfo->spi_sw_version = IPATH_KERN_SWVERSION;
kinfo->spi_hw_version = dd->ipath_revision;
if (copy_to_user(ubase, kinfo, sizeof(*kinfo)))
@@ -1224,6 +1224,10 @@ static unsigned int ipath_poll(struct file *fp,
if (tail == head) {
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
+ if(dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
+ (void)ipath_write_ureg(dd, ur_rcvhdrhead,
+ dd->ipath_rhdrhead_intr_off
+ | head, pd->port_port);
poll_wait(fp, &pd->port_wait, pt);
if (test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
diff --git a/drivers/infiniband/hw/ipath/ipath_ht400.c b/drivers/infiniband/hw/ipath/ipath_ht400.c
index 4652435998f3..fac0a2b74de2 100644
--- a/drivers/infiniband/hw/ipath/ipath_ht400.c
+++ b/drivers/infiniband/hw/ipath/ipath_ht400.c
@@ -607,7 +607,12 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
case 4: /* Ponderosa is one of the bringup boards */
n = "Ponderosa";
break;
- case 5: /* HT-460 original production board */
+ case 5:
+ /*
+ * HT-460 original production board; two production levels, with
+ * different serial number ranges. See ipath_ht_early_init() for
+ * case where we enable IPATH_GPIO_INTR for later serial # range.
+ */
n = "InfiniPath_HT-460";
break;
case 6:
@@ -642,7 +647,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
if (n)
snprintf(name, namelen, "%s", n);
- if (dd->ipath_majrev != 3 || dd->ipath_minrev != 2) {
+ if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
/*
* This version of the driver only supports the HT-400
* Rev 3.2
@@ -1520,6 +1525,18 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
INFINIPATH_S_ABORT);
+
+ ipath_get_eeprom_info(dd);
+ if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
+ dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
+ /*
+ * Later production HT-460 has same changes as HT-465, so
+ * can use GPIO interrupts. They have serial #'s starting
+ * with 128, rather than 112.
+ */
+ dd->ipath_flags |= IPATH_GPIO_INTR;
+ dd->ipath_flags &= ~IPATH_POLL_RX_INTR;
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 2823ff9c0c62..dc83250d26a6 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -53,13 +53,19 @@ MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
/*
* Number of buffers reserved for driver (layered drivers and SMA
- * send). Reserved at end of buffer list.
+ * send). Reserved at end of buffer list. Initialized based on
+ * number of PIO buffers if not set via module interface.
+ * The problem with this is that it's global, but we'll use different
+ * numbers for different chip types. So the default value is not
+ * very useful. I've redefined it for the 1.3 release so that it's
+ * zero unless set by the user to something else, in which case we
+ * try to respect it.
*/
-static ushort ipath_kpiobufs = 32;
+static ushort ipath_kpiobufs;
static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp);
-module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_uint,
+module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_ushort,
&ipath_kpiobufs, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver");
@@ -531,8 +537,11 @@ static int init_housekeeping(struct ipath_devdata *dd,
* Don't clear ipath_flags as 8bit mode was set before
* entering this func. However, we do set the linkstate to
* unknown, so we can watch for a transition.
+ * PRESENT is set because we want register reads to work,
+ * and the kernel infrastructure saw it in config space;
+ * We clear it if we have failures.
*/
- dd->ipath_flags |= IPATH_LINKUNK;
+ dd->ipath_flags |= IPATH_LINKUNK | IPATH_PRESENT;
dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED |
IPATH_LINKDOWN | IPATH_LINKINIT);
@@ -560,6 +569,7 @@ static int init_housekeeping(struct ipath_devdata *dd,
|| (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) {
ipath_dev_err(dd, "Register read failures from chip, "
"giving up initialization\n");
+ dd->ipath_flags &= ~IPATH_PRESENT;
ret = -ENODEV;
goto done;
}
@@ -682,16 +692,14 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
*/
dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2)
/ (sizeof(u64) * BITS_PER_BYTE / 2);
- if (!ipath_kpiobufs) /* have to have at least 1, for SMA */
- kpiobufs = ipath_kpiobufs = 1;
- else if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) <
- (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT)) {
- dev_info(&dd->pcidev->dev, "Too few PIO buffers (%u) "
- "for %u ports to have %u each!\n",
- dd->ipath_piobcnt2k + dd->ipath_piobcnt4k,
- dd->ipath_cfgports, IPATH_MIN_USER_PORT_BUFCNT);
- kpiobufs = 1; /* reserve just the minimum for SMA/ether */
- } else
+ if (ipath_kpiobufs == 0) {
+ /* not set by user, or set explictly to default */
+ if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128)
+ kpiobufs = 32;
+ else
+ kpiobufs = 16;
+ }
+ else
kpiobufs = ipath_kpiobufs;
if (kpiobufs >
@@ -871,7 +879,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
done:
if (!ret) {
- ipath_get_guid(dd);
*dd->ipath_statusp |= IPATH_STATUS_CHIP_PRESENT;
if (!dd->ipath_f_intrsetup(dd)) {
/* now we can enable all interrupts from the chip */
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 0bcb428041f3..3e72a1fe3d73 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -665,14 +665,14 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE);
if (ret > 0)
- goto clear;
+ goto set;
ret = __ipath_verbs_piobufavail(dd);
if (ret > 0)
- goto clear;
+ goto set;
return;
-clear:
+set:
set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
@@ -719,11 +719,24 @@ static void handle_rcv(struct ipath_devdata *dd, u32 istat)
irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
{
struct ipath_devdata *dd = data;
- u32 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
+ u32 istat;
ipath_err_t estat = 0;
static unsigned unexpected = 0;
irqreturn_t ret;
+ if(!(dd->ipath_flags & IPATH_PRESENT)) {
+ /* this is mostly so we don't try to touch the chip while
+ * it is being reset */
+ /*
+ * This return value is perhaps odd, but we do not want the
+ * interrupt core code to remove our interrupt handler
+ * because we don't appear to be handling an interrupt
+ * during a chip reset.
+ */
+ return IRQ_HANDLED;
+ }
+
+ istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
if (unlikely(!istat)) {
ipath_stats.sps_nullintr++;
ret = IRQ_NONE; /* not our interrupt, or already handled */
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 0ce5f19c9d62..5d92d57b6f54 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -650,7 +650,7 @@ u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
void ipath_init_pe800_funcs(struct ipath_devdata *);
/* init HT-400-specific func */
void ipath_init_ht400_funcs(struct ipath_devdata *);
-void ipath_get_guid(struct ipath_devdata *);
+void ipath_get_eeprom_info(struct ipath_devdata *);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
/*
@@ -731,7 +731,7 @@ u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg,
static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
ipath_ureg regno, int port)
{
- if (!dd->ipath_kregbase)
+ if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
return 0;
return readl(regno + (u64 __iomem *)
@@ -762,7 +762,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd,
ipath_kreg regno)
{
- if (!dd->ipath_kregbase)
+ if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
return -1;
return readl((u32 __iomem *) & dd->ipath_kregbase[regno]);
}
@@ -770,7 +770,7 @@ static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd,
static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd,
ipath_kreg regno)
{
- if (!dd->ipath_kregbase)
+ if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
return -1;
return readq(&dd->ipath_kregbase[regno]);
@@ -786,7 +786,7 @@ static inline void ipath_write_kreg(const struct ipath_devdata *dd,
static inline u64 ipath_read_creg(const struct ipath_devdata *dd,
ipath_sreg regno)
{
- if (!dd->ipath_kregbase)
+ if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
return 0;
return readq(regno + (u64 __iomem *)
@@ -797,7 +797,7 @@ static inline u64 ipath_read_creg(const struct ipath_devdata *dd,
static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
ipath_sreg regno)
{
- if (!dd->ipath_kregbase)
+ if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
return 0;
return readl(regno + (u64 __iomem *)
(dd->ipath_cregbase +
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index aa33b0e9f2f6..5ae8761f9dd2 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -136,9 +136,7 @@ int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
ret = 1;
goto bail;
}
- spin_lock(&rkt->lock);
mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
- spin_unlock(&rkt->lock);
if (unlikely(mr == NULL || mr->lkey != sge->lkey)) {
ret = 0;
goto bail;
@@ -184,8 +182,6 @@ bail:
* @acc: access flags
*
* Return 1 if successful, otherwise 0.
- *
- * The QP r_rq.lock should be held.
*/
int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
u32 len, u64 vaddr, u32 rkey, int acc)
@@ -196,9 +192,7 @@ int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
size_t off;
int ret;
- spin_lock(&rkt->lock);
mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
- spin_unlock(&rkt->lock);
if (unlikely(mr == NULL || mr->lkey != rkey)) {
ret = 0;
goto bail;
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
index 69ed1100701a..9ec4ac77b87f 100644
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ b/drivers/infiniband/hw/ipath/ipath_layer.c
@@ -46,13 +46,15 @@
/* Acquire before ipath_devs_lock. */
static DEFINE_MUTEX(ipath_layer_mutex);
+static int ipath_verbs_registered;
+
u16 ipath_layer_rcv_opcode;
+
static int (*layer_intr)(void *, u32);
static int (*layer_rcv)(void *, void *, struct sk_buff *);
static int (*layer_rcv_lid)(void *, void *);
static int (*verbs_piobufavail)(void *);
static void (*verbs_rcv)(void *, void *, void *, u32);
-static int ipath_verbs_registered;
static void *(*layer_add_one)(int, struct ipath_devdata *);
static void (*layer_remove_one)(void *);
@@ -586,6 +588,8 @@ void ipath_verbs_unregister(void)
verbs_rcv = NULL;
verbs_timer_cb = NULL;
+ ipath_verbs_registered = 0;
+
mutex_unlock(&ipath_layer_mutex);
}
@@ -868,12 +872,13 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
update_sge(ss, len);
length -= len;
}
+ /* Update address before sending packet. */
+ update_sge(ss, length);
/* must flush early everything before trigger word */
ipath_flush_wc();
__raw_writel(last, piobuf);
/* be sure trigger word is written */
ipath_flush_wc();
- update_sge(ss, length);
}
/**
@@ -939,17 +944,18 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
!((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
u32 w;
+ u32 *addr = (u32 *) ss->sge.vaddr;
+ /* Update address before sending packet. */
+ update_sge(ss, len);
/* Need to round up for the last dword in the packet. */
w = (len + 3) >> 2;
- __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
+ __iowrite32_copy(piobuf, addr, w - 1);
/* must flush early everything before trigger word */
ipath_flush_wc();
- __raw_writel(((u32 *) ss->sge.vaddr)[w - 1],
- piobuf + w - 1);
+ __raw_writel(addr[w - 1], piobuf + w - 1);
/* be sure trigger word is written */
ipath_flush_wc();
- update_sge(ss, len);
ret = 0;
goto bail;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index f7f8391fe43f..1a9d0a2c33c3 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -137,47 +137,11 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp,
return reply(smp);
}
-struct port_info {
- __be64 mkey;
- __be64 gid_prefix;
- __be16 lid;
- __be16 sm_lid;
- __be32 cap_mask;
- __be16 diag_code;
- __be16 mkey_lease_period;
- u8 local_port_num;
- u8 link_width_enabled;
- u8 link_width_supported;
- u8 link_width_active;
- u8 linkspeed_portstate; /* 4 bits, 4 bits */
- u8 portphysstate_linkdown; /* 4 bits, 4 bits */
- u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */
- u8 linkspeedactive_enabled; /* 4 bits, 4 bits */
- u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */
- u8 vlcap_inittype; /* 4 bits, 4 bits */
- u8 vl_high_limit;
- u8 vl_arb_high_cap;
- u8 vl_arb_low_cap;
- u8 inittypereply_mtucap; /* 4 bits, 4 bits */
- u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */
- u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */
- __be16 mkey_violations;
- __be16 pkey_violations;
- __be16 qkey_violations;
- u8 guid_cap;
- u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */
- u8 resv_resptimevalue; /* 3 bits, 5 bits */
- u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */
- __be16 max_credit_hint;
- u8 resv;
- u8 link_roundtrip_latency[3];
-} __attribute__ ((packed));
-
static int recv_subn_get_portinfo(struct ib_smp *smp,
struct ib_device *ibdev, u8 port)
{
struct ipath_ibdev *dev;
- struct port_info *pip = (struct port_info *)smp->data;
+ struct ib_port_info *pip = (struct ib_port_info *)smp->data;
u16 lid;
u8 ibcstat;
u8 mtu;
@@ -312,7 +276,7 @@ static int recv_subn_set_guidinfo(struct ib_smp *smp,
static int recv_subn_set_portinfo(struct ib_smp *smp,
struct ib_device *ibdev, u8 port)
{
- struct port_info *pip = (struct port_info *)smp->data;
+ struct ib_port_info *pip = (struct ib_port_info *)smp->data;
struct ib_event event;
struct ipath_ibdev *dev;
u32 flags;
@@ -445,7 +409,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
if (pip->clientrereg_resv_subnetto & 0x80) {
clientrereg = 1;
- event.event = IB_EVENT_LID_CHANGE;
+ event.event = IB_EVENT_CLIENT_REREGISTER;
ib_dispatch_event(&event);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_pe800.c
index e1dc4f757062..02e8c75b24f6 100644
--- a/drivers/infiniband/hw/ipath/ipath_pe800.c
+++ b/drivers/infiniband/hw/ipath/ipath_pe800.c
@@ -972,6 +972,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd)
/* Use ERROR so it shows up in logs, etc. */
ipath_dev_err(dd, "Resetting PE-800 unit %u\n",
dd->ipath_unit);
+ /* keep chip from being accessed in a few places */
+ dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);
val = dd->ipath_control | INFINIPATH_C_RESET;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);
mb();
@@ -997,6 +999,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd)
if ((r = pci_enable_device(dd->pcidev)))
ipath_dev_err(dd, "pci_enable_device failed after "
"reset: %d\n", r);
+ /* whether it worked or not, mark as present, again */
+ dd->ipath_flags |= IPATH_PRESENT;
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
if (val == dd->ipath_revision) {
ipath_cdbg(VERBOSE, "Got matching revision "
@@ -1176,6 +1180,8 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
*/
dd->ipath_rhdrhead_intr_off = 1ULL<<32;
+ ipath_get_eeprom_info(dd);
+
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 18890716db1e..9f8855d970c8 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -375,10 +375,10 @@ static void ipath_error_qp(struct ipath_qp *qp)
spin_lock(&dev->pending_lock);
/* XXX What if its already removed by the timeout code? */
- if (qp->timerwait.next != LIST_POISON1)
- list_del(&qp->timerwait);
- if (qp->piowait.next != LIST_POISON1)
- list_del(&qp->piowait);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
wc.status = IB_WC_WR_FLUSH_ERR;
@@ -427,6 +427,7 @@ static void ipath_error_qp(struct ipath_qp *qp)
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask)
{
+ struct ipath_ibdev *dev = to_idev(ibqp->device);
struct ipath_qp *qp = to_iqp(ibqp);
enum ib_qp_state cur_state, new_state;
unsigned long flags;
@@ -443,6 +444,19 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr_mask))
goto inval;
+ if (attr_mask & IB_QP_AV)
+ if (attr->ah_attr.dlid == 0 ||
+ attr->ah_attr.dlid >= IPS_MULTICAST_LID_BASE)
+ goto inval;
+
+ if (attr_mask & IB_QP_PKEY_INDEX)
+ if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd))
+ goto inval;
+
+ if (attr_mask & IB_QP_MIN_RNR_TIMER)
+ if (attr->min_rnr_timer > 31)
+ goto inval;
+
switch (new_state) {
case IB_QPS_RESET:
ipath_reset_qp(qp);
@@ -457,13 +471,8 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
- if (attr_mask & IB_QP_PKEY_INDEX) {
- struct ipath_ibdev *dev = to_idev(ibqp->device);
-
- if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd))
- goto inval;
+ if (attr_mask & IB_QP_PKEY_INDEX)
qp->s_pkey_index = attr->pkey_index;
- }
if (attr_mask & IB_QP_DEST_QPN)
qp->remote_qpn = attr->dest_qp_num;
@@ -479,12 +488,8 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (attr_mask & IB_QP_ACCESS_FLAGS)
qp->qp_access_flags = attr->qp_access_flags;
- if (attr_mask & IB_QP_AV) {
- if (attr->ah_attr.dlid == 0 ||
- attr->ah_attr.dlid >= IPS_MULTICAST_LID_BASE)
- goto inval;
+ if (attr_mask & IB_QP_AV)
qp->remote_ah_attr = attr->ah_attr;
- }
if (attr_mask & IB_QP_PATH_MTU)
qp->path_mtu = attr->path_mtu;
@@ -499,11 +504,8 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->s_rnr_retry_cnt = qp->s_rnr_retry;
}
- if (attr_mask & IB_QP_MIN_RNR_TIMER) {
- if (attr->min_rnr_timer > 31)
- goto inval;
+ if (attr_mask & IB_QP_MIN_RNR_TIMER)
qp->s_min_rnr_timer = attr->min_rnr_timer;
- }
if (attr_mask & IB_QP_QKEY)
qp->qkey = attr->qkey;
@@ -710,10 +712,8 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
init_attr->qp_type == IB_QPT_RC ?
ipath_do_rc_send : ipath_do_uc_send,
(unsigned long)qp);
- qp->piowait.next = LIST_POISON1;
- qp->piowait.prev = LIST_POISON2;
- qp->timerwait.next = LIST_POISON1;
- qp->timerwait.prev = LIST_POISON2;
+ INIT_LIST_HEAD(&qp->piowait);
+ INIT_LIST_HEAD(&qp->timerwait);
qp->state = IB_QPS_RESET;
qp->s_wq = swq;
qp->s_size = init_attr->cap.max_send_wr + 1;
@@ -734,7 +734,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
ipath_reset_qp(qp);
/* Tell the core driver that the kernel SMA is present. */
- if (qp->ibqp.qp_type == IB_QPT_SMI)
+ if (init_attr->qp_type == IB_QPT_SMI)
ipath_layer_set_verbs_flags(dev->dd,
IPATH_VERBS_KERNEL_SMA);
break;
@@ -783,10 +783,10 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
/* Make sure the QP isn't on the timeout list. */
spin_lock_irqsave(&dev->pending_lock, flags);
- if (qp->timerwait.next != LIST_POISON1)
- list_del(&qp->timerwait);
- if (qp->piowait.next != LIST_POISON1)
- list_del(&qp->piowait);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
spin_unlock_irqrestore(&dev->pending_lock, flags);
/*
@@ -855,10 +855,10 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
spin_lock(&dev->pending_lock);
/* XXX What if its already removed by the timeout code? */
- if (qp->timerwait.next != LIST_POISON1)
- list_del(&qp->timerwait);
- if (qp->piowait.next != LIST_POISON1)
- list_del(&qp->piowait);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1);
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index a4055ca00614..493b1821a934 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -57,7 +57,7 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
qp->s_len = wqe->length - len;
dev = to_idev(qp->ibqp.device);
spin_lock(&dev->pending_lock);
- if (qp->timerwait.next == LIST_POISON1)
+ if (list_empty(&qp->timerwait))
list_add_tail(&qp->timerwait,
&dev->pending[dev->pending_index]);
spin_unlock(&dev->pending_lock);
@@ -356,7 +356,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
qp->s_next_psn = qp->s_psn;
spin_lock(&dev->pending_lock);
- if (qp->timerwait.next == LIST_POISON1)
+ if (list_empty(&qp->timerwait))
list_add_tail(&qp->timerwait,
&dev->pending[dev->pending_index]);
spin_unlock(&dev->pending_lock);
@@ -726,8 +726,8 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
*/
dev = to_idev(qp->ibqp.device);
spin_lock(&dev->pending_lock);
- if (qp->timerwait.next != LIST_POISON1)
- list_del(&qp->timerwait);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
spin_unlock(&dev->pending_lock);
if (wqe->wr.opcode == IB_WR_RDMA_READ)
@@ -886,8 +886,8 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* just won't find anything to restart if we ACK everything.
*/
spin_lock(&dev->pending_lock);
- if (qp->timerwait.next != LIST_POISON1)
- list_del(&qp->timerwait);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
spin_unlock(&dev->pending_lock);
/*
@@ -1194,8 +1194,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
IB_WR_RDMA_READ))
goto ack_done;
spin_lock(&dev->pending_lock);
- if (qp->s_rnr_timeout == 0 &&
- qp->timerwait.next != LIST_POISON1)
+ if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
list_move_tail(&qp->timerwait,
&dev->pending[dev->pending_index]);
spin_unlock(&dev->pending_lock);
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index 1e59750c5f63..402126eb79c9 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -34,8 +34,9 @@
#define _IPATH_REGISTERS_H
/*
- * This file should only be included by kernel source, and by the diags.
- * It defines the registers, and their contents, for the InfiniPath HT-400 chip
+ * This file should only be included by kernel source, and by the diags. It
+ * defines the registers, and their contents, for the InfiniPath HT-400
+ * chip.
*/
/*
@@ -156,8 +157,10 @@
#define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8
#define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL
#define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1
-#define INFINIPATH_IBCC_LINKINITCMD_POLL 2 /* cycle through TS1/TS2 till OK */
-#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 /* wait for TS1, then go on */
+/* cycle through TS1/TS2 till OK */
+#define INFINIPATH_IBCC_LINKINITCMD_POLL 2
+/* wait for TS1, then go on */
+#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3
#define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16
#define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL
#define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */
@@ -182,7 +185,8 @@
#define INFINIPATH_IBCS_LINKSTATE_SHIFT 4
#define INFINIPATH_IBCS_TXREADY 0x40000000
#define INFINIPATH_IBCS_TXCREDITOK 0x80000000
-/* link training states (shift by INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */
+/* link training states (shift by
+ INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */
#define INFINIPATH_IBCS_LT_STATE_DISABLED 0x00
#define INFINIPATH_IBCS_LT_STATE_LINKUP 0x01
#define INFINIPATH_IBCS_LT_STATE_POLLACTIVE 0x02
@@ -267,10 +271,12 @@
/* kr_serdesconfig0 bits */
#define INFINIPATH_SERDC0_RESET_MASK 0xfULL /* overal reset bits */
#define INFINIPATH_SERDC0_RESET_PLL 0x10000000ULL /* pll reset */
-#define INFINIPATH_SERDC0_TXIDLE 0xF000ULL /* tx idle enables (per lane) */
-#define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL /* rx detect enables (per lane) */
-#define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL /* L1 Power down; use with RXDETECT,
- Otherwise not used on IB side */
+/* tx idle enables (per lane) */
+#define INFINIPATH_SERDC0_TXIDLE 0xF000ULL
+/* rx detect enables (per lane) */
+#define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL
+/* L1 Power down; use with RXDETECT, Otherwise not used on IB side */
+#define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL
/* kr_xgxsconfig bits */
#define INFINIPATH_XGXS_RESET 0x7ULL
@@ -390,12 +396,13 @@ struct ipath_kregs {
ipath_kreg kr_txintmemsize;
ipath_kreg kr_xgxsconfig;
ipath_kreg kr_ibpllcfg;
- /* use these two (and the following N ports) only with ipath_k*_kreg64_port();
- * not *kreg64() */
+ /* use these two (and the following N ports) only with
+ * ipath_k*_kreg64_port(); not *kreg64() */
ipath_kreg kr_rcvhdraddr;
ipath_kreg kr_rcvhdrtailaddr;
- /* remaining registers are not present on all types of infinipath chips */
+ /* remaining registers are not present on all types of infinipath
+ chips */
ipath_kreg kr_rcvpktledcnt;
ipath_kreg kr_pcierbuftestreg0;
ipath_kreg kr_pcierbuftestreg1;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index f232e77b78ee..d38f4f3cfd1d 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -435,7 +435,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
unsigned long flags;
spin_lock_irqsave(&dev->pending_lock, flags);
- if (qp->piowait.next == LIST_POISON1)
+ if (list_empty(&qp->piowait))
list_add_tail(&qp->piowait, &dev->piowait);
spin_unlock_irqrestore(&dev->pending_lock, flags);
/*
@@ -531,19 +531,12 @@ int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
}
wqe->wr.num_sge = j;
qp->s_head = next;
- /*
- * Wake up the send tasklet if the QP is not waiting
- * for an RNR timeout.
- */
- next = qp->s_rnr_timeout;
spin_unlock_irqrestore(&qp->s_lock, flags);
- if (next == 0) {
- if (qp->ibqp.qp_type == IB_QPT_UC)
- ipath_do_uc_send((unsigned long) qp);
- else
- ipath_do_rc_send((unsigned long) qp);
- }
+ if (qp->ibqp.qp_type == IB_QPT_UC)
+ ipath_do_uc_send((unsigned long) qp);
+ else
+ ipath_do_rc_send((unsigned long) qp);
ret = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 32acd8048b49..f323791cc495 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -711,10 +711,22 @@ static struct attribute_group dev_attr_group = {
* enters diag mode. A device reset is quite likely to crash the
* machine entirely, so we don't want to normally make it
* available.
+ *
+ * Called with ipath_mutex held.
*/
int ipath_expose_reset(struct device *dev)
{
- return device_create_file(dev, &dev_attr_reset);
+ static int exposed;
+ int ret;
+
+ if (!exposed) {
+ ret = device_create_file(dev, &dev_attr_reset);
+ exposed = 1;
+ }
+ else
+ ret = 0;
+
+ return ret;
}
int ipath_driver_create_group(struct device_driver *drv)
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 01cfb30ee160..e606daf83210 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -46,8 +46,10 @@
* This is called from ipath_post_ud_send() to forward a WQE addressed
* to the same HCA.
*/
-static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_sge_state *ss,
- u32 length, struct ib_send_wr *wr, struct ib_wc *wc)
+static void ipath_ud_loopback(struct ipath_qp *sqp,
+ struct ipath_sge_state *ss,
+ u32 length, struct ib_send_wr *wr,
+ struct ib_wc *wc)
{
struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
struct ipath_qp *qp;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 8d2558a01f35..28fdbdaa789d 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -449,7 +449,6 @@ static void ipath_ib_timer(void *arg)
{
struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
struct ipath_qp *resend = NULL;
- struct ipath_qp *rnr = NULL;
struct list_head *last;
struct ipath_qp *qp;
unsigned long flags;
@@ -465,32 +464,18 @@ static void ipath_ib_timer(void *arg)
last = &dev->pending[dev->pending_index];
while (!list_empty(last)) {
qp = list_entry(last->next, struct ipath_qp, timerwait);
- if (last->next == LIST_POISON1 ||
- last->next != &qp->timerwait ||
- qp->timerwait.prev != last) {
- INIT_LIST_HEAD(last);
- } else {
- list_del(&qp->timerwait);
- qp->timerwait.prev = (struct list_head *) resend;
- resend = qp;
- atomic_inc(&qp->refcount);
- }
+ list_del_init(&qp->timerwait);
+ qp->timer_next = resend;
+ resend = qp;
+ atomic_inc(&qp->refcount);
}
last = &dev->rnrwait;
if (!list_empty(last)) {
qp = list_entry(last->next, struct ipath_qp, timerwait);
if (--qp->s_rnr_timeout == 0) {
do {
- if (last->next == LIST_POISON1 ||
- last->next != &qp->timerwait ||
- qp->timerwait.prev != last) {
- INIT_LIST_HEAD(last);
- break;
- }
- list_del(&qp->timerwait);
- qp->timerwait.prev =
- (struct list_head *) rnr;
- rnr = qp;
+ list_del_init(&qp->timerwait);
+ tasklet_hi_schedule(&qp->s_task);
if (list_empty(last))
break;
qp = list_entry(last->next, struct ipath_qp,
@@ -530,8 +515,7 @@ static void ipath_ib_timer(void *arg)
spin_unlock_irqrestore(&dev->pending_lock, flags);
/* XXX What if timer fires again while this is running? */
- for (qp = resend; qp != NULL;
- qp = (struct ipath_qp *) qp->timerwait.prev) {
+ for (qp = resend; qp != NULL; qp = qp->timer_next) {
struct ib_wc wc;
spin_lock_irqsave(&qp->s_lock, flags);
@@ -545,9 +529,6 @@ static void ipath_ib_timer(void *arg)
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
}
- for (qp = rnr; qp != NULL;
- qp = (struct ipath_qp *) qp->timerwait.prev)
- tasklet_hi_schedule(&qp->s_task);
}
/**
@@ -556,9 +537,9 @@ static void ipath_ib_timer(void *arg)
*
* This is called from ipath_intr() at interrupt level when a PIO buffer is
* available after ipath_verbs_send() returned an error that no buffers were
- * available. Return 0 if we consumed all the PIO buffers and we still have
+ * available. Return 1 if we consumed all the PIO buffers and we still have
* QPs waiting for buffers (for now, just do a tasklet_hi_schedule and
- * return one).
+ * return zero).
*/
static int ipath_ib_piobufavail(void *arg)
{
@@ -573,13 +554,13 @@ static int ipath_ib_piobufavail(void *arg)
while (!list_empty(&dev->piowait)) {
qp = list_entry(dev->piowait.next, struct ipath_qp,
piowait);
- list_del(&qp->piowait);
+ list_del_init(&qp->piowait);
tasklet_hi_schedule(&qp->s_task);
}
spin_unlock_irqrestore(&dev->pending_lock, flags);
bail:
- return 1;
+ return 0;
}
static int ipath_query_device(struct ib_device *ibdev,
@@ -970,6 +951,7 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
idev->dd = dd;
strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX);
+ dev->owner = THIS_MODULE;
dev->node_guid = ipath_layer_get_guid(dd);
dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION;
dev->uverbs_cmd_mask =
@@ -1159,7 +1141,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf)
len = sprintf(buf,
"RC resends %d\n"
- "RC QACKs %d\n"
+ "RC no QACK %d\n"
"RC ACKs %d\n"
"RC SEQ NAKs %d\n"
"RC RDMA seq %d\n"
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index fcafbc7c9e71..4f8d59300e9b 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -282,7 +282,8 @@ struct ipath_srq {
*/
struct ipath_qp {
struct ib_qp ibqp;
- struct ipath_qp *next; /* link list for QPN hash table */
+ struct ipath_qp *next; /* link list for QPN hash table */
+ struct ipath_qp *timer_next; /* link list for ipath_ib_timer() */
struct list_head piowait; /* link for wait PIO buf */
struct list_head timerwait; /* link for waiting for timeouts */
struct ib_ah_attr remote_ah_attr;
diff --git a/drivers/infiniband/hw/ipath/ips_common.h b/drivers/infiniband/hw/ipath/ips_common.h
index 410a764dfcef..ab7cbbbfd03a 100644
--- a/drivers/infiniband/hw/ipath/ips_common.h
+++ b/drivers/infiniband/hw/ipath/ips_common.h
@@ -95,7 +95,7 @@ struct ether_header {
__u8 seq_num;
__le32 len;
/* MUST be of word size due to PIO write requirements */
- __u32 csum;
+ __le32 csum;
__le16 csum_offset;
__le16 flags;
__u16 first_2_bytes;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 1985b5dfa481..d0f7731802c9 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -174,7 +174,6 @@ enum {
struct mthca_cmd_context {
struct completion done;
- struct timer_list timer;
int result;
int next;
u64 out_param;
@@ -182,7 +181,7 @@ struct mthca_cmd_context {
u8 status;
};
-static int fw_cmd_doorbell = 1;
+static int fw_cmd_doorbell = 0;
module_param(fw_cmd_doorbell, int, 0644);
MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
"(and supported by FW)");
@@ -362,15 +361,6 @@ void mthca_cmd_event(struct mthca_dev *dev,
complete(&context->done);
}
-static void event_timeout(unsigned long context_ptr)
-{
- struct mthca_cmd_context *context =
- (struct mthca_cmd_context *) context_ptr;
-
- context->result = -EBUSY;
- complete(&context->done);
-}
-
static int mthca_cmd_wait(struct mthca_dev *dev,
u64 in_param,
u64 *out_param,
@@ -401,11 +391,10 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
if (err)
goto out;
- context->timer.expires = jiffies + timeout;
- add_timer(&context->timer);
-
- wait_for_completion(&context->done);
- del_timer_sync(&context->timer);
+ if (!wait_for_completion_timeout(&context->done, timeout)) {
+ err = -EBUSY;
+ goto out;
+ }
err = context->result;
if (err)
@@ -535,10 +524,6 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
for (i = 0; i < dev->cmd.max_cmds; ++i) {
dev->cmd.context[i].token = i;
dev->cmd.context[i].next = i + 1;
- init_timer(&dev->cmd.context[i].timer);
- dev->cmd.context[i].timer.data =
- (unsigned long) &dev->cmd.context[i];
- dev->cmd.context[i].timer.function = event_timeout;
}
dev->cmd.context[dev->cmd.max_cmds - 1].next = -1;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 312cf90731ea..3e27a084257e 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -238,9 +238,9 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
spin_lock(&dev->cq_table.lock);
cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
-
if (cq)
- atomic_inc(&cq->refcount);
+ ++cq->refcount;
+
spin_unlock(&dev->cq_table.lock);
if (!cq) {
@@ -254,8 +254,10 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
if (cq->ibcq.event_handler)
cq->ibcq.event_handler(&event, cq->ibcq.cq_context);
- if (atomic_dec_and_test(&cq->refcount))
+ spin_lock(&dev->cq_table.lock);
+ if (!--cq->refcount)
wake_up(&cq->wait);
+ spin_unlock(&dev->cq_table.lock);
}
static inline int is_recv_cqe(struct mthca_cqe *cqe)
@@ -267,23 +269,13 @@ static inline int is_recv_cqe(struct mthca_cqe *cqe)
return !(cqe->is_send & 0x80);
}
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn,
struct mthca_srq *srq)
{
- struct mthca_cq *cq;
struct mthca_cqe *cqe;
u32 prod_index;
int nfreed = 0;
- spin_lock_irq(&dev->cq_table.lock);
- cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
- if (cq)
- atomic_inc(&cq->refcount);
- spin_unlock_irq(&dev->cq_table.lock);
-
- if (!cq)
- return;
-
spin_lock_irq(&cq->lock);
/*
@@ -301,7 +293,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
if (0)
mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n",
- qpn, cqn, cq->cons_index, prod_index);
+ qpn, cq->cqn, cq->cons_index, prod_index);
/*
* Now sweep backwards through the CQ, removing CQ entries
@@ -325,8 +317,6 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
}
spin_unlock_irq(&cq->lock);
- if (atomic_dec_and_test(&cq->refcount))
- wake_up(&cq->wait);
}
void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
@@ -550,8 +540,17 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
entry->wr_id = srq->wrid[wqe_index];
mthca_free_srq_wqe(srq, wqe);
} else {
+ s32 wqe;
wq = &(*cur_qp)->rq;
- wqe_index = be32_to_cpu(cqe->wqe) >> wq->wqe_shift;
+ wqe = be32_to_cpu(cqe->wqe);
+ wqe_index = wqe >> wq->wqe_shift;
+ /*
+ * WQE addr == base - 1 might be reported in receive completion
+ * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
+ * Arbel FW 5.1.400. This bug should be fixed in later FW revs.
+ */
+ if (unlikely(wqe_index < 0))
+ wqe_index = wq->max - 1;
entry->wr_id = (*cur_qp)->wrid[wqe_index];
}
@@ -821,8 +820,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
}
spin_lock_init(&cq->lock);
- atomic_set(&cq->refcount, 1);
+ cq->refcount = 1;
init_waitqueue_head(&cq->wait);
+ mutex_init(&cq->mutex);
memset(cq_context, 0, sizeof *cq_context);
cq_context->flags = cpu_to_be32(MTHCA_CQ_STATUS_OK |
@@ -896,6 +896,17 @@ err_out:
return err;
}
+static inline int get_cq_refcount(struct mthca_dev *dev, struct mthca_cq *cq)
+{
+ int c;
+
+ spin_lock_irq(&dev->cq_table.lock);
+ c = cq->refcount;
+ spin_unlock_irq(&dev->cq_table.lock);
+
+ return c;
+}
+
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq)
{
@@ -929,6 +940,7 @@ void mthca_free_cq(struct mthca_dev *dev,
spin_lock_irq(&dev->cq_table.lock);
mthca_array_clear(&dev->cq_table.cq,
cq->cqn & (dev->limits.num_cqs - 1));
+ --cq->refcount;
spin_unlock_irq(&dev->cq_table.lock);
if (dev->mthca_flags & MTHCA_FLAG_MSI_X)
@@ -936,8 +948,7 @@ void mthca_free_cq(struct mthca_dev *dev,
else
synchronize_irq(dev->pdev->irq);
- atomic_dec(&cq->refcount);
- wait_event(cq->wait, !atomic_read(&cq->refcount));
+ wait_event(cq->wait, !get_cq_refcount(dev, cq));
if (cq->is_kernel) {
mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 4c1dcb4c1822..f8160b8de090 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -496,7 +496,7 @@ void mthca_free_cq(struct mthca_dev *dev,
void mthca_cq_completion(struct mthca_dev *dev, u32 cqn);
void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
enum ib_event_type event_type);
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn,
struct mthca_srq *srq);
void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 99f109c3815d..d536217e700e 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -695,10 +695,6 @@ static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset,
static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
{
- unsigned long mthca_base;
-
- mthca_base = pci_resource_start(dev->pdev, 0);
-
if (mthca_is_memfree(dev)) {
/*
* We assume that the EQ arm and EQ set CI registers
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 4730863ece9a..d9bc030bcccc 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -114,14 +114,22 @@ static void smp_snoop(struct ib_device *ibdev,
mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
mad->mad_hdr.method == IB_MGMT_METHOD_SET) {
if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
+ struct ib_port_info *pinfo =
+ (struct ib_port_info *) ((struct ib_smp *) mad)->data;
+
mthca_update_rate(to_mdev(ibdev), port_num);
update_sm_ah(to_mdev(ibdev), port_num,
- be16_to_cpup((__be16 *) (mad->data + 58)),
- (*(u8 *) (mad->data + 76)) & 0xf);
+ be16_to_cpu(pinfo->lid),
+ pinfo->neighbormtu_mastersmsl & 0xf);
event.device = ibdev;
- event.event = IB_EVENT_LID_CHANGE;
event.element.port_num = port_num;
+
+ if(pinfo->clientrereg_resv_subnetto & 0x80)
+ event.event = IB_EVENT_CLIENT_REREGISTER;
+ else
+ event.event = IB_EVENT_LID_CHANGE;
+
ib_dispatch_event(&event);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 25e1c1db9a40..a486dec1707e 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -761,6 +761,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
int __devinit mthca_init_mr_table(struct mthca_dev *dev)
{
+ unsigned long addr;
int err, i;
err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
@@ -796,9 +797,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
goto err_fmr_mpt;
}
+ addr = pci_resource_start(dev->pdev, 4) +
+ ((pci_resource_len(dev->pdev, 4) - 1) &
+ dev->mr_table.mpt_base);
+
dev->mr_table.tavor_fmr.mpt_base =
- ioremap(dev->mr_table.mpt_base,
- (1 << i) * sizeof (struct mthca_mpt_entry));
+ ioremap(addr, (1 << i) * sizeof(struct mthca_mpt_entry));
if (!dev->mr_table.tavor_fmr.mpt_base) {
mthca_warn(dev, "MPT ioremap for FMR failed.\n");
@@ -806,9 +810,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
goto err_fmr_mpt;
}
+ addr = pci_resource_start(dev->pdev, 4) +
+ ((pci_resource_len(dev->pdev, 4) - 1) &
+ dev->mr_table.mtt_base);
+
dev->mr_table.tavor_fmr.mtt_base =
- ioremap(dev->mr_table.mtt_base,
- (1 << i) * MTHCA_MTT_SEG_SIZE);
+ ioremap(addr, (1 << i) * MTHCA_MTT_SEG_SIZE);
if (!dev->mr_table.tavor_fmr.mtt_base) {
mthca_warn(dev, "MTT ioremap for FMR failed.\n");
err = -ENOMEM;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 565a24b1756f..230ae21db8fd 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -115,6 +115,16 @@ static int mthca_query_device(struct ib_device *ibdev,
props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
props->max_mcast_grp;
+ /*
+ * If Sinai memory key optimization is being used, then only
+ * the 8-bit key portion will change. For other HCAs, the
+ * unused index bits will also be used for FMR remapping.
+ */
+ if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+ props->max_map_per_fmr = 255;
+ else
+ props->max_map_per_fmr =
+ (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1;
err = 0;
out:
@@ -306,7 +316,7 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port,
goto out;
}
- memcpy(gid->raw + 8, out_mad->data + (index % 8) * 16, 8);
+ memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
out:
kfree(in_mad);
@@ -783,18 +793,24 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda
if (entries < 1 || entries > dev->limits.max_cqes)
return -EINVAL;
+ mutex_lock(&cq->mutex);
+
entries = roundup_pow_of_two(entries + 1);
- if (entries == ibcq->cqe + 1)
- return 0;
+ if (entries == ibcq->cqe + 1) {
+ ret = 0;
+ goto out;
+ }
if (cq->is_kernel) {
ret = mthca_alloc_resize_buf(dev, cq, entries);
if (ret)
- return ret;
+ goto out;
lkey = cq->resize_buf->buf.mr.ibmr.lkey;
} else {
- if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
- return -EFAULT;
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+ ret = -EFAULT;
+ goto out;
+ }
lkey = ucmd.lkey;
}
@@ -811,7 +827,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda
cq->resize_buf = NULL;
spin_unlock_irq(&cq->lock);
}
- return ret;
+ goto out;
}
if (cq->is_kernel) {
@@ -838,7 +854,10 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda
} else
ibcq->cqe = entries - 1;
- return 0;
+out:
+ mutex_unlock(&cq->mutex);
+
+ return ret;
}
static int mthca_destroy_cq(struct ib_cq *cq)
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 6676a786d690..8de2887ba15c 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -139,11 +139,12 @@ struct mthca_ah {
* a qp may be locked, with the send cq locked first. No other
* nesting should be done.
*
- * Each struct mthca_cq/qp also has an atomic_t ref count. The
- * pointer from the cq/qp_table to the struct counts as one reference.
- * This reference also is good for access through the consumer API, so
- * modifying the CQ/QP etc doesn't need to take another reference.
- * Access because of a completion being polled does need a reference.
+ * Each struct mthca_cq/qp also has an ref count, protected by the
+ * corresponding table lock. The pointer from the cq/qp_table to the
+ * struct counts as one reference. This reference also is good for
+ * access through the consumer API, so modifying the CQ/QP etc doesn't
+ * need to take another reference. Access to a QP because of a
+ * completion being polled does not need a reference either.
*
* Finally, each struct mthca_cq/qp has a wait_queue_head_t for the
* destroy function to sleep on.
@@ -159,8 +160,9 @@ struct mthca_ah {
* - decrement ref count; if zero, wake up waiters
*
* To destroy a CQ/QP, we can do the following:
- * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock
- * - decrement ref count
+ * - lock cq/qp_table
+ * - remove pointer and decrement ref count
+ * - unlock cq/qp_table lock
* - wait_event until ref count is zero
*
* It is the consumer's responsibilty to make sure that no QP
@@ -197,7 +199,7 @@ struct mthca_cq_resize {
struct mthca_cq {
struct ib_cq ibcq;
spinlock_t lock;
- atomic_t refcount;
+ int refcount;
int cqn;
u32 cons_index;
struct mthca_cq_buf buf;
@@ -212,12 +214,13 @@ struct mthca_cq {
int arm_sn;
wait_queue_head_t wait;
+ struct mutex mutex;
};
struct mthca_srq {
struct ib_srq ibsrq;
spinlock_t lock;
- atomic_t refcount;
+ int refcount;
int srqn;
int max;
int max_gs;
@@ -235,6 +238,7 @@ struct mthca_srq {
struct mthca_mr mr;
wait_queue_head_t wait;
+ struct mutex mutex;
};
struct mthca_wq {
@@ -254,7 +258,7 @@ struct mthca_wq {
struct mthca_qp {
struct ib_qp ibqp;
- atomic_t refcount;
+ int refcount;
u32 qpn;
int is_direct;
u8 port; /* for SQP and memfree use only */
@@ -276,6 +280,7 @@ struct mthca_qp {
union mthca_buf queue;
wait_queue_head_t wait;
+ struct mutex mutex;
};
struct mthca_sqp {
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index f37b0e367323..16c387d8170c 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -240,7 +240,7 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
spin_lock(&dev->qp_table.lock);
qp = mthca_array_get(&dev->qp_table.qp, qpn & (dev->limits.num_qps - 1));
if (qp)
- atomic_inc(&qp->refcount);
+ ++qp->refcount;
spin_unlock(&dev->qp_table.lock);
if (!qp) {
@@ -257,8 +257,10 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
if (qp->ibqp.event_handler)
qp->ibqp.event_handler(&event, qp->ibqp.qp_context);
- if (atomic_dec_and_test(&qp->refcount))
+ spin_lock(&dev->qp_table.lock);
+ if (!--qp->refcount)
wake_up(&qp->wait);
+ spin_unlock(&dev->qp_table.lock);
}
static int to_mthca_state(enum ib_qp_state ib_state)
@@ -532,7 +534,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
struct mthca_qp_context *qp_context;
u32 sqd_event = 0;
u8 status;
- int err;
+ int err = -EINVAL;
+
+ mutex_lock(&qp->mutex);
if (attr_mask & IB_QP_CUR_STATE) {
cur_state = attr->cur_qp_state;
@@ -551,39 +555,41 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
"%d->%d with attr 0x%08x\n",
qp->transport, cur_state, new_state,
attr_mask);
- return -EINVAL;
+ goto out;
}
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
attr->pkey_index, dev->limits.pkey_table_len-1);
- return -EINVAL;
+ goto out;
}
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) {
mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num);
- return -EINVAL;
+ goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
attr->max_rd_atomic > dev->limits.max_qp_init_rdma) {
mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n",
attr->max_rd_atomic, dev->limits.max_qp_init_rdma);
- return -EINVAL;
+ goto out;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) {
mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n",
attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift);
- return -EINVAL;
+ goto out;
}
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
+ if (IS_ERR(mailbox)) {
+ err = PTR_ERR(mailbox);
+ goto out;
+ }
qp_param = mailbox->buf;
qp_context = &qp_param->context;
memset(qp_param, 0, sizeof *qp_param);
@@ -616,7 +622,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_2048) {
mthca_dbg(dev, "path MTU (%u) is invalid\n",
attr->path_mtu);
- return -EINVAL;
+ goto out_mailbox;
}
qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31;
}
@@ -670,7 +676,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr_mask & IB_QP_AV) {
if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path,
attr_mask & IB_QP_PORT ? attr->port_num : qp->port))
- return -EINVAL;
+ goto out_mailbox;
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
}
@@ -684,18 +690,18 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr->alt_pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n",
attr->alt_pkey_index, dev->limits.pkey_table_len-1);
- return -EINVAL;
+ goto out_mailbox;
}
if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
attr->alt_port_num);
- return -EINVAL;
+ goto out_mailbox;
}
if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path,
attr->alt_ah_attr.port_num))
- return -EINVAL;
+ goto out_mailbox;
qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
attr->alt_port_num << 24);
@@ -791,12 +797,12 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0,
mailbox, sqd_event, &status);
if (err)
- goto out;
+ goto out_mailbox;
if (status) {
mthca_warn(dev, "modify QP %d->%d returned status %02x.\n",
cur_state, new_state, status);
err = -EINVAL;
- goto out;
+ goto out_mailbox;
}
qp->state = new_state;
@@ -833,10 +839,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
* entries and reinitialize the QP.
*/
if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) {
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
mthca_wq_init(&qp->sq);
@@ -851,8 +857,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
}
-out:
+out_mailbox:
mthca_free_mailbox(dev, mailbox);
+
+out:
+ mutex_unlock(&qp->mutex);
return err;
}
@@ -1096,8 +1105,9 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
int ret;
int i;
- atomic_set(&qp->refcount, 1);
+ qp->refcount = 1;
init_waitqueue_head(&qp->wait);
+ mutex_init(&qp->mutex);
qp->state = IB_QPS_RESET;
qp->atomic_rd_en = 0;
qp->resp_depth = 0;
@@ -1318,6 +1328,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev,
return err;
}
+static inline int get_qp_refcount(struct mthca_dev *dev, struct mthca_qp *qp)
+{
+ int c;
+
+ spin_lock_irq(&dev->qp_table.lock);
+ c = qp->refcount;
+ spin_unlock_irq(&dev->qp_table.lock);
+
+ return c;
+}
+
void mthca_free_qp(struct mthca_dev *dev,
struct mthca_qp *qp)
{
@@ -1339,14 +1360,14 @@ void mthca_free_qp(struct mthca_dev *dev,
spin_lock(&dev->qp_table.lock);
mthca_array_clear(&dev->qp_table.qp,
qp->qpn & (dev->limits.num_qps - 1));
+ --qp->refcount;
spin_unlock(&dev->qp_table.lock);
if (send_cq != recv_cq)
spin_unlock(&recv_cq->lock);
spin_unlock_irq(&send_cq->lock);
- atomic_dec(&qp->refcount);
- wait_event(qp->wait, !atomic_read(&qp->refcount));
+ wait_event(qp->wait, !get_qp_refcount(dev, qp));
if (qp->state != IB_QPS_RESET)
mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0,
@@ -1358,10 +1379,10 @@ void mthca_free_qp(struct mthca_dev *dev,
* unref the mem-free tables and free the QPN in our table.
*/
if (!qp->ibqp.uobject) {
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
mthca_free_memfree(dev, qp);
@@ -1714,23 +1735,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
ind = qp->rq.next_ind;
- for (nreq = 0; wr; ++nreq, wr = wr->next) {
- if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
- nreq = 0;
-
- doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
- doorbell[1] = cpu_to_be32(qp->qpn << 8);
-
- wmb();
-
- mthca_write64(doorbell,
- dev->kar + MTHCA_RECEIVE_DOORBELL,
- MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
-
- qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
- size0 = 0;
- }
-
+ for (nreq = 0; wr; wr = wr->next) {
if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
mthca_err(dev, "RQ %06x full (%u head, %u tail,"
" %d max, %d nreq)\n", qp->qpn,
@@ -1784,6 +1789,23 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
++ind;
if (unlikely(ind >= qp->rq.max))
ind -= qp->rq.max;
+
+ ++nreq;
+ if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
+ nreq = 0;
+
+ doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
+ doorbell[1] = cpu_to_be32(qp->qpn << 8);
+
+ wmb();
+
+ mthca_write64(doorbell,
+ dev->kar + MTHCA_RECEIVE_DOORBELL,
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+
+ qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
+ size0 = 0;
+ }
}
out:
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c
index df5e494a9d38..f4fddd5327f5 100644
--- a/drivers/infiniband/hw/mthca/mthca_reset.c
+++ b/drivers/infiniband/hw/mthca/mthca_reset.c
@@ -49,6 +49,12 @@ int mthca_reset(struct mthca_dev *mdev)
u32 *hca_header = NULL;
u32 *bridge_header = NULL;
struct pci_dev *bridge = NULL;
+ int bridge_pcix_cap = 0;
+ int hca_pcie_cap = 0;
+ int hca_pcix_cap = 0;
+
+ u16 devctl;
+ u16 linkctl;
#define MTHCA_RESET_OFFSET 0xf0010
#define MTHCA_RESET_VALUE swab32(1)
@@ -110,6 +116,9 @@ int mthca_reset(struct mthca_dev *mdev)
}
}
+ hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);
+ hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
+
if (bridge) {
bridge_header = kmalloc(256, GFP_KERNEL);
if (!bridge_header) {
@@ -129,6 +138,13 @@ int mthca_reset(struct mthca_dev *mdev)
goto out;
}
}
+ bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
+ if (!bridge_pcix_cap) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't locate HCA bridge "
+ "PCI-X capability, aborting.\n");
+ goto out;
+ }
}
/* actually hit reset */
@@ -178,6 +194,20 @@ int mthca_reset(struct mthca_dev *mdev)
good:
/* Now restore the PCI headers */
if (bridge) {
+ if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8,
+ bridge_header[(bridge_pcix_cap + 0x8) / 4])) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't restore HCA bridge Upstream "
+ "split transaction control, aborting.\n");
+ goto out;
+ }
+ if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc,
+ bridge_header[(bridge_pcix_cap + 0xc) / 4])) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't restore HCA bridge Downstream "
+ "split transaction control, aborting.\n");
+ goto out;
+ }
/*
* Bridge control register is at 0x3e, so we'll
* naturally restore it last in this loop.
@@ -203,6 +233,35 @@ good:
}
}
+ if (hca_pcix_cap) {
+ if (pci_write_config_dword(mdev->pdev, hca_pcix_cap,
+ hca_header[hca_pcix_cap / 4])) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't restore HCA PCI-X "
+ "command register, aborting.\n");
+ goto out;
+ }
+ }
+
+ if (hca_pcie_cap) {
+ devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4];
+ if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL,
+ devctl)) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't restore HCA PCI Express "
+ "Device Control register, aborting.\n");
+ goto out;
+ }
+ linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4];
+ if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL,
+ linkctl)) {
+ err = -ENODEV;
+ mthca_err(mdev, "Couldn't restore HCA PCI Express "
+ "Link control register, aborting.\n");
+ goto out;
+ }
+ }
+
for (i = 0; i < 16; ++i) {
if (i * 4 == PCI_COMMAND)
continue;
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index adcaf85355ae..fab417c5cf43 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -241,8 +241,9 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
goto err_out_mailbox;
spin_lock_init(&srq->lock);
- atomic_set(&srq->refcount, 1);
+ srq->refcount = 1;
init_waitqueue_head(&srq->wait);
+ mutex_init(&srq->mutex);
if (mthca_is_memfree(dev))
mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf);
@@ -308,6 +309,17 @@ err_out:
return err;
}
+static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq)
+{
+ int c;
+
+ spin_lock_irq(&dev->srq_table.lock);
+ c = srq->refcount;
+ spin_unlock_irq(&dev->srq_table.lock);
+
+ return c;
+}
+
void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
{
struct mthca_mailbox *mailbox;
@@ -329,10 +341,10 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
spin_lock_irq(&dev->srq_table.lock);
mthca_array_clear(&dev->srq_table.srq,
srq->srqn & (dev->limits.num_srqs - 1));
+ --srq->refcount;
spin_unlock_irq(&dev->srq_table.lock);
- atomic_dec(&srq->refcount);
- wait_event(srq->wait, !atomic_read(&srq->refcount));
+ wait_event(srq->wait, !get_srq_refcount(dev, srq));
if (!srq->ibsrq.uobject) {
mthca_free_srq_buf(dev, srq);
@@ -360,7 +372,11 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (attr_mask & IB_SRQ_LIMIT) {
if (attr->srq_limit > srq->max)
return -EINVAL;
+
+ mutex_lock(&srq->mutex);
ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status);
+ mutex_unlock(&srq->mutex);
+
if (ret)
return ret;
if (status)
@@ -414,7 +430,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
spin_lock(&dev->srq_table.lock);
srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1));
if (srq)
- atomic_inc(&srq->refcount);
+ ++srq->refcount;
spin_unlock(&dev->srq_table.lock);
if (!srq) {
@@ -431,8 +447,10 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context);
out:
- if (atomic_dec_and_test(&srq->refcount))
+ spin_lock(&dev->srq_table.lock);
+ if (!--srq->refcount)
wake_up(&srq->wait);
+ spin_unlock(&dev->srq_table.lock);
}
/*
@@ -477,26 +495,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
first_ind = srq->first_free;
- for (nreq = 0; wr; ++nreq, wr = wr->next) {
- if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
- nreq = 0;
-
- doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
- doorbell[1] = cpu_to_be32(srq->srqn << 8);
-
- /*
- * Make sure that descriptors are written
- * before doorbell is rung.
- */
- wmb();
-
- mthca_write64(doorbell,
- dev->kar + MTHCA_RECEIVE_DOORBELL,
- MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
-
- first_ind = srq->first_free;
- }
-
+ for (nreq = 0; wr; wr = wr->next) {
ind = srq->first_free;
if (ind < 0) {
@@ -556,6 +555,26 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
srq->wrid[ind] = wr->wr_id;
srq->first_free = next_ind;
+
+ ++nreq;
+ if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
+ nreq = 0;
+
+ doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
+ doorbell[1] = cpu_to_be32(srq->srqn << 8);
+
+ /*
+ * Make sure that descriptors are written
+ * before doorbell is rung.
+ */
+ wmb();
+
+ mthca_write64(doorbell,
+ dev->kar + MTHCA_RECEIVE_DOORBELL,
+ MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+
+ first_ind = srq->first_free;
+ }
}
if (likely(nreq)) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 12a1e0572ef2..491d2afaf5b4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -272,8 +272,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
void ipoib_dev_cleanup(struct net_device *dev);
void ipoib_mcast_join_task(void *dev_ptr);
-void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
- struct sk_buff *skb);
+void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb);
void ipoib_mcast_restart_task(void *dev_ptr);
int ipoib_mcast_start_thread(struct net_device *dev);
@@ -369,15 +368,26 @@ extern int ipoib_debug_level;
#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */
-#define IPOIB_GID_FMT "%x:%x:%x:%x:%x:%x:%x:%x"
-
-#define IPOIB_GID_ARG(gid) be16_to_cpup((__be16 *) ((gid).raw + 0)), \
- be16_to_cpup((__be16 *) ((gid).raw + 2)), \
- be16_to_cpup((__be16 *) ((gid).raw + 4)), \
- be16_to_cpup((__be16 *) ((gid).raw + 6)), \
- be16_to_cpup((__be16 *) ((gid).raw + 8)), \
- be16_to_cpup((__be16 *) ((gid).raw + 10)), \
- be16_to_cpup((__be16 *) ((gid).raw + 12)), \
- be16_to_cpup((__be16 *) ((gid).raw + 14))
+#define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \
+ "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x"
+
+#define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \
+ ((u8 *)(gid))[1], \
+ ((u8 *)(gid))[2], \
+ ((u8 *)(gid))[3], \
+ ((u8 *)(gid))[4], \
+ ((u8 *)(gid))[5], \
+ ((u8 *)(gid))[6], \
+ ((u8 *)(gid))[7], \
+ ((u8 *)(gid))[8], \
+ ((u8 *)(gid))[9], \
+ ((u8 *)(gid))[10],\
+ ((u8 *)(gid))[11],\
+ ((u8 *)(gid))[12],\
+ ((u8 *)(gid))[13],\
+ ((u8 *)(gid))[14],\
+ ((u8 *)(gid))[15]
+
+#define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw)
#endif /* _IPOIB_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index a54da42849ae..5033666b1481 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -84,15 +84,9 @@ void ipoib_free_ah(struct kref *kref)
unsigned long flags;
- if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
- ipoib_dbg(priv, "Freeing ah %p\n", ah->ah);
- ib_destroy_ah(ah->ah);
- kfree(ah);
- } else {
- spin_lock_irqsave(&priv->lock, flags);
- list_add_tail(&ah->list, &priv->dead_ahs);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ spin_lock_irqsave(&priv->lock, flags);
+ list_add_tail(&ah->list, &priv->dead_ahs);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static int ipoib_ib_post_receive(struct net_device *dev, int id)
@@ -275,6 +269,7 @@ static void ipoib_ib_handle_wc(struct net_device *dev,
spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_tail;
if (netif_queue_stopped(dev) &&
+ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
netif_wake_queue(dev);
spin_unlock_irqrestore(&priv->tx_lock, flags);
@@ -376,19 +371,16 @@ static void __ipoib_reap_ah(struct net_device *dev)
struct ipoib_ah *ah, *tah;
LIST_HEAD(remove_list);
- spin_lock_irq(&priv->lock);
+ spin_lock_irq(&priv->tx_lock);
+ spin_lock(&priv->lock);
list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
list_del(&ah->list);
- list_add_tail(&ah->list, &remove_list);
+ ib_destroy_ah(ah->ah);
+ kfree(ah);
}
- spin_unlock_irq(&priv->lock);
-
- list_for_each_entry_safe(ah, tah, &remove_list, list) {
- ipoib_dbg(priv, "Reaping ah %p\n", ah->ah);
- ib_destroy_ah(ah->ah);
- kfree(ah);
- }
+ spin_unlock(&priv->lock);
+ spin_unlock_irq(&priv->tx_lock);
}
void ipoib_reap_ah(void *dev_ptr)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index cb078a7d0bf5..1c6ea1c682a5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -185,8 +185,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static struct ipoib_path *__path_find(struct net_device *dev,
- union ib_gid *gid)
+static struct ipoib_path *__path_find(struct net_device *dev, void *gid)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct rb_node *n = priv->path_tree.rb_node;
@@ -196,7 +195,7 @@ static struct ipoib_path *__path_find(struct net_device *dev,
while (n) {
path = rb_entry(n, struct ipoib_path, rb_node);
- ret = memcmp(gid->raw, path->pathrec.dgid.raw,
+ ret = memcmp(gid, path->pathrec.dgid.raw,
sizeof (union ib_gid));
if (ret < 0)
@@ -424,8 +423,7 @@ static void path_rec_completion(int status,
}
}
-static struct ipoib_path *path_rec_create(struct net_device *dev,
- union ib_gid *gid)
+static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path;
@@ -440,7 +438,7 @@ static struct ipoib_path *path_rec_create(struct net_device *dev,
INIT_LIST_HEAD(&path->neigh_list);
- memcpy(path->pathrec.dgid.raw, gid->raw, sizeof (union ib_gid));
+ memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
path->pathrec.sgid = priv->local_gid;
path->pathrec.pkey = cpu_to_be16(priv->pkey);
path->pathrec.numb_path = 1;
@@ -498,10 +496,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
*/
spin_lock(&priv->lock);
- path = __path_find(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4));
+ path = __path_find(dev, skb->dst->neighbour->ha + 4);
if (!path) {
- path = path_rec_create(dev,
- (union ib_gid *) (skb->dst->neighbour->ha + 4));
+ path = path_rec_create(dev, skb->dst->neighbour->ha + 4);
if (!path)
goto err_path;
@@ -551,7 +548,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
/* Add in the P_Key for multicasts */
skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
skb->dst->neighbour->ha[9] = priv->pkey & 0xff;
- ipoib_mcast_send(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4), skb);
+ ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb);
}
static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
@@ -566,10 +563,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
*/
spin_lock(&priv->lock);
- path = __path_find(dev, (union ib_gid *) (phdr->hwaddr + 4));
+ path = __path_find(dev, phdr->hwaddr + 4);
if (!path) {
- path = path_rec_create(dev,
- (union ib_gid *) (phdr->hwaddr + 4));
+ path = path_rec_create(dev, phdr->hwaddr + 4);
if (path) {
/* put pseudoheader back on for next time */
skb_push(skb, sizeof *phdr);
@@ -660,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
phdr->hwaddr[9] = priv->pkey & 0xff;
- ipoib_mcast_send(dev, (union ib_gid *) (phdr->hwaddr + 4), skb);
+ ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
} else {
/* unicast GID -- should be ARP or RARP reply */
@@ -671,7 +667,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst ? "neigh" : "dst",
be16_to_cpup((__be16 *) skb->data),
be32_to_cpup((__be32 *) phdr->hwaddr),
- IPOIB_GID_ARG(*(union ib_gid *) (phdr->hwaddr + 4)));
+ IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb);
++priv->stats.tx_dropped;
goto out;
@@ -754,7 +750,7 @@ static void ipoib_neigh_destructor(struct neighbour *n)
ipoib_dbg(priv,
"neigh_destructor for %06x " IPOIB_GID_FMT "\n",
be32_to_cpup((__be32 *) n->ha),
- IPOIB_GID_ARG(*((union ib_gid *) (n->ha + 4))));
+ IPOIB_GID_RAW_ARG(n->ha + 4));
spin_lock_irqsave(&priv->lock, flags);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 1dae4b238252..216471fa01cc 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -154,7 +154,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev,
return mcast;
}
-static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_gid *mgid)
+static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, void *mgid)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct rb_node *n = priv->multicast_tree.rb_node;
@@ -165,7 +165,7 @@ static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_g
mcast = rb_entry(n, struct ipoib_mcast, rb_node);
- ret = memcmp(mgid->raw, mcast->mcmember.mgid.raw,
+ ret = memcmp(mgid, mcast->mcmember.mgid.raw,
sizeof (union ib_gid));
if (ret < 0)
n = n->rb_left;
@@ -694,8 +694,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
return 0;
}
-void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
- struct sk_buff *skb)
+void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_mcast *mcast;
@@ -718,7 +717,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
if (!mcast) {
/* Let's create a new send only group now */
ipoib_dbg_mcast(priv, "setting up send only multicast group for "
- IPOIB_GID_FMT "\n", IPOIB_GID_ARG(*mgid));
+ IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid));
mcast = ipoib_mcast_alloc(dev, 0);
if (!mcast) {
@@ -730,7 +729,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
}
set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags);
- mcast->mcmember.mgid = *mgid;
+ memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid));
__ipoib_mcast_add(dev, mcast);
list_add_tail(&mcast->list, &priv->multicast_list);
}
@@ -821,7 +820,8 @@ void ipoib_mcast_restart_task(void *dev_ptr)
ipoib_mcast_stop_thread(dev, 0);
- spin_lock_irqsave(&dev->xmit_lock, flags);
+ local_irq_save(flags);
+ netif_tx_lock(dev);
spin_lock(&priv->lock);
/*
@@ -896,7 +896,8 @@ void ipoib_mcast_restart_task(void *dev_ptr)
}
spin_unlock(&priv->lock);
- spin_unlock_irqrestore(&dev->xmit_lock, flags);
+ netif_tx_unlock(dev);
+ local_irq_restore(flags);
/* We have to cancel outside of the spinlock */
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 1d49d1643c59..7b717c648f72 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -255,7 +255,8 @@ void ipoib_event(struct ib_event_handler *handler,
record->event == IB_EVENT_PKEY_CHANGE ||
record->event == IB_EVENT_PORT_ACTIVE ||
record->event == IB_EVENT_LID_CHANGE ||
- record->event == IB_EVENT_SM_CHANGE) {
+ record->event == IB_EVENT_SM_CHANGE ||
+ record->event == IB_EVENT_CLIENT_REREGISTER) {
ipoib_dbg(priv, "Port state change event\n");
queue_work(ipoib_workqueue, &priv->flush_task);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 4ca175553f9f..f887780e8093 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -158,10 +158,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
if (priv->pkey == pkey) {
unregister_netdev(priv->dev);
ipoib_dev_cleanup(priv->dev);
-
list_del(&priv->list);
-
- kfree(priv);
+ free_netdev(priv->dev);
ret = 0;
break;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5bb55742ada6..4e22afef7206 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -62,6 +62,13 @@ MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator "
"v" DRV_VERSION " (" DRV_RELDATE ")");
MODULE_LICENSE("Dual BSD/GPL");
+static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE;
+static int srp_max_iu_len;
+
+module_param(srp_sg_tablesize, int, 0444);
+MODULE_PARM_DESC(srp_sg_tablesize,
+ "Max number of gather/scatter entries per I/O (default is 12)");
+
static int topspin_workarounds = 1;
module_param(topspin_workarounds, int, 0444);
@@ -105,7 +112,8 @@ static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
if (!iu->buf)
goto out_free_iu;
- iu->dma = dma_map_single(host->dev->dma_device, iu->buf, size, direction);
+ iu->dma = dma_map_single(host->dev->dev->dma_device,
+ iu->buf, size, direction);
if (dma_mapping_error(iu->dma))
goto out_free_buf;
@@ -127,7 +135,8 @@ static void srp_free_iu(struct srp_host *host, struct srp_iu *iu)
if (!iu)
return;
- dma_unmap_single(host->dev->dma_device, iu->dma, iu->size, iu->direction);
+ dma_unmap_single(host->dev->dev->dma_device,
+ iu->dma, iu->size, iu->direction);
kfree(iu->buf);
kfree(iu);
}
@@ -147,7 +156,7 @@ static int srp_init_qp(struct srp_target_port *target,
if (!attr)
return -ENOMEM;
- ret = ib_find_cached_pkey(target->srp_host->dev,
+ ret = ib_find_cached_pkey(target->srp_host->dev->dev,
target->srp_host->port,
be16_to_cpu(target->path.pkey),
&attr->pkey_index);
@@ -179,7 +188,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
if (!init_attr)
return -ENOMEM;
- target->cq = ib_create_cq(target->srp_host->dev, srp_completion,
+ target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
NULL, target, SRP_CQ_SIZE);
if (IS_ERR(target->cq)) {
ret = PTR_ERR(target->cq);
@@ -198,7 +207,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
init_attr->send_cq = target->cq;
init_attr->recv_cq = target->cq;
- target->qp = ib_create_qp(target->srp_host->pd, init_attr);
+ target->qp = ib_create_qp(target->srp_host->dev->pd, init_attr);
if (IS_ERR(target->qp)) {
ret = PTR_ERR(target->qp);
ib_destroy_cq(target->cq);
@@ -250,7 +259,7 @@ static int srp_lookup_path(struct srp_target_port *target)
init_completion(&target->done);
- target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev,
+ target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev,
target->srp_host->port,
&target->path,
IB_SA_PATH_REC_DGID |
@@ -309,10 +318,32 @@ static int srp_send_req(struct srp_target_port *target)
req->priv.opcode = SRP_LOGIN_REQ;
req->priv.tag = 0;
- req->priv.req_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+ req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len);
req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
SRP_BUF_FORMAT_INDIRECT);
- memcpy(req->priv.initiator_port_id, target->srp_host->initiator_port_id, 16);
+ /*
+ * In the published SRP specification (draft rev. 16a), the
+ * port identifier format is 8 bytes of ID extension followed
+ * by 8 bytes of GUID. Older drafts put the two halves in the
+ * opposite order, so that the GUID comes first.
+ *
+ * Targets conforming to these obsolete drafts can be
+ * recognized by the I/O Class they report.
+ */
+ if (target->io_class == SRP_REV10_IB_IO_CLASS) {
+ memcpy(req->priv.initiator_port_id,
+ target->srp_host->initiator_port_id + 8, 8);
+ memcpy(req->priv.initiator_port_id + 8,
+ target->srp_host->initiator_port_id, 8);
+ memcpy(req->priv.target_port_id, &target->ioc_guid, 8);
+ memcpy(req->priv.target_port_id + 8, &target->id_ext, 8);
+ } else {
+ memcpy(req->priv.initiator_port_id,
+ target->srp_host->initiator_port_id, 16);
+ memcpy(req->priv.target_port_id, &target->id_ext, 8);
+ memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
+ }
+
/*
* Topspin/Cisco SRP targets will reject our login unless we
* zero out the first 8 bytes of our initiator port ID. The
@@ -325,8 +356,6 @@ static int srp_send_req(struct srp_target_port *target)
(unsigned long long) be64_to_cpu(target->ioc_guid));
memset(req->priv.initiator_port_id, 0, 8);
}
- memcpy(req->priv.target_port_id, &target->id_ext, 8);
- memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
status = ib_send_cm_req(target->cm_id, &req->param);
@@ -340,7 +369,10 @@ static void srp_disconnect_target(struct srp_target_port *target)
/* XXX should send SRP_I_LOGOUT request */
init_completion(&target->done);
- ib_send_cm_dreq(target->cm_id, NULL, 0);
+ if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
+ printk(KERN_DEBUG PFX "Sending CM DREQ failed\n");
+ return;
+ }
wait_for_completion(&target->done);
}
@@ -351,22 +383,19 @@ static void srp_remove_work(void *target_ptr)
spin_lock_irq(target->scsi_host->host_lock);
if (target->state != SRP_TARGET_DEAD) {
spin_unlock_irq(target->scsi_host->host_lock);
- scsi_host_put(target->scsi_host);
return;
}
target->state = SRP_TARGET_REMOVED;
spin_unlock_irq(target->scsi_host->host_lock);
- mutex_lock(&target->srp_host->target_mutex);
+ spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
- mutex_unlock(&target->srp_host->target_mutex);
+ spin_unlock(&target->srp_host->target_lock);
scsi_remove_host(target->scsi_host);
ib_destroy_cm_id(target->cm_id);
srp_free_target_ib(target);
scsi_host_put(target->scsi_host);
- /* And another put to really free the target port... */
- scsi_host_put(target->scsi_host);
}
static int srp_connect_target(struct srp_target_port *target)
@@ -409,14 +438,59 @@ static int srp_connect_target(struct srp_target_port *target)
}
}
+static void srp_unmap_data(struct scsi_cmnd *scmnd,
+ struct srp_target_port *target,
+ struct srp_request *req)
+{
+ struct scatterlist *scat;
+ int nents;
+
+ if (!scmnd->request_buffer ||
+ (scmnd->sc_data_direction != DMA_TO_DEVICE &&
+ scmnd->sc_data_direction != DMA_FROM_DEVICE))
+ return;
+
+ if (req->fmr) {
+ ib_fmr_pool_unmap(req->fmr);
+ req->fmr = NULL;
+ }
+
+ /*
+ * This handling of non-SG commands can be killed when the
+ * SCSI midlayer no longer generates non-SG commands.
+ */
+ if (likely(scmnd->use_sg)) {
+ nents = scmnd->use_sg;
+ scat = scmnd->request_buffer;
+ } else {
+ nents = 1;
+ scat = &req->fake_sg;
+ }
+
+ dma_unmap_sg(target->srp_host->dev->dev->dma_device, scat, nents,
+ scmnd->sc_data_direction);
+}
+
+static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
+{
+ srp_unmap_data(req->scmnd, target, req);
+ list_move_tail(&req->list, &target->free_reqs);
+}
+
+static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
+{
+ req->scmnd->result = DID_RESET << 16;
+ req->scmnd->scsi_done(req->scmnd);
+ srp_remove_req(target, req);
+}
+
static int srp_reconnect_target(struct srp_target_port *target)
{
struct ib_cm_id *new_cm_id;
struct ib_qp_attr qp_attr;
- struct srp_request *req;
+ struct srp_request *req, *tmp;
struct ib_wc wc;
int ret;
- int i;
spin_lock_irq(target->scsi_host->host_lock);
if (target->state != SRP_TARGET_LIVE) {
@@ -431,7 +505,7 @@ static int srp_reconnect_target(struct srp_target_port *target)
* Now get a new local CM ID so that we avoid confusing the
* target in case things are really fouled up.
*/
- new_cm_id = ib_create_cm_id(target->srp_host->dev,
+ new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
srp_cm_handler, target);
if (IS_ERR(new_cm_id)) {
ret = PTR_ERR(new_cm_id);
@@ -452,19 +526,12 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->cq, 1, &wc) > 0)
; /* nothing */
- list_for_each_entry(req, &target->req_queue, list) {
- req->scmnd->result = DID_RESET << 16;
- req->scmnd->scsi_done(req->scmnd);
- }
+ list_for_each_entry_safe(req, tmp, &target->req_queue, list)
+ srp_reset_req(target, req);
target->rx_head = 0;
target->tx_head = 0;
target->tx_tail = 0;
- target->req_head = 0;
- for (i = 0; i < SRP_SQ_SIZE - 1; ++i)
- target->req_ring[i].next = i + 1;
- target->req_ring[SRP_SQ_SIZE - 1].next = -1;
- INIT_LIST_HEAD(&target->req_queue);
ret = srp_connect_target(target);
if (ret)
@@ -500,14 +567,79 @@ err:
return ret;
}
+static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
+ int sg_cnt, struct srp_request *req,
+ struct srp_direct_buf *buf)
+{
+ u64 io_addr = 0;
+ u64 *dma_pages;
+ u32 len;
+ int page_cnt;
+ int i, j;
+ int ret;
+
+ if (!dev->fmr_pool)
+ return -ENODEV;
+
+ len = page_cnt = 0;
+ for (i = 0; i < sg_cnt; ++i) {
+ if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
+ if (i > 0)
+ return -EINVAL;
+ else
+ ++page_cnt;
+ }
+ if ((sg_dma_address(&scat[i]) + sg_dma_len(&scat[i])) &
+ ~dev->fmr_page_mask) {
+ if (i < sg_cnt - 1)
+ return -EINVAL;
+ else
+ ++page_cnt;
+ }
+
+ len += sg_dma_len(&scat[i]);
+ }
+
+ page_cnt += len >> dev->fmr_page_shift;
+ if (page_cnt > SRP_FMR_SIZE)
+ return -ENOMEM;
+
+ dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC);
+ if (!dma_pages)
+ return -ENOMEM;
+
+ page_cnt = 0;
+ for (i = 0; i < sg_cnt; ++i)
+ for (j = 0; j < sg_dma_len(&scat[i]); j += dev->fmr_page_size)
+ dma_pages[page_cnt++] =
+ (sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
+
+ req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
+ dma_pages, page_cnt, &io_addr);
+ if (IS_ERR(req->fmr)) {
+ ret = PTR_ERR(req->fmr);
+ goto out;
+ }
+
+ buf->va = cpu_to_be64(sg_dma_address(&scat[0]) & ~dev->fmr_page_mask);
+ buf->key = cpu_to_be32(req->fmr->fmr->rkey);
+ buf->len = cpu_to_be32(len);
+
+ ret = 0;
+
+out:
+ kfree(dma_pages);
+
+ return ret;
+}
+
static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
struct srp_request *req)
{
struct scatterlist *scat;
struct srp_cmd *cmd = req->cmd->buf;
int len, nents, count;
- int i;
- u8 fmt;
+ u8 fmt = SRP_DATA_DESC_DIRECT;
if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
return sizeof (struct srp_cmd);
@@ -532,53 +664,63 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
}
- count = dma_map_sg(target->srp_host->dev->dma_device, scat, nents,
- scmnd->sc_data_direction);
+ count = dma_map_sg(target->srp_host->dev->dev->dma_device,
+ scat, nents, scmnd->sc_data_direction);
+
+ fmt = SRP_DATA_DESC_DIRECT;
+ len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
if (count == 1) {
+ /*
+ * The midlayer only generated a single gather/scatter
+ * entry, or DMA mapping coalesced everything to a
+ * single entry. So a direct descriptor along with
+ * the DMA MR suffices.
+ */
struct srp_direct_buf *buf = (void *) cmd->add_data;
- fmt = SRP_DATA_DESC_DIRECT;
-
buf->va = cpu_to_be64(sg_dma_address(scat));
- buf->key = cpu_to_be32(target->srp_host->mr->rkey);
+ buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
buf->len = cpu_to_be32(sg_dma_len(scat));
-
- len = sizeof (struct srp_cmd) +
- sizeof (struct srp_direct_buf);
- } else {
+ } else if (srp_map_fmr(target->srp_host->dev, scat, count, req,
+ (void *) cmd->add_data)) {
+ /*
+ * FMR mapping failed, and the scatterlist has more
+ * than one entry. Generate an indirect memory
+ * descriptor.
+ */
struct srp_indirect_buf *buf = (void *) cmd->add_data;
u32 datalen = 0;
+ int i;
fmt = SRP_DATA_DESC_INDIRECT;
+ len = sizeof (struct srp_cmd) +
+ sizeof (struct srp_indirect_buf) +
+ count * sizeof (struct srp_direct_buf);
+
+ for (i = 0; i < count; ++i) {
+ buf->desc_list[i].va =
+ cpu_to_be64(sg_dma_address(&scat[i]));
+ buf->desc_list[i].key =
+ cpu_to_be32(target->srp_host->dev->mr->rkey);
+ buf->desc_list[i].len =
+ cpu_to_be32(sg_dma_len(&scat[i]));
+ datalen += sg_dma_len(&scat[i]);
+ }
if (scmnd->sc_data_direction == DMA_TO_DEVICE)
cmd->data_out_desc_cnt = count;
else
cmd->data_in_desc_cnt = count;
- buf->table_desc.va = cpu_to_be64(req->cmd->dma +
- sizeof *cmd +
- sizeof *buf);
+ buf->table_desc.va =
+ cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf);
buf->table_desc.key =
- cpu_to_be32(target->srp_host->mr->rkey);
+ cpu_to_be32(target->srp_host->dev->mr->rkey);
buf->table_desc.len =
cpu_to_be32(count * sizeof (struct srp_direct_buf));
- for (i = 0; i < count; ++i) {
- buf->desc_list[i].va = cpu_to_be64(sg_dma_address(&scat[i]));
- buf->desc_list[i].key =
- cpu_to_be32(target->srp_host->mr->rkey);
- buf->desc_list[i].len = cpu_to_be32(sg_dma_len(&scat[i]));
-
- datalen += sg_dma_len(&scat[i]);
- }
-
buf->len = cpu_to_be32(datalen);
-
- len = sizeof (struct srp_cmd) +
- sizeof (struct srp_indirect_buf) +
- count * sizeof (struct srp_direct_buf);
}
if (scmnd->sc_data_direction == DMA_TO_DEVICE)
@@ -589,42 +731,6 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return len;
}
-static void srp_unmap_data(struct scsi_cmnd *scmnd,
- struct srp_target_port *target,
- struct srp_request *req)
-{
- struct scatterlist *scat;
- int nents;
-
- if (!scmnd->request_buffer ||
- (scmnd->sc_data_direction != DMA_TO_DEVICE &&
- scmnd->sc_data_direction != DMA_FROM_DEVICE))
- return;
-
- /*
- * This handling of non-SG commands can be killed when the
- * SCSI midlayer no longer generates non-SG commands.
- */
- if (likely(scmnd->use_sg)) {
- nents = scmnd->use_sg;
- scat = scmnd->request_buffer;
- } else {
- nents = 1;
- scat = &req->fake_sg;
- }
-
- dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents,
- scmnd->sc_data_direction);
-}
-
-static void srp_remove_req(struct srp_target_port *target, struct srp_request *req,
- int index)
-{
- list_del(&req->list);
- req->next = target->req_head;
- target->req_head = index;
-}
-
static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
{
struct srp_request *req;
@@ -647,7 +753,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
req->tsk_status = rsp->data[3];
complete(&req->done);
} else {
- scmnd = req->scmnd;
+ scmnd = req->scmnd;
if (!scmnd)
printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",
(unsigned long long) rsp->tag);
@@ -665,14 +771,11 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt);
- srp_unmap_data(scmnd, target, req);
-
if (!req->tsk_mgmt) {
- req->scmnd = NULL;
scmnd->host_scribble = (void *) -1L;
scmnd->scsi_done(scmnd);
- srp_remove_req(target, req, rsp->tag & ~SRP_TAG_TSK_MGMT);
+ srp_remove_req(target, req);
} else
req->cmd_done = 1;
}
@@ -694,7 +797,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV];
- dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma,
+ dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
target->max_ti_iu_len, DMA_FROM_DEVICE);
opcode = *(u8 *) iu->buf;
@@ -731,7 +834,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
break;
}
- dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma,
+ dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
target->max_ti_iu_len, DMA_FROM_DEVICE);
}
@@ -775,7 +878,7 @@ static int __srp_post_recv(struct srp_target_port *target)
list.addr = iu->dma;
list.length = iu->size;
- list.lkey = target->srp_host->mr->lkey;
+ list.lkey = target->srp_host->dev->mr->lkey;
wr.next = NULL;
wr.sg_list = &list;
@@ -810,12 +913,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
return NULL;
- if (unlikely(target->req_lim < 1)) {
- if (printk_ratelimit())
- printk(KERN_DEBUG PFX "Target has req_lim %d\n",
- target->req_lim);
- return NULL;
- }
+ if (unlikely(target->req_lim < 1))
+ ++target->zero_req_lim;
return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
}
@@ -833,7 +932,7 @@ static int __srp_post_send(struct srp_target_port *target,
list.addr = iu->dma;
list.length = len;
- list.lkey = target->srp_host->mr->lkey;
+ list.lkey = target->srp_host->dev->mr->lkey;
wr.next = NULL;
wr.wr_id = target->tx_head & SRP_SQ_SIZE;
@@ -859,7 +958,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
struct srp_request *req;
struct srp_iu *iu;
struct srp_cmd *cmd;
- long req_index;
int len;
if (target->state == SRP_TARGET_CONNECTING)
@@ -876,25 +974,23 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
if (!iu)
goto err;
- dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma,
- SRP_MAX_IU_LEN, DMA_TO_DEVICE);
+ dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
+ srp_max_iu_len, DMA_TO_DEVICE);
- req_index = target->req_head;
+ req = list_entry(target->free_reqs.next, struct srp_request, list);
scmnd->scsi_done = done;
scmnd->result = 0;
- scmnd->host_scribble = (void *) req_index;
+ scmnd->host_scribble = (void *) (long) req->index;
cmd = iu->buf;
memset(cmd, 0, sizeof *cmd);
cmd->opcode = SRP_CMD;
cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48);
- cmd->tag = req_index;
+ cmd->tag = req->index;
memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);
- req = &target->req_ring[req_index];
-
req->scmnd = scmnd;
req->cmd = iu;
req->cmd_done = 0;
@@ -911,16 +1007,15 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
goto err_unmap;
}
- dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma,
- SRP_MAX_IU_LEN, DMA_TO_DEVICE);
+ dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
+ srp_max_iu_len, DMA_TO_DEVICE);
if (__srp_post_send(target, iu, len)) {
printk(KERN_ERR PFX "Send failed\n");
goto err_unmap;
}
- target->req_head = req->next;
- list_add_tail(&req->list, &target->req_queue);
+ list_move_tail(&req->list, &target->req_queue);
return 0;
@@ -945,7 +1040,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
target->tx_ring[i] = srp_alloc_iu(target->srp_host,
- SRP_MAX_IU_LEN,
+ srp_max_iu_len,
GFP_KERNEL, DMA_TO_DEVICE);
if (!target->tx_ring[i])
goto err;
@@ -1116,11 +1211,10 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
srp_cm_rej_handler(cm_id, event, target);
break;
- case IB_CM_MRA_RECEIVED:
- printk(KERN_ERR PFX "MRA received\n");
- break;
-
- case IB_CM_DREP_RECEIVED:
+ case IB_CM_DREQ_RECEIVED:
+ printk(KERN_WARNING PFX "DREQ received - connection closed\n");
+ if (ib_send_cm_drep(cm_id, NULL, 0))
+ printk(KERN_ERR PFX "Sending CM DREP failed\n");
break;
case IB_CM_TIMEWAIT_EXIT:
@@ -1130,6 +1224,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
target->status = 0;
break;
+ case IB_CM_MRA_RECEIVED:
+ case IB_CM_DREQ_ERROR:
+ case IB_CM_DREP_RECEIVED:
+ break;
+
default:
printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
break;
@@ -1143,30 +1242,20 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
return 0;
}
-static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func)
+static int srp_send_tsk_mgmt(struct srp_target_port *target,
+ struct srp_request *req, u8 func)
{
- struct srp_target_port *target = host_to_target(scmnd->device->host);
- struct srp_request *req;
struct srp_iu *iu;
struct srp_tsk_mgmt *tsk_mgmt;
- int req_index;
- int ret = FAILED;
spin_lock_irq(target->scsi_host->host_lock);
if (target->state == SRP_TARGET_DEAD ||
target->state == SRP_TARGET_REMOVED) {
- scmnd->result = DID_BAD_TARGET << 16;
+ req->scmnd->result = DID_BAD_TARGET << 16;
goto out;
}
- if (scmnd->host_scribble == (void *) -1L)
- goto out;
-
- req_index = (long) scmnd->host_scribble;
- printk(KERN_ERR "Abort for req_index %d\n", req_index);
-
- req = &target->req_ring[req_index];
init_completion(&req->done);
iu = __srp_get_tx_iu(target);
@@ -1177,10 +1266,10 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func)
memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
tsk_mgmt->opcode = SRP_TSK_MGMT;
- tsk_mgmt->lun = cpu_to_be64((u64) scmnd->device->lun << 48);
- tsk_mgmt->tag = req_index | SRP_TAG_TSK_MGMT;
+ tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48);
+ tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT;
tsk_mgmt->tsk_mgmt_func = func;
- tsk_mgmt->task_tag = req_index;
+ tsk_mgmt->task_tag = req->index;
if (__srp_post_send(target, iu, sizeof *tsk_mgmt))
goto out;
@@ -1188,37 +1277,82 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func)
req->tsk_mgmt = iu;
spin_unlock_irq(target->scsi_host->host_lock);
+
if (!wait_for_completion_timeout(&req->done,
msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
- return FAILED;
- spin_lock_irq(target->scsi_host->host_lock);
+ return -1;
- if (req->cmd_done) {
- srp_remove_req(target, req, req_index);
- scmnd->scsi_done(scmnd);
- } else if (!req->tsk_status) {
- srp_remove_req(target, req, req_index);
- scmnd->result = DID_ABORT << 16;
- ret = SUCCESS;
- }
+ return 0;
out:
spin_unlock_irq(target->scsi_host->host_lock);
- return ret;
+ return -1;
+}
+
+static int srp_find_req(struct srp_target_port *target,
+ struct scsi_cmnd *scmnd,
+ struct srp_request **req)
+{
+ if (scmnd->host_scribble == (void *) -1L)
+ return -1;
+
+ *req = &target->req_ring[(long) scmnd->host_scribble];
+
+ return 0;
}
static int srp_abort(struct scsi_cmnd *scmnd)
{
+ struct srp_target_port *target = host_to_target(scmnd->device->host);
+ struct srp_request *req;
+ int ret = SUCCESS;
+
printk(KERN_ERR "SRP abort called\n");
- return srp_send_tsk_mgmt(scmnd, SRP_TSK_ABORT_TASK);
+ if (srp_find_req(target, scmnd, &req))
+ return FAILED;
+ if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
+ return FAILED;
+
+ spin_lock_irq(target->scsi_host->host_lock);
+
+ if (req->cmd_done) {
+ srp_remove_req(target, req);
+ scmnd->scsi_done(scmnd);
+ } else if (!req->tsk_status) {
+ srp_remove_req(target, req);
+ scmnd->result = DID_ABORT << 16;
+ } else
+ ret = FAILED;
+
+ spin_unlock_irq(target->scsi_host->host_lock);
+
+ return ret;
}
static int srp_reset_device(struct scsi_cmnd *scmnd)
{
+ struct srp_target_port *target = host_to_target(scmnd->device->host);
+ struct srp_request *req, *tmp;
+
printk(KERN_ERR "SRP reset_device called\n");
- return srp_send_tsk_mgmt(scmnd, SRP_TSK_LUN_RESET);
+ if (srp_find_req(target, scmnd, &req))
+ return FAILED;
+ if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
+ return FAILED;
+ if (req->tsk_status)
+ return FAILED;
+
+ spin_lock_irq(target->scsi_host->host_lock);
+
+ list_for_each_entry_safe(req, tmp, &target->req_queue, list)
+ if (req->scmnd->device == scmnd->device)
+ srp_reset_req(target, req);
+
+ spin_unlock_irq(target->scsi_host->host_lock);
+
+ return SUCCESS;
}
static int srp_reset_host(struct scsi_cmnd *scmnd)
@@ -1300,11 +1434,23 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf)
be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
}
+static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%d\n", target->zero_req_lim);
+}
+
static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static struct class_device_attribute *srp_host_attrs[] = {
&class_device_attr_id_ext,
@@ -1312,6 +1458,7 @@ static struct class_device_attribute *srp_host_attrs[] = {
&class_device_attr_service_id,
&class_device_attr_pkey,
&class_device_attr_dgid,
+ &class_device_attr_zero_req_lim,
NULL
};
@@ -1325,7 +1472,6 @@ static struct scsi_host_template srp_template = {
.eh_host_reset_handler = srp_reset_host,
.can_queue = SRP_SQ_SIZE,
.this_id = -1,
- .sg_tablesize = SRP_MAX_INDIRECT,
.cmd_per_lun = SRP_SQ_SIZE,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = srp_host_attrs
@@ -1336,18 +1482,17 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
sprintf(target->target_name, "SRP.T10:%016llX",
(unsigned long long) be64_to_cpu(target->id_ext));
- if (scsi_add_host(target->scsi_host, host->dev->dma_device))
+ if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device))
return -ENODEV;
- mutex_lock(&host->target_mutex);
+ spin_lock(&host->target_lock);
list_add_tail(&target->list, &host->target_list);
- mutex_unlock(&host->target_mutex);
+ spin_unlock(&host->target_lock);
target->state = SRP_TARGET_LIVE;
- /* XXX: are we supposed to have a definition of SCAN_WILD_CARD ?? */
scsi_scan_target(&target->scsi_host->shost_gendev,
- 0, target->scsi_id, ~0, 0);
+ 0, target->scsi_id, SCAN_WILD_CARD, 0);
return 0;
}
@@ -1381,6 +1526,8 @@ enum {
SRP_OPT_PKEY = 1 << 3,
SRP_OPT_SERVICE_ID = 1 << 4,
SRP_OPT_MAX_SECT = 1 << 5,
+ SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
+ SRP_OPT_IO_CLASS = 1 << 7,
SRP_OPT_ALL = (SRP_OPT_ID_EXT |
SRP_OPT_IOC_GUID |
SRP_OPT_DGID |
@@ -1389,13 +1536,15 @@ enum {
};
static match_table_t srp_opt_tokens = {
- { SRP_OPT_ID_EXT, "id_ext=%s" },
- { SRP_OPT_IOC_GUID, "ioc_guid=%s" },
- { SRP_OPT_DGID, "dgid=%s" },
- { SRP_OPT_PKEY, "pkey=%x" },
- { SRP_OPT_SERVICE_ID, "service_id=%s" },
- { SRP_OPT_MAX_SECT, "max_sect=%d" },
- { SRP_OPT_ERR, NULL }
+ { SRP_OPT_ID_EXT, "id_ext=%s" },
+ { SRP_OPT_IOC_GUID, "ioc_guid=%s" },
+ { SRP_OPT_DGID, "dgid=%s" },
+ { SRP_OPT_PKEY, "pkey=%x" },
+ { SRP_OPT_SERVICE_ID, "service_id=%s" },
+ { SRP_OPT_MAX_SECT, "max_sect=%d" },
+ { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" },
+ { SRP_OPT_IO_CLASS, "io_class=%x" },
+ { SRP_OPT_ERR, NULL }
};
static int srp_parse_options(const char *buf, struct srp_target_port *target)
@@ -1471,6 +1620,29 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
target->scsi_host->max_sectors = token;
break;
+ case SRP_OPT_MAX_CMD_PER_LUN:
+ if (match_int(args, &token)) {
+ printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p);
+ goto out;
+ }
+ target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE);
+ break;
+
+ case SRP_OPT_IO_CLASS:
+ if (match_hex(args, &token)) {
+ printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p);
+ goto out;
+ }
+ if (token != SRP_REV10_IB_IO_CLASS &&
+ token != SRP_REV16A_IB_IO_CLASS) {
+ printk(KERN_WARNING PFX "unknown IO class parameter value"
+ " %x specified (use %x or %x).\n",
+ token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS);
+ goto out;
+ }
+ target->io_class = token;
+ break;
+
default:
printk(KERN_WARNING PFX "unknown parameter or missing value "
"'%s' in target creation request\n", p);
@@ -1513,21 +1685,24 @@ static ssize_t srp_create_target(struct class_device *class_dev,
target = host_to_target(target_host);
memset(target, 0, sizeof *target);
+ target->io_class = SRP_REV16A_IB_IO_CLASS;
target->scsi_host = target_host;
target->srp_host = host;
INIT_WORK(&target->work, srp_reconnect_work, target);
- for (i = 0; i < SRP_SQ_SIZE - 1; ++i)
- target->req_ring[i].next = i + 1;
- target->req_ring[SRP_SQ_SIZE - 1].next = -1;
+ INIT_LIST_HEAD(&target->free_reqs);
INIT_LIST_HEAD(&target->req_queue);
+ for (i = 0; i < SRP_SQ_SIZE; ++i) {
+ target->req_ring[i].index = i;
+ list_add_tail(&target->req_ring[i].list, &target->free_reqs);
+ }
ret = srp_parse_options(buf, target);
if (ret)
goto err;
- ib_get_cached_gid(host->dev, host->port, 0, &target->path.sgid);
+ ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid);
printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
"service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
@@ -1548,7 +1723,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
if (ret)
goto err;
- target->cm_id = ib_create_cm_id(host->dev, srp_cm_handler, target);
+ target->cm_id = ib_create_cm_id(host->dev->dev, srp_cm_handler, target);
if (IS_ERR(target->cm_id)) {
ret = PTR_ERR(target->cm_id);
goto err_free;
@@ -1588,7 +1763,7 @@ static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
struct srp_host *host =
container_of(class_dev, struct srp_host, class_dev);
- return sprintf(buf, "%s\n", host->dev->name);
+ return sprintf(buf, "%s\n", host->dev->dev->name);
}
static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
@@ -1603,7 +1778,7 @@ static ssize_t show_port(struct class_device *class_dev, char *buf)
static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
-static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
+static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
{
struct srp_host *host;
@@ -1612,32 +1787,21 @@ static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
return NULL;
INIT_LIST_HEAD(&host->target_list);
- mutex_init(&host->target_mutex);
+ spin_lock_init(&host->target_lock);
init_completion(&host->released);
host->dev = device;
host->port = port;
host->initiator_port_id[7] = port;
- memcpy(host->initiator_port_id + 8, &device->node_guid, 8);
-
- host->pd = ib_alloc_pd(device);
- if (IS_ERR(host->pd))
- goto err_free;
-
- host->mr = ib_get_dma_mr(host->pd,
- IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE);
- if (IS_ERR(host->mr))
- goto err_pd;
+ memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8);
host->class_dev.class = &srp_class;
- host->class_dev.dev = device->dma_device;
+ host->class_dev.dev = device->dev->dma_device;
snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d",
- device->name, port);
+ device->dev->name, port);
if (class_device_register(&host->class_dev))
- goto err_mr;
+ goto free_host;
if (class_device_create_file(&host->class_dev, &class_device_attr_add_target))
goto err_class;
if (class_device_create_file(&host->class_dev, &class_device_attr_ibdev))
@@ -1650,13 +1814,7 @@ static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
err_class:
class_device_unregister(&host->class_dev);
-err_mr:
- ib_dereg_mr(host->mr);
-
-err_pd:
- ib_dealloc_pd(host->pd);
-
-err_free:
+free_host:
kfree(host);
return NULL;
@@ -1664,15 +1822,62 @@ err_free:
static void srp_add_one(struct ib_device *device)
{
- struct list_head *dev_list;
+ struct srp_device *srp_dev;
+ struct ib_device_attr *dev_attr;
+ struct ib_fmr_pool_param fmr_param;
struct srp_host *host;
int s, e, p;
- dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
- if (!dev_list)
+ dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
+ if (!dev_attr)
return;
- INIT_LIST_HEAD(dev_list);
+ if (ib_query_device(device, dev_attr)) {
+ printk(KERN_WARNING PFX "Query device failed for %s\n",
+ device->name);
+ goto free_attr;
+ }
+
+ srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL);
+ if (!srp_dev)
+ goto free_attr;
+
+ /*
+ * Use the smallest page size supported by the HCA, down to a
+ * minimum of 512 bytes (which is the smallest sector that a
+ * SCSI command will ever carry).
+ */
+ srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
+ srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift;
+ srp_dev->fmr_page_mask = ~((unsigned long) srp_dev->fmr_page_size - 1);
+
+ INIT_LIST_HEAD(&srp_dev->dev_list);
+
+ srp_dev->dev = device;
+ srp_dev->pd = ib_alloc_pd(device);
+ if (IS_ERR(srp_dev->pd))
+ goto free_dev;
+
+ srp_dev->mr = ib_get_dma_mr(srp_dev->pd,
+ IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_WRITE);
+ if (IS_ERR(srp_dev->mr))
+ goto err_pd;
+
+ memset(&fmr_param, 0, sizeof fmr_param);
+ fmr_param.pool_size = SRP_FMR_POOL_SIZE;
+ fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE;
+ fmr_param.cache = 1;
+ fmr_param.max_pages_per_fmr = SRP_FMR_SIZE;
+ fmr_param.page_shift = srp_dev->fmr_page_shift;
+ fmr_param.access = (IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_REMOTE_READ);
+
+ srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param);
+ if (IS_ERR(srp_dev->fmr_pool))
+ srp_dev->fmr_pool = NULL;
if (device->node_type == IB_NODE_SWITCH) {
s = 0;
@@ -1683,25 +1888,35 @@ static void srp_add_one(struct ib_device *device)
}
for (p = s; p <= e; ++p) {
- host = srp_add_port(device, p);
+ host = srp_add_port(srp_dev, p);
if (host)
- list_add_tail(&host->list, dev_list);
+ list_add_tail(&host->list, &srp_dev->dev_list);
}
- ib_set_client_data(device, &srp_client, dev_list);
+ ib_set_client_data(device, &srp_client, srp_dev);
+
+ goto free_attr;
+
+err_pd:
+ ib_dealloc_pd(srp_dev->pd);
+
+free_dev:
+ kfree(srp_dev);
+
+free_attr:
+ kfree(dev_attr);
}
static void srp_remove_one(struct ib_device *device)
{
- struct list_head *dev_list;
+ struct srp_device *srp_dev;
struct srp_host *host, *tmp_host;
LIST_HEAD(target_list);
struct srp_target_port *target, *tmp_target;
- unsigned long flags;
- dev_list = ib_get_client_data(device, &srp_client);
+ srp_dev = ib_get_client_data(device, &srp_client);
- list_for_each_entry_safe(host, tmp_host, dev_list, list) {
+ list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
class_device_unregister(&host->class_dev);
/*
* Wait for the sysfs entry to go away, so that no new
@@ -1713,15 +1928,13 @@ static void srp_remove_one(struct ib_device *device)
* Mark all target ports as removed, so we stop queueing
* commands and don't try to reconnect.
*/
- mutex_lock(&host->target_mutex);
- list_for_each_entry_safe(target, tmp_target,
- &host->target_list, list) {
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
- if (target->state != SRP_TARGET_REMOVED)
- target->state = SRP_TARGET_REMOVED;
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+ spin_lock(&host->target_lock);
+ list_for_each_entry(target, &host->target_list, list) {
+ spin_lock_irq(target->scsi_host->host_lock);
+ target->state = SRP_TARGET_REMOVED;
+ spin_unlock_irq(target->scsi_host->host_lock);
}
- mutex_unlock(&host->target_mutex);
+ spin_unlock(&host->target_lock);
/*
* Wait for any reconnection tasks that may have
@@ -1739,18 +1952,26 @@ static void srp_remove_one(struct ib_device *device)
scsi_host_put(target->scsi_host);
}
- ib_dereg_mr(host->mr);
- ib_dealloc_pd(host->pd);
kfree(host);
}
- kfree(dev_list);
+ if (srp_dev->fmr_pool)
+ ib_destroy_fmr_pool(srp_dev->fmr_pool);
+ ib_dereg_mr(srp_dev->mr);
+ ib_dealloc_pd(srp_dev->pd);
+
+ kfree(srp_dev);
}
static int __init srp_init_module(void)
{
int ret;
+ srp_template.sg_tablesize = srp_sg_tablesize;
+ srp_max_iu_len = (sizeof (struct srp_cmd) +
+ sizeof (struct srp_indirect_buf) +
+ srp_sg_tablesize * 16);
+
ret = class_register(&srp_class);
if (ret) {
printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index bd7f7c3115de..5b581fb8eb0d 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -46,6 +46,7 @@
#include <rdma/ib_verbs.h>
#include <rdma/ib_sa.h>
#include <rdma/ib_cm.h>
+#include <rdma/ib_fmr_pool.h>
enum {
SRP_PATH_REC_TIMEOUT_MS = 1000,
@@ -55,20 +56,21 @@ enum {
SRP_DLID_REDIRECT = 2,
SRP_MAX_LUN = 512,
- SRP_MAX_IU_LEN = 256,
+ SRP_DEF_SG_TABLESIZE = 12,
SRP_RQ_SHIFT = 6,
SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT,
SRP_SQ_SIZE = SRP_RQ_SIZE - 1,
SRP_CQ_SIZE = SRP_SQ_SIZE + SRP_RQ_SIZE,
- SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1)
+ SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1),
+
+ SRP_FMR_SIZE = 256,
+ SRP_FMR_POOL_SIZE = 1024,
+ SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4
};
#define SRP_OP_RECV (1 << 31)
-#define SRP_MAX_INDIRECT ((SRP_MAX_IU_LEN - \
- sizeof (struct srp_cmd) - \
- sizeof (struct srp_indirect_buf)) / 16)
enum srp_target_state {
SRP_TARGET_LIVE,
@@ -77,15 +79,24 @@ enum srp_target_state {
SRP_TARGET_REMOVED
};
-struct srp_host {
- u8 initiator_port_id[16];
+struct srp_device {
+ struct list_head dev_list;
struct ib_device *dev;
- u8 port;
struct ib_pd *pd;
struct ib_mr *mr;
+ struct ib_fmr_pool *fmr_pool;
+ int fmr_page_shift;
+ int fmr_page_size;
+ unsigned long fmr_page_mask;
+};
+
+struct srp_host {
+ u8 initiator_port_id[16];
+ struct srp_device *dev;
+ u8 port;
struct class_device class_dev;
struct list_head target_list;
- struct mutex target_mutex;
+ spinlock_t target_lock;
struct completion released;
struct list_head list;
};
@@ -95,13 +106,14 @@ struct srp_request {
struct scsi_cmnd *scmnd;
struct srp_iu *cmd;
struct srp_iu *tsk_mgmt;
+ struct ib_pool_fmr *fmr;
/*
* Fake scatterlist used when scmnd->use_sg==0. Can be killed
* when the SCSI midlayer no longer generates non-SG commands.
*/
struct scatterlist fake_sg;
struct completion done;
- short next;
+ short index;
u8 cmd_done;
u8 tsk_status;
};
@@ -110,6 +122,7 @@ struct srp_target_port {
__be64 id_ext;
__be64 ioc_guid;
__be64 service_id;
+ u16 io_class;
struct srp_host *srp_host;
struct Scsi_Host *scsi_host;
char target_name[32];
@@ -126,6 +139,8 @@ struct srp_target_port {
int max_ti_iu_len;
s32 req_lim;
+ int zero_req_lim;
+
unsigned rx_head;
struct srp_iu *rx_ring[SRP_RQ_SIZE];
@@ -133,7 +148,7 @@ struct srp_target_port {
unsigned tx_tail;
struct srp_iu *tx_ring[SRP_SQ_SIZE + 1];
- int req_head;
+ struct list_head free_reqs;
struct list_head req_queue;
struct srp_request req_ring[SRP_SQ_SIZE];
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a34e3d91d9ed..ba325f16d077 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -403,6 +403,27 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
case EVIOCGID:
if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
return -EFAULT;
+ return 0;
+
+ case EVIOCGREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (put_user(dev->rep[REP_DELAY], ip))
+ return -EFAULT;
+ if (put_user(dev->rep[REP_PERIOD], ip + 1))
+ return -EFAULT;
+ return 0;
+
+ case EVIOCSREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (get_user(u, ip))
+ return -EFAULT;
+ if (get_user(v, ip + 1))
+ return -EFAULT;
+
+ input_event(dev, EV_REP, REP_DELAY, u);
+ input_event(dev, EV_REP, REP_PERIOD, v);
return 0;
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a935abeffffc..3038c268917d 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -155,6 +155,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (code > SND_MAX || !test_bit(code, dev->sndbit))
return;
+ if (!!test_bit(code, dev->snd) != !!value)
+ change_bit(code, dev->snd);
+
if (dev->event) dev->event(dev, type, code, value);
break;
@@ -286,19 +289,19 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st
for (; id->flags || id->driver_info; id++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
- if (id->id.bustype != dev->id.bustype)
+ if (id->bustype != dev->id.bustype)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
- if (id->id.vendor != dev->id.vendor)
+ if (id->vendor != dev->id.vendor)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
- if (id->id.product != dev->id.product)
+ if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
- if (id->id.version != dev->id.version)
+ if (id->version != dev->id.version)
continue;
MATCH_BIT(evbit, EV_MAX);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 2b2ec1057dee..95c0de7964a0 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -589,7 +589,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
struct sw *sw;
struct input_dev *input_dev;
int i, j, k, l;
- int err;
+ int err = 0;
unsigned char *buf = NULL; /* [SW_LENGTH] */
unsigned char *idbuf = NULL; /* [SW_LENGTH] */
unsigned char m = 1;
@@ -776,7 +776,10 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail4;
}
- return 0;
+ out: kfree(buf);
+ kfree(idbuf);
+
+ return err;
fail4: input_free_device(sw->dev[i]);
fail3: while (--i >= 0)
@@ -784,9 +787,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
fail2: gameport_close(gameport);
fail1: gameport_set_drvdata(gameport, NULL);
kfree(sw);
- kfree(buf);
- kfree(idbuf);
- return err;
+ goto out;
}
static void sw_disconnect(struct gameport *gameport)
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 96c6bf77248a..1f0e720267d7 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -245,9 +245,9 @@ static void corgikbd_hinge_timer(unsigned long data)
if (hinge_count >= HINGE_STABLE_COUNT) {
spin_lock_irqsave(&corgikbd_data->lock, flags);
- input_report_switch(corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
- input_report_switch(corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
- input_report_switch(corgikbd_data->input, SW_2, (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0));
+ input_report_switch(corgikbd_data->input, SW_LID, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
+ input_report_switch(corgikbd_data->input, SW_TABLET_MODE, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
+ input_report_switch(corgikbd_data->input, SW_HEADPHONE_INSERT, (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0));
input_sync(corgikbd_data->input);
spin_unlock_irqrestore(&corgikbd_data->lock, flags);
@@ -340,9 +340,9 @@ static int __init corgikbd_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
set_bit(corgikbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
- set_bit(SW_0, input_dev->swbit);
- set_bit(SW_1, input_dev->swbit);
- set_bit(SW_2, input_dev->swbit);
+ set_bit(SW_LID, input_dev->swbit);
+ set_bit(SW_TABLET_MODE, input_dev->swbit);
+ set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
input_register_device(corgikbd->input);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 1dca3cf42a54..2e4abdc26367 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -350,11 +350,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
return 0;
bail2:
serio_close(serio);
+ serio_set_drvdata(serio, NULL);
bail1:
input_free_device(kbd->dev);
bail0:
kfree(kbd);
- serio_set_drvdata(serio, NULL);
return -EIO;
}
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index bc61cf8cfc65..c5d03fb77bcb 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -53,8 +53,8 @@ static unsigned char spitzkbd_keycode[NR_SCANCODES] = {
KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */
0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */
KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
- SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
- SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */
+ SPITZ_KEY_ADDRESS, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
+ SPITZ_KEY_CALENDER, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */
SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */
KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */
};
@@ -299,9 +299,9 @@ static void spitzkbd_hinge_timer(unsigned long data)
if (hinge_count >= HINGE_STABLE_COUNT) {
spin_lock_irqsave(&spitzkbd_data->lock, flags);
- input_report_switch(spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
- input_report_switch(spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
- input_report_switch(spitzkbd_data->input, SW_2, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0));
+ input_report_switch(spitzkbd_data->input, SW_LID, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
+ input_report_switch(spitzkbd_data->input, SW_TABLET_MODE, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
+ input_report_switch(spitzkbd_data->input, SW_HEADPHONE_INSERT, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0));
input_sync(spitzkbd_data->input);
spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
@@ -398,9 +398,9 @@ static int __init spitzkbd_probe(struct platform_device *dev)
for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++)
set_bit(spitzkbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
- set_bit(SW_0, input_dev->swbit);
- set_bit(SW_1, input_dev->swbit);
- set_bit(SW_2, input_dev->swbit);
+ set_bit(SW_LID, input_dev->swbit);
+ set_bit(SW_TABLET_MODE, input_dev->swbit);
+ set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
input_register_device(input_dev);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 4b415d9b0123..e4e5be111c96 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -273,6 +273,18 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = {
{ KE_END, 0 }
};
+static struct key_entry keymap_fujitsu_n3510[] = {
+ { KE_KEY, 0x11, KEY_PROG1 },
+ { KE_KEY, 0x12, KEY_PROG2 },
+ { KE_KEY, 0x36, KEY_WWW },
+ { KE_KEY, 0x31, KEY_MAIL },
+ { KE_KEY, 0x71, KEY_STOPCD },
+ { KE_KEY, 0x72, KEY_PLAYPAUSE },
+ { KE_KEY, 0x74, KEY_REWIND },
+ { KE_KEY, 0x78, KEY_FORWARD },
+ { KE_END, 0 }
+};
+
static struct key_entry keymap_wistron_ms2141[] = {
{ KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 },
@@ -306,6 +318,16 @@ static struct key_entry keymap_acer_travelmate_240[] = {
{ KE_END, 0 }
};
+static struct key_entry keymap_aopen_1559as[] = {
+ { KE_KEY, 0x01, KEY_HELP },
+ { KE_KEY, 0x06, KEY_PROG3 },
+ { KE_KEY, 0x11, KEY_PROG1 },
+ { KE_KEY, 0x12, KEY_PROG2 },
+ { KE_WIFI, 0x30, 0 },
+ { KE_KEY, 0x31, KEY_MAIL },
+ { KE_KEY, 0x36, KEY_WWW },
+};
+
/*
* If your machine is not here (which is currently rather likely), please send
* a list of buttons and their key codes (reported when loading this module
@@ -323,6 +345,24 @@ static struct dmi_system_id dmi_ids[] = {
},
{
.callback = dmi_matched,
+ .ident = "Fujitsu-Siemens Amilo M7400",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "),
+ },
+ .driver_data = keymap_fs_amilo_pro_v2000
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Fujitsu N3510",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
+ },
+ .driver_data = keymap_fujitsu_n3510
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer Aspire 1500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -339,6 +379,15 @@ static struct dmi_system_id dmi_ids[] = {
},
.driver_data = keymap_acer_travelmate_240
},
+ {
+ .callback = dmi_matched,
+ .ident = "AOpen 1559AS",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
+ DMI_MATCH(DMI_BOARD_NAME, "E2U"),
+ },
+ .driver_data = keymap_aopen_1559as
+ },
{ NULL, }
};
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 2141501e9f2e..a0e2e797c6d5 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -100,8 +100,8 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
}
if (priv->i->flags & ALPS_OLDPROTO) {
- left = packet[2] & 0x08;
- right = packet[2] & 0x10;
+ left = packet[2] & 0x10;
+ right = packet[2] & 0x08;
middle = 0;
x = packet[1] | ((packet[0] & 0x07) << 7);
y = packet[4] | ((packet[3] & 0x07) << 7);
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 5ccc3ef3b89e..c14395ba7980 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -22,12 +22,36 @@
static struct dmi_system_id lifebook_dmi_table[] = {
{
+ .ident = "LifeBook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
+ },
+ },
+ {
.ident = "Lifebook B",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
},
},
{
+ .ident = "Lifebook B213x/B2150",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
+ },
+ },
+ {
+ .ident = "Zephyr",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
+ },
+ },
+ {
+ .ident = "CF-18",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
+ },
+ },
+ {
.ident = "Lifebook B142",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 40333d61093c..2f0d28840810 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -19,6 +19,7 @@
#define PS2PP_KIND_WHEEL 1
#define PS2PP_KIND_MX 2
#define PS2PP_KIND_TP3 3
+#define PS2PP_KIND_TRACKMAN 4
/* Logitech mouse features */
#define PS2PP_WHEEL 0x01
@@ -223,6 +224,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 73, 0, PS2PP_SIDE_BTN },
{ 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
+ { 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */
{ 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
@@ -298,6 +300,10 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_inf
psmouse->name = "TouchPad 3";
break;
+ case PS2PP_KIND_TRACKMAN:
+ psmouse->name = "TrackMan";
+ break;
+
default:
/*
* Set name to "Mouse" only when using PS2++,
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 32d70ed8f41d..136321a2cfdb 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -302,8 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
* Check if this is a new device announcement (0xAA 0x00)
*/
if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
- if (psmouse->pktcnt == 1)
+ if (psmouse->pktcnt == 1) {
+ psmouse->last = jiffies;
goto out;
+ }
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 9a9221644250..cc21914fbc72 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -67,14 +67,14 @@ static inline int i8042_platform_init(void)
* On some platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on such boxes.
*/
-#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64)
+#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC_MERGE)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -EBUSY;
#endif
i8042_reset = 1;
-#if defined(CONFIG_PPC64)
+#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(I8042_DATA_REG))
return -EBUSY;
if (!request_region(I8042_DATA_REG, 16, "i8042"))
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 46d1fec2cfd8..161afddd0f44 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -2,6 +2,8 @@
* ADS7846 based touchscreen and sensor driver
*
* Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * Various changes: Imre Deak <imre.deak@nokia.com>
*
* Using code from:
* - corgi_ts.c
@@ -34,17 +36,22 @@
/*
- * This code has been lightly tested on an ads7846.
+ * This code has been heavily tested on a Nokia 770, and lightly
+ * tested on other ads7846 devices (OSK/Mistral, Lubbock).
* Support for ads7843 and ads7845 has only been stubbed in.
*
- * Not yet done: investigate the values reported. Are x/y/pressure
- * event values sane enough for X11? How accurate are the temperature
- * and voltage readings? (System-specific calibration should support
- * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.)
+ * IRQ handling needs a workaround because of a shortcoming in handling
+ * edge triggered IRQs on some platforms like the OMAP1/2. These
+ * platforms don't handle the ARM lazy IRQ disabling properly, thus we
+ * have to maintain our own SW IRQ disabled status. This should be
+ * removed as soon as the affected platform's IRQ handling is fixed.
*
* app note sbaa036 talks in more detail about accurate sampling...
* that ought to help in situations like LCDs inducing noise (which
* can also be helped by using synch signals) and more generally.
+ * This driver tries to utilize the measures described in the app
+ * note. The strength of filtering can be set in the board-* specific
+ * files.
*/
#define TS_POLL_PERIOD msecs_to_jiffies(10)
@@ -61,6 +68,7 @@ struct ts_event {
__be16 x;
__be16 y;
__be16 z1, z2;
+ int ignore;
};
struct ads7846 {
@@ -71,12 +79,23 @@ struct ads7846 {
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
+ u16 pressure_max;
- u8 read_x, read_y, read_z1, read_z2;
+ u8 read_x, read_y, read_z1, read_z2, pwrdown;
+ u16 dummy; /* for the pwrdown read */
struct ts_event tc;
- struct spi_transfer xfer[8];
- struct spi_message msg;
+ struct spi_transfer xfer[10];
+ struct spi_message msg[5];
+ struct spi_message *last_msg;
+ int msg_idx;
+ int read_cnt;
+ int read_rep;
+ int last_read;
+
+ u16 debounce_max;
+ u16 debounce_tol;
+ u16 debounce_rep;
spinlock_t lock;
struct timer_list timer; /* P: lock */
@@ -84,6 +103,9 @@ struct ads7846 {
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
+ unsigned disabled:1;
+
+ int (*get_pendown_state)(void);
};
/* leave chip selected when we're done, for quicker re-select? */
@@ -125,7 +147,9 @@ struct ads7846 {
#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
-#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) /* LAST */
+
+#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON)
+#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
@@ -152,6 +176,15 @@ struct ser_req {
struct spi_transfer xfer[6];
};
+static void ads7846_enable(struct ads7846 *ts);
+static void ads7846_disable(struct ads7846 *ts);
+
+static int device_suspended(struct device *dev)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ return dev->power.power_state.event != PM_EVENT_ON || ts->disabled;
+}
+
static int ads7846_read12_ser(struct device *dev, unsigned command)
{
struct spi_device *spi = to_spi_device(dev);
@@ -164,7 +197,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
if (!req)
return -ENOMEM;
- INIT_LIST_HEAD(&req->msg.transfers);
+ spi_message_init(&req->msg);
/* activate reference, so it has time to settle; */
req->ref_on = REF_ON;
@@ -204,16 +237,21 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
for (i = 0; i < 6; i++)
spi_message_add_tail(&req->xfer[i], &req->msg);
+ ts->irq_disabled = 1;
disable_irq(spi->irq);
status = spi_sync(spi, &req->msg);
+ ts->irq_disabled = 0;
enable_irq(spi->irq);
if (req->msg.status)
status = req->msg.status;
+
+ /* on-wire is a must-ignore bit, a BE12 value, then padding */
sample = be16_to_cpu(req->sample);
- sample = sample >> 4;
- kfree(req);
+ sample = sample >> 3;
+ sample &= 0x0fff;
+ kfree(req);
return status ? status : sample;
}
@@ -233,6 +271,52 @@ SHOW(temp1)
SHOW(vaux)
SHOW(vbatt)
+static int is_pen_down(struct device *dev)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+
+ return ts->pendown;
+}
+
+static ssize_t ads7846_pen_down_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", is_pen_down(dev));
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
+
+static ssize_t ads7846_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t ads7846_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ char *endp;
+ int i;
+
+ i = simple_strtoul(buf, &endp, 10);
+ spin_lock_irq(&ts->lock);
+
+ if (i)
+ ads7846_disable(ts);
+ else
+ ads7846_enable(ts);
+
+ spin_unlock_irq(&ts->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
+
/*--------------------------------------------------------------------------*/
/*
@@ -252,19 +336,19 @@ static void ads7846_rx(void *ads)
u16 x, y, z1, z2;
unsigned long flags;
- /* adjust: 12 bit samples (left aligned), built from
- * two 8 bit values writen msb-first.
+ /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
+ * built from two 8 bit values written msb-first.
*/
- x = be16_to_cpu(ts->tc.x) >> 4;
- y = be16_to_cpu(ts->tc.y) >> 4;
- z1 = be16_to_cpu(ts->tc.z1) >> 4;
- z2 = be16_to_cpu(ts->tc.z2) >> 4;
+ x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
+ y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
+ z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
+ z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
/* range filtering */
if (x == MAX_12BIT)
x = 0;
- if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
+ if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
@@ -275,6 +359,14 @@ static void ads7846_rx(void *ads)
} else
Rt = 0;
+ /* Sample found inconsistent by debouncing or pressure is beyond
+ * the maximum. Don't report it to user space, repeat at least
+ * once more the measurement */
+ if (ts->tc.ignore || Rt > ts->pressure_max) {
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+ return;
+ }
+
/* NOTE: "pendown" is inferred from pressure; we don't rely on
* being able to check nPENIRQ status, or "friendly" trigger modes
* (both-edges is much better than just-falling or low-level).
@@ -296,11 +388,13 @@ static void ads7846_rx(void *ads)
if (Rt) {
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
- input_report_abs(input_dev, ABS_PRESSURE, Rt);
sync = 1;
}
- if (sync)
+
+ if (sync) {
+ input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
+ }
#ifdef VERBOSE
if (Rt || ts->pendown)
@@ -308,80 +402,137 @@ static void ads7846_rx(void *ads)
x, y, Rt, Rt ? "" : " UP");
#endif
- /* don't retrigger while we're suspended */
spin_lock_irqsave(&ts->lock, flags);
ts->pendown = (Rt != 0);
- ts->pending = 0;
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
- if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
- if (ts->pendown)
- mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
- else if (ts->irq_disabled) {
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
+ spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void ads7846_debounce(void *ads)
+{
+ struct ads7846 *ts = ads;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ int val;
+ int status;
+
+ m = &ts->msg[ts->msg_idx];
+ t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
+ if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+ /* Repeat it, if this was the first read or the read
+ * wasn't consistent enough. */
+ if (ts->read_cnt < ts->debounce_max) {
+ ts->last_read = val;
+ ts->read_cnt++;
+ } else {
+ /* Maximum number of debouncing reached and still
+ * not enough number of consistent readings. Abort
+ * the whole sample, repeat it in the next sampling
+ * period.
+ */
+ ts->tc.ignore = 1;
+ ts->read_cnt = 0;
+ /* Last message will contain ads7846_rx() as the
+ * completion function.
+ */
+ m = ts->last_msg;
}
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
+ } else {
+ if (++ts->read_rep > ts->debounce_rep) {
+ /* Got a good reading for this coordinate,
+ * go for the next one. */
+ ts->tc.ignore = 0;
+ ts->msg_idx++;
+ ts->read_cnt = 0;
+ ts->read_rep = 0;
+ m++;
+ } else
+ /* Read more values that are consistent. */
+ ts->read_cnt++;
}
-
- spin_unlock_irqrestore(&ts->lock, flags);
+ status = spi_async(ts->spi, m);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n",
+ status);
}
static void ads7846_timer(unsigned long handle)
{
struct ads7846 *ts = (void *)handle;
int status = 0;
- unsigned long flags;
+
+ spin_lock_irq(&ts->lock);
+
+ if (unlikely(ts->msg_idx && !ts->pendown)) {
+ /* measurement cycle ended */
+ if (!device_suspended(&ts->spi->dev)) {
+ ts->irq_disabled = 0;
+ enable_irq(ts->spi->irq);
+ }
+ ts->pending = 0;
+ ts->msg_idx = 0;
+ } else {
+ /* pen is still down, continue with the measurement */
+ ts->msg_idx = 0;
+ status = spi_async(ts->spi, &ts->msg[0]);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
+ }
+
+ spin_unlock_irq(&ts->lock);
+}
+
+static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+{
+ struct ads7846 *ts = handle;
+ unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
- if (!ts->pending) {
- ts->pending = 1;
+ if (likely(ts->get_pendown_state())) {
if (!ts->irq_disabled) {
+ /* The ARM do_simple_IRQ() dispatcher doesn't act
+ * like the other dispatchers: it will report IRQs
+ * even after they've been disabled. We work around
+ * that here. (The "generic irq" framework may help...)
+ */
ts->irq_disabled = 1;
disable_irq(ts->spi->irq);
+ ts->pending = 1;
+ mod_timer(&ts->timer, jiffies);
}
- status = spi_async(ts->spi, &ts->msg);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n",
- status);
}
spin_unlock_irqrestore(&ts->lock, flags);
-}
-static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
-{
- ads7846_timer((unsigned long) handle);
return IRQ_HANDLED;
}
/*--------------------------------------------------------------------------*/
-static int
-ads7846_suspend(struct spi_device *spi, pm_message_t message)
+/* Must be called with ts->lock held */
+static void ads7846_disable(struct ads7846 *ts)
{
- struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- unsigned long flags;
+ if (ts->disabled)
+ return;
- spin_lock_irqsave(&ts->lock, flags);
-
- spi->dev.power.power_state = message;
+ ts->disabled = 1;
/* are we waiting for IRQ, or polling? */
- if (!ts->pendown) {
- if (!ts->irq_disabled) {
- ts->irq_disabled = 1;
- disable_irq(ts->spi->irq);
- }
+ if (!ts->pending) {
+ ts->irq_disabled = 1;
+ disable_irq(ts->spi->irq);
} else {
- /* polling; force a final SPI completion;
- * that will clean things up neatly
+ /* the timer will run at least once more, and
+ * leave everything in a clean state, IRQ disabled
*/
- if (!ts->pending)
- mod_timer(&ts->timer, jiffies);
-
- while (ts->pendown || ts->pending) {
- spin_unlock_irqrestore(&ts->lock, flags);
- udelay(10);
- spin_lock_irqsave(&ts->lock, flags);
+ while (ts->pending) {
+ spin_unlock_irq(&ts->lock);
+ msleep(1);
+ spin_lock_irq(&ts->lock);
}
}
@@ -389,17 +540,45 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message)
* leave it that way after every request
*/
- spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+/* Must be called with ts->lock held */
+static void ads7846_enable(struct ads7846 *ts)
+{
+ if (!ts->disabled)
+ return;
+
+ ts->disabled = 0;
+ ts->irq_disabled = 0;
+ enable_irq(ts->spi->irq);
+}
+
+static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
+{
+ struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+
+ spin_lock_irq(&ts->lock);
+
+ spi->dev.power.power_state = message;
+ ads7846_disable(ts);
+
+ spin_unlock_irq(&ts->lock);
+
return 0;
+
}
static int ads7846_resume(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
+ spin_lock_irq(&ts->lock);
+
spi->dev.power.power_state = PMSG_ON;
+ ads7846_enable(ts);
+
+ spin_unlock_irq(&ts->lock);
+
return 0;
}
@@ -408,6 +587,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
struct ads7846 *ts;
struct input_dev *input_dev;
struct ads7846_platform_data *pdata = spi->dev.platform_data;
+ struct spi_message *m;
struct spi_transfer *x;
int err;
@@ -428,11 +608,20 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return -EINVAL;
}
- /* We'd set the wordsize to 12 bits ... except that some controllers
- * will then treat the 8 bit command words as 12 bits (and drop the
- * four MSBs of the 12 bit result). Result: inputs must be shifted
- * to discard the four garbage LSBs.
+ /* REVISIT when the irq can be triggered active-low, or if for some
+ * reason the touchscreen isn't hooked up, we don't need to access
+ * the pendown state.
*/
+ if (pdata->get_pendown_state == NULL) {
+ dev_dbg(&spi->dev, "no get_pendown_state function?\n");
+ return -EINVAL;
+ }
+
+ /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
+ * that even if the hardware can do that, the SPI controller driver
+ * may not. So we stick to very-portable 8 bit words, both RX and TX.
+ */
+ spi->bits_per_word = 8;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -451,9 +640,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->timer.data = (unsigned long) ts;
ts->timer.function = ads7846_timer;
+ spin_lock_init(&ts->lock);
+
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+ ts->pressure_max = pdata->pressure_max ? : ~0;
+ if (pdata->debounce_max) {
+ ts->debounce_max = pdata->debounce_max;
+ ts->debounce_tol = pdata->debounce_tol;
+ ts->debounce_rep = pdata->debounce_rep;
+ if (ts->debounce_rep > ts->debounce_max + 1)
+ ts->debounce_rep = ts->debounce_max - 1;
+ } else
+ ts->debounce_tol = ~0;
+ ts->get_pendown_state = pdata->get_pendown_state;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -477,64 +678,104 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
- INIT_LIST_HEAD(&ts->msg.transfers);
+ m = &ts->msg[0];
x = ts->xfer;
+ spi_message_init(m);
+
/* y- still on; turn on only y+ (and ADC) */
ts->read_y = READ_Y;
x->tx_buf = &ts->read_y;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.y;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
+
+ m++;
+ spi_message_init(m);
+
+ /* turn y- off, x+ on, then leave in lowpower */
+ x++;
+ ts->read_x = READ_X;
+ x->tx_buf = &ts->read_x;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.x;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
/* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) {
+ m++;
+ spi_message_init(m);
+
x++;
ts->read_z1 = READ_Z1;
x->tx_buf = &ts->read_z1;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z1;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
+
+ m++;
+ spi_message_init(m);
x++;
ts->read_z2 = READ_Z2;
x->tx_buf = &ts->read_z2;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z2;
x->len = 2;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_debounce;
+ m->context = ts;
}
- /* turn y- off, x+ on, then leave in lowpower */
+ /* power down */
+ m++;
+ spi_message_init(m);
+
x++;
- ts->read_x = READ_X;
- x->tx_buf = &ts->read_x;
+ ts->pwrdown = PWRDOWN;
+ x->tx_buf = &ts->pwrdown;
x->len = 1;
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
x++;
- x->rx_buf = &ts->tc.x;
+ x->rx_buf = &ts->dummy;
x->len = 2;
CS_CHANGE(*x);
- spi_message_add_tail(x, &ts->msg);
+ spi_message_add_tail(x, m);
+
+ m->complete = ads7846_rx;
+ m->context = ts;
- ts->msg.complete = ads7846_rx;
- ts->msg.context = ts;
+ ts->last_msg = m;
if (request_irq(spi->irq, ads7846_irq,
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
- spi->dev.bus_id, ts)) {
+ spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
goto err_free_mem;
@@ -559,13 +800,27 @@ static int __devinit ads7846_probe(struct spi_device *spi)
device_create_file(&spi->dev, &dev_attr_vbatt);
device_create_file(&spi->dev, &dev_attr_vaux);
+ device_create_file(&spi->dev, &dev_attr_pen_down);
+
+ device_create_file(&spi->dev, &dev_attr_disable);
+
err = input_register_device(input_dev);
if (err)
- goto err_free_irq;
+ goto err_remove_attr;
return 0;
- err_free_irq:
+ err_remove_attr:
+ device_remove_file(&spi->dev, &dev_attr_disable);
+ device_remove_file(&spi->dev, &dev_attr_pen_down);
+ if (ts->model == 7846) {
+ device_remove_file(&spi->dev, &dev_attr_temp1);
+ device_remove_file(&spi->dev, &dev_attr_temp0);
+ }
+ if (ts->model != 7845)
+ device_remove_file(&spi->dev, &dev_attr_vbatt);
+ device_remove_file(&spi->dev, &dev_attr_vaux);
+
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
@@ -577,20 +832,24 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ input_unregister_device(ts->input);
+
ads7846_suspend(spi, PMSG_SUSPEND);
- free_irq(ts->spi->irq, ts);
- if (ts->irq_disabled)
- enable_irq(ts->spi->irq);
+ device_remove_file(&spi->dev, &dev_attr_disable);
+ device_remove_file(&spi->dev, &dev_attr_pen_down);
if (ts->model == 7846) {
- device_remove_file(&spi->dev, &dev_attr_temp0);
device_remove_file(&spi->dev, &dev_attr_temp1);
+ device_remove_file(&spi->dev, &dev_attr_temp0);
}
if (ts->model != 7845)
device_remove_file(&spi->dev, &dev_attr_vbatt);
device_remove_file(&spi->dev, &dev_attr_vaux);
- input_unregister_device(ts->input);
+ free_irq(ts->spi->irq, ts);
+ /* suspend left the IRQ disabled */
+ enable_irq(ts->spi->irq);
+
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 1042987856f7..5013703db0e6 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/irq.h>
+//#include <asm/irq.h>
#include <asm/arch/sharpsl.h>
#include <asm/arch/hardware.h>
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 9b493f0becc4..173c899a1fb4 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1499,7 +1499,6 @@ static int __init capi_init(void)
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
return major_ret;
}
- capi_major = major_ret;
capi_class = class_create(THIS_MODULE, "capi");
if (IS_ERR(capi_class)) {
unregister_chrdev(capi_major, "capi20");
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index f86ed6af3aa2..eb41aba3ddef 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -5,8 +5,6 @@
* Tilman Schmidt <tilman@imap.cc>,
* Stefan Eilers.
*
- * Based on usb-gigaset.c.
- *
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -46,19 +44,20 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_DEVFSNAME "gig/bas/"
#define GIGASET_DEVNAME "ttyGB"
-#define IF_WRITEBUF 256 //FIXME
+/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
+#define IF_WRITEBUF 264
/* Values for the Gigaset 307x */
#define USB_GIGA_VENDOR_ID 0x0681
-#define USB_GIGA_PRODUCT_ID 0x0001
-#define USB_4175_PRODUCT_ID 0x0002
+#define USB_3070_PRODUCT_ID 0x0001
+#define USB_3075_PRODUCT_ID 0x0002
#define USB_SX303_PRODUCT_ID 0x0021
#define USB_SX353_PRODUCT_ID 0x0022
/* table of devices that work with this driver */
static struct usb_device_id gigaset_table [] = {
- { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) },
- { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) },
+ { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) },
+ { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) },
{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) },
{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) },
{ } /* Terminating entry */
@@ -77,6 +76,10 @@ static int gigaset_probe(struct usb_interface *interface,
/* Function will be called if the device is unplugged */
static void gigaset_disconnect(struct usb_interface *interface);
+static void read_ctrl_callback(struct urb *, struct pt_regs *);
+static void stopurbs(struct bas_bc_state *);
+static int atwrite_submit(struct cardstate *, unsigned char *, int);
+static int start_cbsend(struct cardstate *);
/*==============================================================================*/
@@ -111,12 +114,14 @@ struct bas_cardstate {
};
/* status of direct USB connection to 307x base (bits in basstate) */
-#define BS_ATOPEN 0x001
-#define BS_B1OPEN 0x002
-#define BS_B2OPEN 0x004
-#define BS_ATREADY 0x008
-#define BS_INIT 0x010
-#define BS_ATTIMER 0x020
+#define BS_ATOPEN 0x001 /* AT channel open */
+#define BS_B1OPEN 0x002 /* B channel 1 open */
+#define BS_B2OPEN 0x004 /* B channel 2 open */
+#define BS_ATREADY 0x008 /* base ready for AT command */
+#define BS_INIT 0x010 /* base has signalled INIT_OK */
+#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */
+#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */
+#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */
static struct gigaset_driver *driver = NULL;
@@ -130,6 +135,47 @@ static struct usb_driver gigaset_usb_driver = {
.id_table = gigaset_table,
};
+/* get message text for usb_submit_urb return code
+ */
+static char *get_usb_rcmsg(int rc)
+{
+ static char unkmsg[28];
+
+ switch (rc) {
+ case 0:
+ return "success";
+ case -ENOMEM:
+ return "out of memory";
+ case -ENODEV:
+ return "device not present";
+ case -ENOENT:
+ return "endpoint not present";
+ case -ENXIO:
+ return "URB type not supported";
+ case -EINVAL:
+ return "invalid argument";
+ case -EAGAIN:
+ return "start frame too early or too much scheduled";
+ case -EFBIG:
+ return "too many isochronous frames requested";
+ case -EPIPE:
+ return "endpoint stalled";
+ case -EMSGSIZE:
+ return "invalid packet size";
+ case -ENOSPC:
+ return "would overcommit USB bandwidth";
+ case -ESHUTDOWN:
+ return "device shut down";
+ case -EPERM:
+ return "reject flag set";
+ case -EHOSTUNREACH:
+ return "device suspended";
+ default:
+ snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", rc);
+ return unkmsg;
+ }
+}
+
/* get message text for USB status code
*/
static char *get_usb_statmsg(int status)
@@ -140,43 +186,37 @@ static char *get_usb_statmsg(int status)
case 0:
return "success";
case -ENOENT:
- return "canceled";
- case -ECONNRESET:
- return "canceled (async)";
+ return "unlinked (sync)";
case -EINPROGRESS:
return "pending";
case -EPROTO:
- return "bit stuffing or unknown USB error";
+ return "bit stuffing error, timeout, or unknown USB error";
case -EILSEQ:
- return "Illegal byte sequence (CRC mismatch)";
- case -EPIPE:
- return "babble detect or endpoint stalled";
- case -ENOSR:
- return "buffer error";
+ return "CRC mismatch, timeout, or unknown USB error";
case -ETIMEDOUT:
return "timed out";
- case -ENODEV:
- return "device not present";
+ case -EPIPE:
+ return "endpoint stalled";
+ case -ECOMM:
+ return "IN buffer overrun";
+ case -ENOSR:
+ return "OUT buffer underrun";
+ case -EOVERFLOW:
+ return "too much data";
case -EREMOTEIO:
return "short packet detected";
+ case -ENODEV:
+ return "device removed";
case -EXDEV:
return "partial isochronous transfer";
case -EINVAL:
return "invalid argument";
- case -ENXIO:
- return "URB already queued";
- case -EAGAIN:
- return "isochronous start frame too early or too much scheduled";
- case -EFBIG:
- return "too many isochronous frames requested";
- case -EMSGSIZE:
- return "endpoint message size zero";
+ case -ECONNRESET:
+ return "unlinked (async)";
case -ESHUTDOWN:
- return "endpoint shutdown";
- case -EBUSY:
- return "another request pending";
+ return "device shut down";
default:
- snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status);
+ snprintf(unkmsg, sizeof(unkmsg), "unknown status %d", status);
return unkmsg;
}
}
@@ -277,18 +317,17 @@ static inline void error_hangup(struct bc_state *bcs)
gig_dbg(DEBUG_ANY, "%s: scheduling HUP for channel %d",
__func__, bcs->channel);
- if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
- //FIXME what should we do?
- return;
- }
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL))
+ dev_err(cs->dev, "event queue full\n");
gigaset_schedule_event(cs);
}
/* error_reset
* reset Gigaset device because of an unrecoverable error
- * This function may be called from any context and takes care of scheduling
- * the necessary actions for execution outside of interrupt context.
+ * This function may be called from any context, and should take care of
+ * scheduling the necessary actions for execution outside of interrupt context.
+ * Right now, it just generates a kernel message calling for help.
* argument:
* controller state structure
*/
@@ -364,36 +403,38 @@ static void cmd_in_timeout(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
struct bas_cardstate *ucs = cs->hw.bas;
- unsigned long flags;
- spin_lock_irqsave(&cs->lock, flags);
- if (unlikely(!cs->connected)) {
- gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
- spin_unlock_irqrestore(&cs->lock, flags);
- return;
- }
if (!ucs->rcvbuf_size) {
gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
- spin_unlock_irqrestore(&cs->lock, flags);
return;
}
- spin_unlock_irqrestore(&cs->lock, flags);
dev_err(cs->dev, "timeout reading AT response\n");
error_reset(cs); //FIXME retry?
}
+/* set/clear bits in base connection state, return previous state
+ */
+inline static int update_basstate(struct bas_cardstate *ucs,
+ int set, int clear)
+{
+ unsigned long flags;
+ int state;
-static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs);
+ spin_lock_irqsave(&ucs->lock, flags);
+ state = atomic_read(&ucs->basstate);
+ atomic_set(&ucs->basstate, (state & ~clear) | set);
+ spin_unlock_irqrestore(&ucs->lock, flags);
+ return state;
+}
/* atread_submit
- * submit an HD_READ_ATMESSAGE command URB
+ * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout
* parameters:
* cs controller state structure
* timeout timeout in 1/10 sec., 0: none
* return value:
* 0 on success
- * -EINVAL if a NULL pointer is encountered somewhere
* -EBUSY if another request is pending
* any URB submission error code
*/
@@ -405,7 +446,7 @@ static int atread_submit(struct cardstate *cs, int timeout)
gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
ucs->rcvbuf_size);
- if (ucs->urb_cmd_in->status == -EINPROGRESS) {
+ if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) {
dev_err(cs->dev,
"could not submit HD_READ_ATMESSAGE: URB busy\n");
return -EBUSY;
@@ -423,6 +464,7 @@ static int atread_submit(struct cardstate *cs, int timeout)
read_ctrl_callback, cs->inbuf);
if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
+ update_basstate(ucs, 0, BS_ATRDPEND);
dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
get_usb_statmsg(ret));
return ret;
@@ -438,26 +480,6 @@ static int atread_submit(struct cardstate *cs, int timeout)
return 0;
}
-static void stopurbs(struct bas_bc_state *);
-static int start_cbsend(struct cardstate *);
-
-/* set/clear bits in base connection state
- */
-inline static void update_basstate(struct bas_cardstate *ucs,
- int set, int clear)
-{
- unsigned long flags;
- int state;
-
- spin_lock_irqsave(&ucs->lock, flags);
- state = atomic_read(&ucs->basstate);
- state &= ~clear;
- state |= set;
- atomic_set(&ucs->basstate, state);
- spin_unlock_irqrestore(&ucs->lock, flags);
-}
-
-
/* read_int_callback
* USB completion handler for interrupt pipe input
* called by the USB subsystem in interrupt context
@@ -471,20 +493,25 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
struct bas_cardstate *ucs = cs->hw.bas;
struct bc_state *bcs;
unsigned long flags;
- int status;
+ int rc;
unsigned l;
int channel;
switch (urb->status) {
case 0: /* success */
break;
- case -ENOENT: /* canceled */
- case -ECONNRESET: /* canceled (async) */
+ case -ENOENT: /* cancelled */
+ case -ECONNRESET: /* cancelled (async) */
case -EINPROGRESS: /* pending */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
__func__, get_usb_statmsg(urb->status));
return;
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
+ //FIXME use this as disconnect indicator?
+ gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__);
+ return;
default: /* severe trouble */
dev_warn(cs->dev, "interrupt read: %s\n",
get_usb_statmsg(urb->status));
@@ -492,6 +519,13 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
+ /* drop incomplete packets even if the missing bytes wouldn't matter */
+ if (unlikely(urb->actual_length < 3)) {
+ dev_warn(cs->dev, "incomplete interrupt packet (%d bytes)\n",
+ urb->actual_length);
+ goto resubmit;
+ }
+
l = (unsigned) ucs->int_in_buf[1] +
(((unsigned) ucs->int_in_buf[2]) << 8);
@@ -558,25 +592,28 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
}
spin_lock_irqsave(&cs->lock, flags);
if (ucs->rcvbuf_size) {
- spin_unlock_irqrestore(&cs->lock, flags);
+ /* throw away previous buffer - we have no queue */
dev_err(cs->dev,
- "receive AT data overrun, %d bytes lost\n", l);
- error_reset(cs); //FIXME reschedule
- break;
+ "receive AT data overrun, %d bytes lost\n",
+ ucs->rcvbuf_size);
+ kfree(ucs->rcvbuf);
+ ucs->rcvbuf_size = 0;
}
if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) {
spin_unlock_irqrestore(&cs->lock, flags);
- dev_err(cs->dev, "out of memory, %d bytes lost\n", l);
- error_reset(cs); //FIXME reschedule
+ dev_err(cs->dev, "out of memory receiving AT data\n");
+ error_reset(cs);
break;
}
ucs->rcvbuf_size = l;
ucs->retry_cmd_in = 0;
- if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) {
+ if ((rc = atread_submit(cs, BAS_TIMEOUT)) < 0) {
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- error_reset(cs); //FIXME reschedule
+ if (rc != -ENODEV)
+ //FIXME corrective action?
+ error_reset(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
@@ -598,12 +635,10 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
check_pending(ucs);
resubmit:
- spin_lock_irqsave(&cs->lock, flags);
- status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
- spin_unlock_irqrestore(&cs->lock, flags);
- if (unlikely(status)) {
+ rc = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (unlikely(rc != 0 && rc != -ENODEV)) {
dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
- get_usb_statmsg(status));
+ get_usb_rcmsg(rc));
error_reset(cs);
}
}
@@ -622,18 +657,12 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
struct bas_cardstate *ucs = cs->hw.bas;
int have_data = 0;
unsigned numbytes;
- unsigned long flags;
+ int rc;
- spin_lock_irqsave(&cs->lock, flags);
- if (unlikely(!cs->connected)) {
- warn("%s: disconnected", __func__);
- spin_unlock_irqrestore(&cs->lock, flags);
- return;
- }
+ update_basstate(ucs, 0, BS_ATRDPEND);
if (!ucs->rcvbuf_size) {
dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
- spin_unlock_irqrestore(&cs->lock, flags);
return;
}
@@ -666,9 +695,11 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
}
break;
- case -ENOENT: /* canceled */
- case -ECONNRESET: /* canceled (async) */
+ case -ENOENT: /* cancelled */
+ case -ECONNRESET: /* cancelled (async) */
case -EINPROGRESS: /* pending */
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
/* no action necessary */
gig_dbg(DEBUG_USBREQ, "%s: %s",
__func__, get_usb_statmsg(urb->status));
@@ -681,11 +712,11 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
if (ucs->retry_cmd_in++ < BAS_RETRY) {
dev_notice(cs->dev, "control read: retry %d\n",
ucs->retry_cmd_in);
- if (atread_submit(cs, BAS_TIMEOUT) >= 0) {
- /* resubmitted - bypass regular exit block */
- spin_unlock_irqrestore(&cs->lock, flags);
+ rc = atread_submit(cs, BAS_TIMEOUT);
+ if (rc >= 0 || rc == -ENODEV)
+ /* resubmitted or disconnected */
+ /* - bypass regular exit block */
return;
- }
} else {
dev_err(cs->dev,
"control read: giving up after %d tries\n",
@@ -697,7 +728,6 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- spin_unlock_irqrestore(&cs->lock, flags);
if (have_data) {
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(cs);
@@ -719,8 +749,11 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
int i, rc;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS)) {
+ if (unlikely(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -EINPROGRESS ||
+ urb->status == -ENODEV ||
+ urb->status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
__func__, get_usb_statmsg(urb->status));
return;
@@ -740,9 +773,9 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
for (i = 0; i < BAS_NUMFRAMES; i++) {
ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
if (unlikely(urb->iso_frame_desc[i].status != 0 &&
- urb->iso_frame_desc[i].status != -EINPROGRESS)) {
+ urb->iso_frame_desc[i].status !=
+ -EINPROGRESS))
ubc->loststatus = urb->iso_frame_desc[i].status;
- }
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
@@ -754,10 +787,10 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit",
__func__);
rc = usb_submit_urb(urb, SLAB_ATOMIC);
- if (unlikely(rc != 0)) {
+ if (unlikely(rc != 0 && rc != -ENODEV)) {
dev_err(bcs->cs->dev,
"could not resubmit isochronous read "
- "URB: %s\n", get_usb_statmsg(rc));
+ "URB: %s\n", get_usb_rcmsg(rc));
dump_urb(DEBUG_ISO, "isoc read", urb);
error_hangup(bcs);
}
@@ -780,8 +813,11 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
unsigned long flags;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS)) {
+ if (unlikely(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -EINPROGRESS ||
+ urb->status == -ENODEV ||
+ urb->status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
__func__, get_usb_statmsg(urb->status));
return;
@@ -822,7 +858,6 @@ static int starturbs(struct bc_state *bcs)
for (k = 0; k < BAS_INURBS; k++) {
urb = ubc->isoinurbs[k];
if (!urb) {
- dev_err(bcs->cs->dev, "isoinurbs[%d]==NULL\n", k);
rc = -EFAULT;
goto error;
}
@@ -844,12 +879,8 @@ static int starturbs(struct bc_state *bcs)
}
dump_urb(DEBUG_ISO, "Initial isoc read", urb);
- if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
- dev_err(bcs->cs->dev,
- "could not submit isochronous read URB %d: %s\n",
- k, get_usb_statmsg(rc));
+ if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0)
goto error;
- }
}
/* initialize L2 transmission */
@@ -859,7 +890,6 @@ static int starturbs(struct bc_state *bcs)
for (k = 0; k < BAS_OUTURBS; ++k) {
urb = ubc->isoouturbs[k].urb;
if (!urb) {
- dev_err(bcs->cs->dev, "isoouturbs[%d].urb==NULL\n", k);
rc = -EFAULT;
goto error;
}
@@ -885,12 +915,8 @@ static int starturbs(struct bc_state *bcs)
for (k = 0; k < 2; ++k) {
dump_urb(DEBUG_ISO, "Initial isoc write", urb);
rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC);
- if (rc != 0) {
- dev_err(bcs->cs->dev,
- "could not submit isochronous write URB %d: %s\n",
- k, get_usb_statmsg(rc));
+ if (rc != 0)
goto error;
- }
}
dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
ubc->isooutfree = &ubc->isoouturbs[2];
@@ -916,15 +942,15 @@ static void stopurbs(struct bas_bc_state *ubc)
for (k = 0; k < BAS_INURBS; ++k) {
rc = usb_unlink_urb(ubc->isoinurbs[k]);
gig_dbg(DEBUG_ISO,
- "%s: isoc input URB %d unlinked, result = %d",
- __func__, k, rc);
+ "%s: isoc input URB %d unlinked, result = %s",
+ __func__, k, get_usb_rcmsg(rc));
}
for (k = 0; k < BAS_OUTURBS; ++k) {
rc = usb_unlink_urb(ubc->isoouturbs[k].urb);
gig_dbg(DEBUG_ISO,
- "%s: isoc output URB %d unlinked, result = %d",
- __func__, k, rc);
+ "%s: isoc output URB %d unlinked, result = %s",
+ __func__, k, get_usb_rcmsg(rc));
}
}
@@ -934,7 +960,7 @@ static void stopurbs(struct bas_bc_state *ubc)
/* submit_iso_write_urb
* fill and submit the next isochronous write URB
* parameters:
- * bcs B channel state structure
+ * ucx context structure containing URB
* return value:
* number of frames submitted in URB
* 0 if URB not submitted because no data available (isooutbuf busy)
@@ -946,7 +972,6 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
struct bas_bc_state *ubc = ucx->bcs->hw.bas;
struct usb_iso_packet_descriptor *ifd;
int corrbytes, nframe, rc;
- unsigned long flags;
/* urb->dev is clobbered by USB subsystem */
urb->dev = ucx->bcs->cs->hw.bas->udev;
@@ -992,20 +1017,22 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
ifd->status = 0;
ifd->actual_length = 0;
}
- if ((urb->number_of_packets = nframe) > 0) {
- spin_lock_irqsave(&ucx->bcs->cs->lock, flags);
- rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
- spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags);
+ if (unlikely(nframe == 0))
+ return 0; /* no data to send */
+ urb->number_of_packets = nframe;
- if (rc) {
+ rc = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (unlikely(rc)) {
+ if (rc == -ENODEV)
+ /* device removed - give up silently */
+ gig_dbg(DEBUG_ISO, "%s: disconnected", __func__);
+ else
dev_err(ucx->bcs->cs->dev,
"could not submit isochronous write URB: %s\n",
- get_usb_statmsg(rc));
- dump_urb(DEBUG_ISO, "isoc write", urb);
- return rc;
- }
- ++ubc->numsub;
+ get_usb_rcmsg(rc));
+ return rc;
}
+ ++ubc->numsub;
return nframe;
}
@@ -1028,6 +1055,7 @@ static void write_iso_tasklet(unsigned long data)
int i;
struct sk_buff *skb;
int len;
+ int rc;
/* loop while completed URBs arrive in time */
for (;;) {
@@ -1057,7 +1085,8 @@ static void write_iso_tasklet(unsigned long data)
ubc->isooutfree = NULL;
spin_unlock_irqrestore(&ubc->isooutlock, flags);
if (next) {
- if (submit_iso_write_urb(next) <= 0) {
+ rc = submit_iso_write_urb(next);
+ if (unlikely(rc <= 0 && rc != -ENODEV)) {
/* could not submit URB, put it back */
spin_lock_irqsave(&ubc->isooutlock, flags);
if (ubc->isooutfree == NULL) {
@@ -1077,17 +1106,18 @@ static void write_iso_tasklet(unsigned long data)
/* process completed URB */
urb = done->urb;
switch (urb->status) {
+ case -EXDEV: /* partial completion */
+ gig_dbg(DEBUG_ISO, "%s: URB partially completed",
+ __func__);
+ /* fall through - what's the difference anyway? */
case 0: /* normal completion */
- break;
- case -EXDEV: /* inspect individual frames */
- /* assumptions (for lack of documentation):
- * - actual_length bytes of the frame in error are
+ /* inspect individual frames
+ * assumptions (for lack of documentation):
+ * - actual_length bytes of first frame in error are
* successfully sent
* - all following frames are not sent at all
*/
- gig_dbg(DEBUG_ISO, "%s: URB partially completed",
- __func__);
- offset = done->limit; /* just in case */
+ offset = done->limit; /* default (no error) */
for (i = 0; i < BAS_NUMFRAMES; i++) {
ifd = &urb->iso_frame_desc[i];
if (ifd->status ||
@@ -1122,7 +1152,7 @@ static void write_iso_tasklet(unsigned long data)
}
#endif
break;
- case -EPIPE: //FIXME is this the code for "underrun"?
+ case -EPIPE: /* stall - probably underrun */
dev_err(cs->dev, "isochronous write stalled\n");
error_hangup(bcs);
break;
@@ -1142,7 +1172,8 @@ static void write_iso_tasklet(unsigned long data)
spin_unlock_irqrestore(&ubc->isooutlock, flags);
if (next) {
/* only one URB still active - resubmit one */
- if (submit_iso_write_urb(next) <= 0) {
+ rc = submit_iso_write_urb(next);
+ if (unlikely(rc <= 0 && rc != -ENODEV)) {
/* couldn't submit */
error_hangup(bcs);
}
@@ -1222,10 +1253,9 @@ static void read_iso_tasklet(unsigned long data)
break;
case -ENOENT:
case -ECONNRESET:
- gig_dbg(DEBUG_ISO, "%s: URB canceled", __func__);
- continue; /* -> skip */
- case -EINPROGRESS: /* huh? */
- gig_dbg(DEBUG_ISO, "%s: URB still pending", __func__);
+ case -EINPROGRESS:
+ gig_dbg(DEBUG_ISO, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
continue; /* -> skip */
case -EPIPE:
dev_err(cs->dev, "isochronous read stalled\n");
@@ -1290,13 +1320,11 @@ static void read_iso_tasklet(unsigned long data)
urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
urb->number_of_packets = BAS_NUMFRAMES;
- spin_lock_irqsave(&cs->lock, flags);
- rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
- spin_unlock_irqrestore(&cs->lock, flags);
- if (rc) {
+ rc = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (unlikely(rc != 0 && rc != -ENODEV)) {
dev_err(cs->dev,
"could not resubmit isochronous read URB: %s\n",
- get_usb_statmsg(rc));
+ get_usb_rcmsg(rc));
dump_urb(DEBUG_ISO, "resubmit iso read", urb);
error_hangup(bcs);
}
@@ -1397,7 +1425,6 @@ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
* timeout timeout in seconds (0: no timeout)
* return value:
* 0 on success
- * -EINVAL if a NULL pointer is encountered somewhere
* -EBUSY if another request is pending
* any URB submission error code
*/
@@ -1418,12 +1445,6 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
req, ucs->pending);
return -EBUSY;
}
- if (ucs->urb_ctrl->status == -EINPROGRESS) {
- spin_unlock_irqrestore(&ucs->lock, flags);
- dev_err(bcs->cs->dev,
- "could not submit request 0x%02x: URB busy\n", req);
- return -EBUSY;
- }
ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ;
ucs->dr_ctrl.bRequest = req;
@@ -1465,22 +1486,36 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
static int gigaset_init_bchannel(struct bc_state *bcs)
{
int req, ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcs->cs->lock, flags);
+ if (unlikely(!bcs->cs->connected)) {
+ gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ return -ENODEV;
+ }
if ((ret = starturbs(bcs)) < 0) {
dev_err(bcs->cs->dev,
- "could not start isochronous I/O for channel %d\n",
- bcs->channel + 1);
- error_hangup(bcs);
+ "could not start isochronous I/O for channel B%d: %s\n",
+ bcs->channel + 1,
+ ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
+ if (ret != -ENODEV)
+ error_hangup(bcs);
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
return ret;
}
req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
- dev_err(bcs->cs->dev, "could not open channel %d: %s\n",
- bcs->channel + 1, get_usb_statmsg(ret));
+ dev_err(bcs->cs->dev, "could not open channel B%d\n",
+ bcs->channel + 1);
stopurbs(bcs->hw.bas);
- error_hangup(bcs);
+ if (ret != -ENODEV)
+ error_hangup(bcs);
}
+
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
return ret;
}
@@ -1497,19 +1532,30 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
static int gigaset_close_bchannel(struct bc_state *bcs)
{
int req, ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcs->cs->lock, flags);
+ if (unlikely(!bcs->cs->connected)) {
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
+ return -ENODEV;
+ }
if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
(bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
/* channel not running: just signal common.c */
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
gigaset_bchannel_down(bcs);
return 0;
}
+ /* channel running: tell device to close it */
req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
- dev_err(bcs->cs->dev,
- "could not submit HD_CLOSE_BxCHANNEL request: %s\n",
- get_usb_statmsg(ret));
+ dev_err(bcs->cs->dev, "closing channel B%d failed\n",
+ bcs->channel + 1);
+
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
return ret;
}
@@ -1545,8 +1591,6 @@ static void complete_cb(struct cardstate *cs)
kfree(cb);
}
-static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len);
-
/* write_command_callback
* USB completion handler for AT command transmission
* called by the USB subsystem in interrupt context
@@ -1560,13 +1604,17 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs)
struct bas_cardstate *ucs = cs->hw.bas;
unsigned long flags;
+ update_basstate(ucs, 0, BS_ATWRPEND);
+
/* check status */
switch (urb->status) {
case 0: /* normal completion */
break;
- case -ENOENT: /* canceled */
- case -ECONNRESET: /* canceled (async) */
+ case -ENOENT: /* cancelled */
+ case -ECONNRESET: /* cancelled (async) */
case -EINPROGRESS: /* pending */
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
__func__, get_usb_statmsg(urb->status));
@@ -1627,19 +1675,17 @@ static void atrdy_timeout(unsigned long data)
* len length of command to send
* return value:
* 0 on success
- * -EFAULT if a NULL pointer is encountered somewhere
* -EBUSY if another request is pending
* any URB submission error code
*/
static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
{
struct bas_cardstate *ucs = cs->hw.bas;
- unsigned long flags;
- int ret;
+ int rc;
gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
- if (ucs->urb_cmd_out->status == -EINPROGRESS) {
+ if (update_basstate(ucs, BS_ATWRPEND, 0) & BS_ATWRPEND) {
dev_err(cs->dev,
"could not submit HD_WRITE_ATMESSAGE: URB busy\n");
return -EBUSY;
@@ -1654,29 +1700,22 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
usb_sndctrlpipe(ucs->udev, 0),
(unsigned char*) &ucs->dr_cmd_out, buf, len,
write_command_callback, cs);
-
- spin_lock_irqsave(&cs->lock, flags);
- ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV;
- spin_unlock_irqrestore(&cs->lock, flags);
-
- if (ret) {
+ rc = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC);
+ if (unlikely(rc)) {
+ update_basstate(ucs, 0, BS_ATWRPEND);
dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n",
- get_usb_statmsg(ret));
- return ret;
+ get_usb_rcmsg(rc));
+ return rc;
}
- /* submitted successfully */
- update_basstate(ucs, 0, BS_ATREADY);
-
- /* start timeout if necessary */
- if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) {
+ /* submitted successfully, start timeout if necessary */
+ if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) {
gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs",
ATRDY_TIMEOUT);
ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10;
ucs->timer_atrdy.data = (unsigned long) cs;
ucs->timer_atrdy.function = atrdy_timeout;
add_timer(&ucs->timer_atrdy);
- update_basstate(ucs, BS_ATTIMER, 0);
}
return 0;
}
@@ -1702,7 +1741,6 @@ static int start_cbsend(struct cardstate *cs)
gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
if (rc < 0) {
- dev_err(cs->dev, "could not open AT channel\n");
/* flush command queue */
spin_lock_irqsave(&cs->cmdlock, flags);
while (cs->cmdbuf != NULL)
@@ -1786,8 +1824,14 @@ static int gigaset_write_cmd(struct cardstate *cs,
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (unlikely(!cs->connected)) {
+ spin_unlock_irqrestore(&cs->lock, flags);
+ gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
+ return -ENODEV;
+ }
status = start_cbsend(cs);
-
+ spin_unlock_irqrestore(&cs->lock, flags);
return status < 0 ? status : len;
}
@@ -1849,12 +1893,32 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
*/
static int gigaset_freebcshw(struct bc_state *bcs)
{
- if (!bcs->hw.bas)
+ struct bas_bc_state *ubc = bcs->hw.bas;
+ int i;
+
+ if (!ubc)
return 0;
- if (bcs->hw.bas->isooutbuf)
- kfree(bcs->hw.bas->isooutbuf);
- kfree(bcs->hw.bas);
+ /* kill URBs and tasklets before freeing - better safe than sorry */
+ atomic_set(&ubc->running, 0);
+ for (i = 0; i < BAS_OUTURBS; ++i)
+ if (ubc->isoouturbs[i].urb) {
+ gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d",
+ __func__, i);
+ usb_kill_urb(ubc->isoouturbs[i].urb);
+ usb_free_urb(ubc->isoouturbs[i].urb);
+ }
+ for (i = 0; i < BAS_INURBS; ++i)
+ if (ubc->isoinurbs[i]) {
+ gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d",
+ __func__, i);
+ usb_kill_urb(ubc->isoinurbs[i]);
+ usb_free_urb(ubc->isoinurbs[i]);
+ }
+ tasklet_kill(&ubc->sent_tasklet);
+ tasklet_kill(&ubc->rcvd_tasklet);
+ kfree(ubc->isooutbuf);
+ kfree(ubc);
bcs->hw.bas = NULL;
return 1;
}
@@ -1931,13 +1995,9 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
static void gigaset_freecshw(struct cardstate *cs)
{
- struct bas_cardstate *ucs = cs->hw.bas;
-
- del_timer(&ucs->timer_ctrl);
- del_timer(&ucs->timer_atrdy);
- del_timer(&ucs->timer_cmd_in);
-
+ /* timers, URBs and rcvbuf are disposed of in disconnect */
kfree(cs->hw.bas);
+ cs->hw.bas = NULL;
}
static int gigaset_initcshw(struct cardstate *cs)
@@ -2041,23 +2101,13 @@ static int gigaset_probe(struct usb_interface *interface,
struct bas_bc_state *ubc;
struct usb_endpoint_descriptor *endpoint;
int i, j;
- int ret;
+ int rc;
gig_dbg(DEBUG_ANY,
"%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
__func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- /* See if the device offered us matches what we can accept */
- if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) ||
- (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID &&
- le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID &&
- le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID &&
- le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) {
- gig_dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__);
- return -ENODEV;
- }
-
/* set required alternate setting */
hostif = interface->cur_altsetting;
if (hostif->desc.bAlternateSetting != 3) {
@@ -2105,45 +2155,22 @@ static int gigaset_probe(struct usb_interface *interface,
* - three for the different uses of the default control pipe
* - three for each isochronous pipe
*/
- ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL);
- if (!ucs->urb_int_in) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
- ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL);
- if (!ucs->urb_cmd_in) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
- ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL);
- if (!ucs->urb_cmd_out) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
- ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL);
- if (!ucs->urb_ctrl) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
+ if (!(ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL)) ||
+ !(ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL)) ||
+ !(ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL)) ||
+ !(ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL)))
+ goto allocerr;
for (j = 0; j < 2; ++j) {
ubc = cs->bcs[j].hw.bas;
- for (i = 0; i < BAS_OUTURBS; ++i) {
- ubc->isoouturbs[i].urb =
- usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
- if (!ubc->isoouturbs[i].urb) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
- }
- for (i = 0; i < BAS_INURBS; ++i) {
- ubc->isoinurbs[i] =
- usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
- if (!ubc->isoinurbs[i]) {
- dev_err(cs->dev, "no free urbs available\n");
- goto error;
- }
- }
+ for (i = 0; i < BAS_OUTURBS; ++i)
+ if (!(ubc->isoouturbs[i].urb =
+ usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL)))
+ goto allocerr;
+ for (i = 0; i < BAS_INURBS; ++i)
+ if (!(ubc->isoinurbs[i] =
+ usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL)))
+ goto allocerr;
}
ucs->rcvbuf = NULL;
@@ -2156,15 +2183,14 @@ static int gigaset_probe(struct usb_interface *interface,
(endpoint->bEndpointAddress) & 0x0f),
ucs->int_in_buf, 3, read_int_callback, cs,
endpoint->bInterval);
- ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL);
- if (ret) {
+ if ((rc = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL)) != 0) {
dev_err(cs->dev, "could not submit interrupt URB: %s\n",
- get_usb_statmsg(ret));
+ get_usb_rcmsg(rc));
goto error;
}
/* tell the device that the driver is ready */
- if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0)
+ if ((rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0)
goto error;
/* tell common part that the device is ready */
@@ -2179,6 +2205,8 @@ static int gigaset_probe(struct usb_interface *interface,
return 0;
+allocerr:
+ dev_err(cs->dev, "could not allocate URBs\n");
error:
freeurbs(cs);
usb_set_intfdata(interface, NULL);
@@ -2193,19 +2221,34 @@ static void gigaset_disconnect(struct usb_interface *interface)
{
struct cardstate *cs;
struct bas_cardstate *ucs;
+ int j;
cs = usb_get_intfdata(interface);
ucs = cs->hw.bas;
dev_info(cs->dev, "disconnecting Gigaset base\n");
+
+ /* mark base as not ready, all channels disconnected */
+ atomic_set(&ucs->basstate, 0);
+
+ /* tell LL all channels are down */
+ //FIXME shouldn't gigaset_stop() do this?
+ for (j = 0; j < 2; ++j)
+ gigaset_bchannel_down(cs->bcs + j);
+
+ /* stop driver (common part) */
gigaset_stop(cs);
+
+ /* stop timers and URBs, free ressources */
+ del_timer_sync(&ucs->timer_ctrl);
+ del_timer_sync(&ucs->timer_atrdy);
+ del_timer_sync(&ucs->timer_cmd_in);
freeurbs(cs);
usb_set_intfdata(interface, NULL);
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- atomic_set(&ucs->basstate, 0);
usb_put_dev(ucs->udev);
ucs->interface = NULL;
ucs->udev = NULL;
@@ -2277,6 +2320,8 @@ error: if (cardstate)
*/
static void __exit bas_gigaset_exit(void)
{
+ struct bas_cardstate *ucs = cardstate->hw.bas;
+
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
@@ -2284,14 +2329,26 @@ static void __exit bas_gigaset_exit(void)
gigaset_shutdown(cardstate);
/* from now on, no isdn callback should be possible */
- if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) {
- gig_dbg(DEBUG_ANY, "closing AT channel");
- if (req_submit(cardstate->bcs,
- HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) {
- /* successfully submitted */
- //FIXME wait for completion?
- }
+ /* close all still open channels */
+ if (atomic_read(&ucs->basstate) & BS_B1OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B1 channel");
+ usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0,
+ NULL, 0, BAS_TIMEOUT);
+ }
+ if (atomic_read(&ucs->basstate) & BS_B2OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B2 channel");
+ usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0,
+ NULL, 0, BAS_TIMEOUT);
+ }
+ if (atomic_read(&ucs->basstate) & BS_ATOPEN) {
+ gig_dbg(DEBUG_INIT, "closing AT channel");
+ usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0,
+ NULL, 0, BAS_TIMEOUT);
}
+ atomic_set(&ucs->basstate, 0);
/* deregister this driver with the USB subsystem */
usb_deregister(&gigaset_usb_driver);
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 749b3da1236e..e55767b2ccd3 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -781,8 +781,7 @@ error: if (cs)
}
EXPORT_SYMBOL_GPL(gigaset_initcs);
-/* ReInitialize the b-channel structure */
-/* e.g. called on hangup, disconnect */
+/* ReInitialize the b-channel structure on hangup */
void gigaset_bcs_reinit(struct bc_state *bcs)
{
struct sk_buff *skb;
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 1ba3424a286b..18e05c09b71c 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -373,6 +373,9 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */
{EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}},
+ /* B channel closed (general case) */
+ {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME
+
/* misc. */
{EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 9d21ba8757b0..22b9693f7c0a 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -75,7 +75,7 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
* e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
* DEBUG_INTR.
*/
-enum debuglevel { /* up to 24 bits (atomic_t) */
+enum debuglevel {
DEBUG_REG = 0x0002, /* serial port I/O register operations */
DEBUG_OPEN = 0x0004, /* open/close serial port */
DEBUG_INTR = 0x0008, /* interrupt processing */
@@ -141,7 +141,7 @@ enum debuglevel { /* up to 24 bits (atomic_t) */
printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \
## arg); \
} while (0)
-#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
+#define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
#else
@@ -627,8 +627,7 @@ struct gigaset_ops {
/* Called by gigaset_freecs() for freeing bcs->hw.xxx */
int (*freebcshw)(struct bc_state *bcs);
- /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting
- bcs->hw.xxx */
+ /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */
void (*reinitbcshw)(struct bc_state *bcs);
/* Called by gigaset_initcs() for setting up cs->hw.xxx */
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 0815dbfb8291..1654fa413575 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -73,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
/* pass to device-specific module */
- return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly
+ return cs->ops->send_skb(bcs, skb);
}
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 45f017ed6e8c..8667daaa1a82 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -992,14 +992,18 @@ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
int len = skb->len;
unsigned long flags;
+ spin_lock_irqsave(&bcs->cs->lock, flags);
+ if (!bcs->cs->connected) {
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ return -ENODEV;
+ }
+
skb_queue_tail(&bcs->squeue, skb);
gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
__func__, skb_queue_len(&bcs->squeue));
/* tasklet submits URB if necessary */
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->cs->connected)
- tasklet_schedule(&bcs->hw.bas->sent_tasklet);
+ tasklet_schedule(&bcs->hw.bas->sent_tasklet);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return len; /* ok so far */
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index bfb73fd5077e..d86ab68114b0 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -710,8 +710,8 @@ static int gigaset_probe(struct usb_interface *interface,
retval = -ENODEV; //FIXME
/* See if the device offered us matches what we can accept */
- if ((le16_to_cpu(udev->descriptor.idVendor != USB_M105_VENDOR_ID)) ||
- (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID)))
+ if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) ||
+ (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
return -ENODEV;
/* this starts to become ascii art... */
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 3585fb1f3344..2ac90242d263 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -2880,7 +2880,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
p[0]++;
i = 0;
while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN))
+ (i < ISDN_LMSNLEN - 1))
m->lmsn[i++] = *p[0]++;
m->lmsn[i] = '\0';
break;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 3f5b64794542..626506234b76 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -4,8 +4,11 @@ menu "LED devices"
config NEW_LEDS
bool "LED Support"
help
- Say Y to enable Linux LED support. This is not related to standard
- keyboard LEDs which are controlled via the input system.
+ Say Y to enable Linux LED support. This allows control of supported
+ LEDs from both userspace and optionally, by kernel events (triggers).
+
+ This is not related to standard keyboard LEDs which are controlled
+ via the input system.
config LEDS_CLASS
tristate "LED Class Support"
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index b0b5d05fadd6..c75d0ef1609c 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -19,6 +19,7 @@
#include <linux/sysdev.h>
#include <linux/timer.h>
#include <linux/err.h>
+#include <linux/ctype.h>
#include <linux/leds.h>
#include "leds.h"
@@ -43,9 +44,13 @@ static ssize_t led_brightness_store(struct class_device *dev,
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
- if (after - buf > 0) {
- ret = after - buf;
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ ret = count;
led_set_brightness(led_cdev, state);
}
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index f484b5d6dbf8..fbf141ef46ec 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
+#include <linux/ctype.h>
#include <linux/leds.h>
#include "leds.h"
@@ -69,11 +70,15 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
int ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
- if (after - buf > 0) {
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
timer_data->delay_on = state;
mod_timer(&timer_data->timer, jiffies + 1);
- ret = after - buf;
+ ret = count;
}
return ret;
@@ -97,11 +102,15 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
int ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (*after && isspace(*after))
+ count++;
- if (after - buf > 0) {
+ if (count == size) {
timer_data->delay_off = state;
mod_timer(&timer_data->timer, jiffies + 1);
- ret = after - buf;
+ ret = count;
}
return ret;
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 5ebfd1d138da..5282fec17075 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -627,8 +627,8 @@ thermostat_init(void)
if(therm_type == ADT7460)
device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
-#ifndef CONFIG_I2C_KEYWEST
- request_module("i2c-keywest");
+#ifndef CONFIG_I2C_POWERMAC
+ request_module("i2c-powermac");
#endif
return i2c_add_driver(&thermostat_driver);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d7316b829a62..f19b874753a9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -167,6 +167,15 @@ void md_new_event(mddev_t *mddev)
}
EXPORT_SYMBOL_GPL(md_new_event);
+/* Alternate version that can be called from interrupts
+ * when calling sysfs_notify isn't needed.
+ */
+void md_new_event_inintr(mddev_t *mddev)
+{
+ atomic_inc(&md_event_count);
+ wake_up(&md_event_waiters);
+}
+
/*
* Enables to iterate over all existing md arrays
* all_mddevs_lock protects this list.
@@ -2252,7 +2261,7 @@ action_store(mddev_t *mddev, const char *page, size_t len)
} else {
if (cmd_match(page, "check"))
set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
- else if (cmd_match(page, "repair"))
+ else if (!cmd_match(page, "repair"))
return -EINVAL;
set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
@@ -4149,7 +4158,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
- md_new_event(mddev);
+ md_new_event_inintr(mddev);
}
/* seq_file implementation /proc/mdstat */
@@ -5028,8 +5037,10 @@ static int md_notify_reboot(struct notifier_block *this,
printk(KERN_INFO "md: stopping all md devices.\n");
ITERATE_MDDEV(mddev,tmp)
- if (mddev_trylock(mddev))
+ if (mddev_trylock(mddev)) {
do_md_stop (mddev, 1);
+ mddev_unlock(mddev);
+ }
/*
* certain more exotic SCSI devices are known to be
* volatile wrt too early system reboots. While the
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 678f4dbbea1d..cb8c6317e4e5 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -331,13 +331,14 @@ static int raid0_run (mddev_t *mddev)
goto out_free_conf;
size = conf->strip_zone[cur].size;
- for (i=0; i< nb_zone; i++) {
- conf->hash_table[i] = conf->strip_zone + cur;
+ conf->hash_table[0] = conf->strip_zone + cur;
+ for (i=1; i< nb_zone; i++) {
while (size <= conf->hash_spacing) {
cur++;
size += conf->strip_zone[cur].size;
}
size -= conf->hash_spacing;
+ conf->hash_table[i] = conf->strip_zone + cur;
}
if (conf->preshift) {
conf->hash_spacing >>= conf->preshift;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 6081941de1b3..4070eff6f0f8 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -315,10 +315,11 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
if (r1_bio->bios[mirror] == bio)
break;
- if (error == -ENOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) {
+ if (error == -EOPNOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) {
set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags);
set_bit(R1BIO_BarrierRetry, &r1_bio->state);
r1_bio->mddev->barriers_work = 0;
+ /* Don't rdev_dec_pending in this branch - keep it for the retry */
} else {
/*
* this branch is our 'one mirror IO has finished' event handler:
@@ -365,6 +366,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
}
}
}
+ rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
}
/*
*
@@ -374,11 +376,9 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
if (atomic_dec_and_test(&r1_bio->remaining)) {
if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
reschedule_retry(r1_bio);
- /* Don't dec_pending yet, we want to hold
- * the reference over the retry
- */
goto out;
}
+ /* it really is the end of this request */
if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
/* free extra copy of the data pages */
int i = bio->bi_vcnt;
@@ -393,8 +393,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
md_write_end(r1_bio->mddev);
raid_end_bio_io(r1_bio);
}
-
- rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
out:
if (to_put)
bio_put(to_put);
@@ -753,18 +751,24 @@ static int make_request(request_queue_t *q, struct bio * bio)
const int rw = bio_data_dir(bio);
int do_barriers;
- if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
- return 0;
- }
-
/*
* Register the new request and wait if the reconstruction
* thread has put up a bar for new requests.
* Continue immediately if no resync is active currently.
+ * We test barriers_work *after* md_write_start as md_write_start
+ * may cause the first superblock write, and that will check out
+ * if barriers work.
*/
+
md_write_start(mddev, bio); /* wait on superblock update early */
+ if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
+ if (rw == WRITE)
+ md_write_end(mddev);
+ bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ return 0;
+ }
+
wait_barrier(conf);
disk_stat_inc(mddev->gendisk, ios[rw]);
@@ -1404,10 +1408,11 @@ static void raid1d(mddev_t *mddev)
unplug = 1;
} else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
/* some requests in the r1bio were BIO_RW_BARRIER
- * requests which failed with -ENOTSUPP. Hohumm..
+ * requests which failed with -EOPNOTSUPP. Hohumm..
* Better resubmit without the barrier.
* We know which devices to resubmit for, because
* all others have had their bios[] entry cleared.
+ * We already have a nr_pending reference on these rdevs.
*/
int i;
clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 617012bc107a..1440935414e6 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1407,43 +1407,54 @@ static void raid10d(mddev_t *mddev)
if (s > (PAGE_SIZE>>9))
s = PAGE_SIZE >> 9;
+ rcu_read_lock();
do {
int d = r10_bio->devs[sl].devnum;
- rdev = conf->mirrors[d].rdev;
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
if (rdev &&
- test_bit(In_sync, &rdev->flags) &&
- sync_page_io(rdev->bdev,
- r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
- s<<9,
- conf->tmppage, READ))
- success = 1;
- else {
- sl++;
- if (sl == conf->copies)
- sl = 0;
+ test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ success = sync_page_io(rdev->bdev,
+ r10_bio->devs[sl].addr +
+ sect + rdev->data_offset,
+ s<<9,
+ conf->tmppage, READ);
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
+ if (success)
+ break;
}
+ sl++;
+ if (sl == conf->copies)
+ sl = 0;
} while (!success && sl != r10_bio->read_slot);
+ rcu_read_unlock();
if (success) {
int start = sl;
/* write it back and re-read */
+ rcu_read_lock();
while (sl != r10_bio->read_slot) {
int d;
if (sl==0)
sl = conf->copies;
sl--;
d = r10_bio->devs[sl].devnum;
- rdev = conf->mirrors[d].rdev;
- atomic_add(s, &rdev->corrected_errors);
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ atomic_add(s, &rdev->corrected_errors);
if (sync_page_io(rdev->bdev,
r10_bio->devs[sl].addr +
sect + rdev->data_offset,
s<<9, conf->tmppage, WRITE) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
}
}
sl = start;
@@ -1453,17 +1464,22 @@ static void raid10d(mddev_t *mddev)
sl = conf->copies;
sl--;
d = r10_bio->devs[sl].devnum;
- rdev = conf->mirrors[d].rdev;
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
if (sync_page_io(rdev->bdev,
r10_bio->devs[sl].addr +
sect + rdev->data_offset,
s<<9, conf->tmppage, READ) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
}
}
+ rcu_read_unlock();
} else {
/* Cannot read from anywhere -- bye bye array */
md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev);
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index fffc711c260c..344d83aae3ec 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -8,22 +8,54 @@ config VIDEO_DEV
tristate "Video For Linux"
---help---
Support for audio/video capture and overlay devices and FM radio
- cards. The exact capabilities of each device vary. User tools for
- this are available from
- <ftp://ftp.uk.linux.org/pub/linux/video4linux/>.
+ cards. The exact capabilities of each device vary.
This kernel includes support for the new Video for Linux Two API,
(V4L2) as well as the original system. Drivers and applications
need to be rewritten to use V4L2, but drivers for popular cards
and applications for most video capture functions already exist.
- Documentation for the original API is included in the file
- <file:Documentation/video4linux/API.html>. Documentation for V4L2 is
- available on the web at <http://bytesex.org/v4l/>.
+ Additional info and docs are available on the web at
+ <http://linuxtv.org>
+
+ Documentation for V4L2 is also available on the web at
+ <http://bytesex.org/v4l/>.
To compile this driver as a module, choose M here: the
module will be called videodev.
+config VIDEO_V4L1
+ boolean "Enable Video For Linux API 1 (DEPRECATED)"
+ depends on VIDEO_DEV
+ select VIDEO_V4L1_COMPAT
+ default y
+ ---help---
+ Enables a compatibility API used by most V4L2 devices to allow
+ its usage with legacy applications that supports only V4L1 api.
+
+ If you are unsure as to whether this is required, answer Y.
+
+config VIDEO_V4L1_COMPAT
+ boolean "Enable Video For Linux API 1 compatible Layer"
+ depends on VIDEO_DEV
+ default y
+ ---help---
+ This api were developed to be used at Kernel 2.2 and 2.4, but
+ lacks support for several video standards. There are several
+ drivers at kernel that still depends on it.
+
+ Documentation for the original API is included in the file
+ <Documentation/video4linux/API.html>.
+
+ User tools for this are available from
+ <ftp://ftp.uk.linux.org/pub/linux/video4linux/>.
+
+ If you are unsure as to whether this is required, answer Y.
+
+config VIDEO_V4L2
+ tristate
+ default y
+
source "drivers/media/video/Kconfig"
source "drivers/media/radio/Kconfig"
@@ -65,4 +97,3 @@ config USB_DABUSB
module will be called dabusb.
endmenu
-
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 6a901a0268e1..1a04db4552da 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,9 +1,10 @@
config VIDEO_SAA7146
tristate
- select I2C
+ depends on I2C
config VIDEO_SAA7146_VV
tristate
+ select VIDEO_V4L2
select VIDEO_BUF
select VIDEO_VIDEOBUF
select VIDEO_SAA7146
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 3f0ec6be03ae..a97c8f5e9a5d 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -22,26 +22,26 @@ config DVB
source "drivers/media/dvb/dvb-core/Kconfig"
comment "Supported SAA7146 based PCI Adapters"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/ttpci/Kconfig"
comment "Supported USB Adapters"
- depends on DVB_CORE && USB
+ depends on DVB_CORE && USB && I2C
source "drivers/media/dvb/dvb-usb/Kconfig"
source "drivers/media/dvb/ttusb-budget/Kconfig"
source "drivers/media/dvb/ttusb-dec/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig"
comment "Supported FlexCopII (B2C2) Adapters"
- depends on DVB_CORE && (PCI || USB)
+ depends on DVB_CORE && (PCI || USB) && I2C
source "drivers/media/dvb/b2c2/Kconfig"
comment "Supported BT878 Adapters"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/bt8xx/Kconfig"
comment "Supported Pluto2 Adapters"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/pluto2/Kconfig"
comment "Supported DVB Frontends"
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 2963605c0ecc..d7f1fd5b7b02 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,6 +1,6 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select DVB_STV0299
select DVB_MT352
select DVB_MT312
@@ -16,7 +16,7 @@ config DVB_B2C2_FLEXCOP
config DVB_B2C2_FLEXCOP_PCI
tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
- depends on DVB_B2C2_FLEXCOP && PCI
+ depends on DVB_B2C2_FLEXCOP && PCI && I2C
help
Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
@@ -24,7 +24,7 @@ config DVB_B2C2_FLEXCOP_PCI
config DVB_B2C2_FLEXCOP_USB
tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
- depends on DVB_B2C2_FLEXCOP && USB
+ depends on DVB_B2C2_FLEXCOP && USB && I2C
help
Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 376ca48f1d1d..f394002118f8 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,12 +1,13 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
- depends on DVB_CORE && PCI && VIDEO_BT848
+ depends on DVB_CORE && PCI && I2C && VIDEO_BT848
select DVB_MT352
select DVB_SP887X
select DVB_NXT6000
select DVB_CX24110
select DVB_OR51211
select DVB_LGDT330X
+ select DVB_ZL10353
select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index baa8227ef87c..ccc7b2eb4a2d 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -115,7 +115,7 @@ static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
return 0;
}
-static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
+static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
{
unsigned int card_nr;
@@ -709,7 +709,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
}
}
-static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
+static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
{
int result;
@@ -794,7 +794,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
return 0;
}
-static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
+static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
{
struct dvb_bt8xx_card *card;
struct pci_dev* bttv_pci_dev;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 71b575dc22bd..9325d039ea65 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -902,7 +902,10 @@ static int cinergyt2_probe (struct usb_interface *intf,
return -ENOMEM;
}
- dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE);
+ if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+ kfree(cinergyt2);
+ return err;
+ }
cinergyt2->demux.priv = cinergyt2;
cinergyt2->demux.filternum = 256;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 4f8f257e6795..a051790161b0 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -106,6 +106,8 @@ struct dvb_frontend_private {
unsigned long tune_mode_flags;
unsigned int delay;
unsigned int reinitialise;
+ int tone;
+ int voltage;
/* swzigzag values */
unsigned int state;
@@ -537,6 +539,12 @@ static int dvb_frontend_thread(void *data)
if (fepriv->reinitialise) {
dvb_frontend_init(fe);
+ if (fepriv->tone != -1) {
+ fe->ops->set_tone(fe, fepriv->tone);
+ }
+ if (fepriv->voltage != -1) {
+ fe->ops->set_voltage(fe, fepriv->voltage);
+ }
fepriv->reinitialise = 0;
}
@@ -788,6 +796,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_SET_TONE:
if (fe->ops->set_tone) {
err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+ fepriv->tone = (fe_sec_tone_mode_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -796,6 +805,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_SET_VOLTAGE:
if (fe->ops->set_voltage) {
err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+ fepriv->voltage = (fe_sec_voltage_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -995,6 +1005,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
/* normal tune mode when opened R/W */
fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+ fepriv->tone = -1;
+ fepriv->voltage = -1;
}
return ret;
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 2f0f35811bf7..9fd87521a163 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void *data)
dvb_net_feed_stop(dev);
priv->rx_mode = RX_MODE_UNI;
- spin_lock_bh(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void *data)
}
}
- spin_unlock_bh(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
dvb_net_feed_start(dev);
}
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 96fe0ecae250..3852430d0260 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -219,8 +219,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
return -ENOMEM;
}
- mutex_unlock(&dvbdev_register_lock);
-
memcpy(dvbdev, template, sizeof(struct dvb_device));
dvbdev->type = type;
dvbdev->id = id;
@@ -231,6 +229,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
list_add_tail (&dvbdev->list_head, &adap->device_list);
+ mutex_unlock(&dvbdev_register_lock);
+
devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
S_IFCHR | S_IRUSR | S_IWUSR,
"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index d3df12039b06..e388fb1567d6 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB
+ depends on DVB_CORE && USB && I2C
select FW_LOADER
help
By enabling this you will be able to choose the various supported
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 7edd6362b9cc..1f0d3e995c8d 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -150,6 +150,15 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
}
+static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b = 0;
+ if (onoff)
+ return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
+ else
+ return 0;
+}
+
static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 buf[2] = { 0x03, 0x00 };
@@ -544,7 +553,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_power_ctrl,
+ .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
.tuner_attach = cxusb_lgh064f_tuner_attach,
@@ -589,7 +598,7 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_power_ctrl,
+ .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_dee1601_frontend_attach,
.tuner_attach = cxusb_dee1601_tuner_attach,
@@ -638,7 +647,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_power_ctrl,
+ .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_lgz201_tuner_attach,
@@ -683,7 +692,7 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = {
.size_of_priv = sizeof(struct cxusb_state),
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_power_ctrl,
+ .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_dtt7579_tuner_attach,
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index d661c6f9cbe5..691dc840dcc0 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -29,6 +29,9 @@
#include "dvb_frontend.h"
#include "cx24123.h"
+#define XTAL 10111000
+
+static int force_band;
static int debug;
#define dprintk(args...) \
do { \
@@ -52,6 +55,7 @@ struct cx24123_state
u32 VGAarg;
u32 bandselectarg;
u32 pllarg;
+ u32 FILTune;
/* The Demod/Tuner can't easily provide these, we cache them */
u32 currentfreq;
@@ -63,43 +67,33 @@ static struct
{
u32 symbolrate_low;
u32 symbolrate_high;
- u32 VCAslope;
- u32 VCAoffset;
- u32 VGA1offset;
- u32 VGA2offset;
u32 VCAprogdata;
u32 VGAprogdata;
+ u32 FILTune;
} cx24123_AGC_vals[] =
{
{
.symbolrate_low = 1000000,
.symbolrate_high = 4999999,
- .VCAslope = 0x07,
- .VCAoffset = 0x0f,
- .VGA1offset = 0x1f8,
- .VGA2offset = 0x1f8,
- .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8,
- .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07,
+ /* the specs recommend other values for VGA offsets,
+ but tests show they are wrong */
+ .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0,
+ .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x07,
+ .FILTune = 0x27f /* 0.41 V */
},
{
.symbolrate_low = 5000000,
.symbolrate_high = 14999999,
- .VCAslope = 0x1f,
- .VCAoffset = 0x1f,
- .VGA1offset = 0x1e0,
- .VGA2offset = 0x180,
- .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0,
- .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f,
+ .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0,
+ .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x1f,
+ .FILTune = 0x317 /* 0.90 V */
},
{
.symbolrate_low = 15000000,
.symbolrate_high = 45000000,
- .VCAslope = 0x3f,
- .VCAoffset = 0x3f,
- .VGA1offset = 0x180,
- .VGA2offset = 0x100,
- .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180,
- .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f,
+ .VGAprogdata = (1 << 19) | (0x100 << 9) | 0x180,
+ .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x3f,
+ .FILTune = 0x145 /* 2.70 V */
},
};
@@ -112,91 +106,80 @@ static struct
{
u32 freq_low;
u32 freq_high;
- u32 bandselect;
u32 VCOdivider;
- u32 VCOnumber;
u32 progdata;
} cx24123_bandselect_vals[] =
{
+ /* band 1 */
{
.freq_low = 950000,
- .freq_high = 1018999,
- .bandselect = 0x40,
- .VCOdivider = 4,
- .VCOnumber = 7,
- .progdata = (0 << 18) | (0 << 9) | 0x40,
- },
- {
- .freq_low = 1019000,
.freq_high = 1074999,
- .bandselect = 0x80,
.VCOdivider = 4,
- .VCOnumber = 8,
- .progdata = (0 << 18) | (0 << 9) | 0x80,
+ .progdata = (0 << 19) | (0 << 9) | 0x40,
},
+
+ /* band 2 */
{
.freq_low = 1075000,
- .freq_high = 1227999,
- .bandselect = 0x01,
- .VCOdivider = 2,
- .VCOnumber = 1,
- .progdata = (0 << 18) | (1 << 9) | 0x01,
+ .freq_high = 1177999,
+ .VCOdivider = 4,
+ .progdata = (0 << 19) | (0 << 9) | 0x80,
},
+
+ /* band 3 */
{
- .freq_low = 1228000,
- .freq_high = 1349999,
- .bandselect = 0x02,
+ .freq_low = 1178000,
+ .freq_high = 1295999,
.VCOdivider = 2,
- .VCOnumber = 2,
- .progdata = (0 << 18) | (1 << 9) | 0x02,
+ .progdata = (0 << 19) | (1 << 9) | 0x01,
},
+
+ /* band 4 */
{
- .freq_low = 1350000,
- .freq_high = 1481999,
- .bandselect = 0x04,
+ .freq_low = 1296000,
+ .freq_high = 1431999,
.VCOdivider = 2,
- .VCOnumber = 3,
- .progdata = (0 << 18) | (1 << 9) | 0x04,
+ .progdata = (0 << 19) | (1 << 9) | 0x02,
},
+
+ /* band 5 */
{
- .freq_low = 1482000,
- .freq_high = 1595999,
- .bandselect = 0x08,
+ .freq_low = 1432000,
+ .freq_high = 1575999,
.VCOdivider = 2,
- .VCOnumber = 4,
- .progdata = (0 << 18) | (1 << 9) | 0x08,
+ .progdata = (0 << 19) | (1 << 9) | 0x04,
},
+
+ /* band 6 */
{
- .freq_low = 1596000,
+ .freq_low = 1576000,
.freq_high = 1717999,
- .bandselect = 0x10,
.VCOdivider = 2,
- .VCOnumber = 5,
- .progdata = (0 << 18) | (1 << 9) | 0x10,
+ .progdata = (0 << 19) | (1 << 9) | 0x08,
},
+
+ /* band 7 */
{
.freq_low = 1718000,
.freq_high = 1855999,
- .bandselect = 0x20,
.VCOdivider = 2,
- .VCOnumber = 6,
- .progdata = (0 << 18) | (1 << 9) | 0x20,
+ .progdata = (0 << 19) | (1 << 9) | 0x10,
},
+
+ /* band 8 */
{
.freq_low = 1856000,
.freq_high = 2035999,
- .bandselect = 0x40,
.VCOdivider = 2,
- .VCOnumber = 7,
- .progdata = (0 << 18) | (1 << 9) | 0x40,
+ .progdata = (0 << 19) | (1 << 9) | 0x20,
},
+
+ /* band 9 */
{
.freq_low = 2036000,
- .freq_high = 2149999,
- .bandselect = 0x80,
+ .freq_high = 2150000,
.VCOdivider = 2,
- .VCOnumber = 8,
- .progdata = (0 << 18) | (1 << 9) | 0x80,
+ .progdata = (0 << 19) | (1 << 9) | 0x40,
},
};
@@ -207,49 +190,44 @@ static struct {
{
{0x00, 0x03}, /* Reset system */
{0x00, 0x00}, /* Clear reset */
- {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
- {0x03, 0x07},
- {0x04, 0x10},
- {0x05, 0x04},
- {0x06, 0x31},
- {0x0d, 0x02},
- {0x0e, 0x03},
- {0x0f, 0xfe},
- {0x10, 0x01},
- {0x14, 0x01},
- {0x15, 0x98},
- {0x16, 0x00},
- {0x17, 0x01},
- {0x1b, 0x05},
- {0x1c, 0x80},
- {0x1d, 0x00},
- {0x1e, 0x00},
- {0x20, 0x41},
- {0x21, 0x15},
- {0x27, 0x14},
- {0x28, 0x46},
- {0x29, 0x00},
- {0x2a, 0xb0},
- {0x2b, 0x73},
- {0x2c, 0x00},
+ {0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */
+ {0x04, 0x10}, /* MPEG */
+ {0x05, 0x04}, /* MPEG */
+ {0x06, 0x31}, /* MPEG (default) */
+ {0x0b, 0x00}, /* Freq search start point (default) */
+ {0x0c, 0x00}, /* Demodulator sample gain (default) */
+ {0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */
+ {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
+ {0x0f, 0xfe}, /* FEC search mask (all supported codes) */
+ {0x10, 0x01}, /* Default search inversion, no repeat (default) */
+ {0x16, 0x00}, /* Enable reading of frequency */
+ {0x17, 0x01}, /* Enable EsNO Ready Counter */
+ {0x1c, 0x80}, /* Enable error counter */
+ {0x20, 0x00}, /* Tuner burst clock rate = 500KHz */
+ {0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */
+ {0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */
+ {0x29, 0x00}, /* DiSEqC LNB_DC off */
+ {0x2a, 0xb0}, /* DiSEqC Parameters (default) */
+ {0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */
+ {0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */
{0x2d, 0x00},
{0x2e, 0x00},
{0x2f, 0x00},
{0x30, 0x00},
{0x31, 0x00},
- {0x32, 0x8c},
- {0x33, 0x00},
+ {0x32, 0x8c}, /* DiSEqC Parameters (default) */
+ {0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */
{0x34, 0x00},
- {0x35, 0x03},
- {0x36, 0x02},
- {0x37, 0x3a},
- {0x3a, 0x00}, /* Enable AGC accumulator */
- {0x44, 0x00},
- {0x45, 0x00},
- {0x46, 0x05},
- {0x56, 0x41},
- {0x57, 0xff},
- {0x67, 0x83},
+ {0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */
+ {0x36, 0x02}, /* DiSEqC Parameters (default) */
+ {0x37, 0x3a}, /* DiSEqC Parameters (default) */
+ {0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */
+ {0x44, 0x00}, /* Constellation (default) */
+ {0x45, 0x00}, /* Symbol count (default) */
+ {0x46, 0x0d}, /* Symbol rate estimator on (default) */
+ {0x56, 0x41}, /* Various (default) */
+ {0x57, 0xff}, /* Error Counter Window (default) */
+ {0x67, 0x83}, /* Non-DCII symbol clock */
};
static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
@@ -258,6 +236,10 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
int err;
+ if (debug>1)
+ printk("cx24123: %s: write reg 0x%02x, value 0x%02x\n",
+ __FUNCTION__,reg, data);
+
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __FUNCTION__, err, reg, data);
@@ -274,6 +256,10 @@ static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
int err;
+ if (debug>1)
+ printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
+ __FUNCTION__,reg, data);
+
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __FUNCTION__, err, reg, data);
@@ -303,6 +289,9 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
return ret;
}
+ if (debug>1)
+ printk("cx24123: read reg 0x%02x, value 0x%02x\n",reg, ret);
+
return b1[0];
}
@@ -313,17 +302,23 @@ static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
+ u8 nom_reg = cx24123_readreg(state, 0x0e);
+ u8 auto_reg = cx24123_readreg(state, 0x10);
+
switch (inversion) {
case INVERSION_OFF:
- cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
- cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+ dprintk("%s: inversion off\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg & ~0x80);
+ cx24123_writereg(state, 0x10, auto_reg | 0x80);
break;
case INVERSION_ON:
- cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
- cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+ dprintk("%s: inversion on\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x80);
+ cx24123_writereg(state, 0x10, auto_reg | 0x80);
break;
case INVERSION_AUTO:
- cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
+ dprintk("%s: inversion auto\n",__FUNCTION__);
+ cx24123_writereg(state, 0x10, auto_reg & ~0x80);
break;
default:
return -EINVAL;
@@ -338,92 +333,191 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers
val = cx24123_readreg(state, 0x1b) >> 7;
- if (val == 0)
+ if (val == 0) {
+ dprintk("%s: read inversion off\n",__FUNCTION__);
*inversion = INVERSION_OFF;
- else
+ } else {
+ dprintk("%s: read inversion on\n",__FUNCTION__);
*inversion = INVERSION_ON;
+ }
return 0;
}
static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
{
+ u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07;
+
if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
fec = FEC_AUTO;
- /* Hardware has 5/11 and 3/5 but are never unused */
switch (fec) {
- case FEC_NONE:
- return cx24123_writereg(state, 0x0f, 0x01);
case FEC_1_2:
- return cx24123_writereg(state, 0x0f, 0x02);
+ dprintk("%s: set FEC to 1/2\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x01);
+ cx24123_writereg(state, 0x0f, 0x02);
+ break;
case FEC_2_3:
- return cx24123_writereg(state, 0x0f, 0x04);
+ dprintk("%s: set FEC to 2/3\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x02);
+ cx24123_writereg(state, 0x0f, 0x04);
+ break;
case FEC_3_4:
- return cx24123_writereg(state, 0x0f, 0x08);
+ dprintk("%s: set FEC to 3/4\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x03);
+ cx24123_writereg(state, 0x0f, 0x08);
+ break;
+ case FEC_4_5:
+ dprintk("%s: set FEC to 4/5\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x04);
+ cx24123_writereg(state, 0x0f, 0x10);
+ break;
case FEC_5_6:
- return cx24123_writereg(state, 0x0f, 0x20);
+ dprintk("%s: set FEC to 5/6\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x05);
+ cx24123_writereg(state, 0x0f, 0x20);
+ break;
+ case FEC_6_7:
+ dprintk("%s: set FEC to 6/7\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x06);
+ cx24123_writereg(state, 0x0f, 0x40);
+ break;
case FEC_7_8:
- return cx24123_writereg(state, 0x0f, 0x80);
+ dprintk("%s: set FEC to 7/8\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0e, nom_reg | 0x07);
+ cx24123_writereg(state, 0x0f, 0x80);
+ break;
case FEC_AUTO:
- return cx24123_writereg(state, 0x0f, 0xae);
+ dprintk("%s: set FEC to auto\n",__FUNCTION__);
+ cx24123_writereg(state, 0x0f, 0xfe);
+ break;
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
{
int ret;
- u8 val;
ret = cx24123_readreg (state, 0x1b);
if (ret < 0)
return ret;
- val = ret & 0x07;
- switch (val) {
+ ret = ret & 0x07;
+
+ switch (ret) {
case 1:
*fec = FEC_1_2;
break;
- case 3:
+ case 2:
*fec = FEC_2_3;
break;
- case 4:
+ case 3:
*fec = FEC_3_4;
break;
- case 5:
+ case 4:
*fec = FEC_4_5;
break;
- case 6:
+ case 5:
*fec = FEC_5_6;
break;
+ case 6:
+ *fec = FEC_6_7;
+ break;
case 7:
*fec = FEC_7_8;
break;
- case 2: /* *fec = FEC_3_5; break; */
- case 0: /* *fec = FEC_5_11; break; */
- *fec = FEC_AUTO;
- break;
default:
- *fec = FEC_NONE; // can't happen
+ /* this can happen when there's no lock */
+ *fec = FEC_NONE;
}
return 0;
}
-/* fixme: Symbol rates < 3MSps may not work because of precision loss */
+/* Approximation of closest integer of log2(a/b). It actually gives the
+ lowest integer i such that 2^i >= round(a/b) */
+static u32 cx24123_int_log2(u32 a, u32 b)
+{
+ u32 exp, nearest = 0;
+ u32 div = a / b;
+ if(a % b >= b / 2) ++div;
+ if(div < (1 << 31))
+ {
+ for(exp = 1; div > exp; nearest++)
+ exp += exp;
+ }
+ return nearest;
+}
+
static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
{
- u32 val;
+ u32 tmp, sample_rate, ratio, sample_gain;
+ u8 pll_mult;
+
+ /* check if symbol rate is within limits */
+ if ((srate > state->ops.info.symbol_rate_max) ||
+ (srate < state->ops.info.symbol_rate_min))
+ return -EOPNOTSUPP;;
+
+ /* choose the sampling rate high enough for the required operation,
+ while optimizing the power consumed by the demodulator */
+ if (srate < (XTAL*2)/2)
+ pll_mult = 2;
+ else if (srate < (XTAL*3)/2)
+ pll_mult = 3;
+ else if (srate < (XTAL*4)/2)
+ pll_mult = 4;
+ else if (srate < (XTAL*5)/2)
+ pll_mult = 5;
+ else if (srate < (XTAL*6)/2)
+ pll_mult = 6;
+ else if (srate < (XTAL*7)/2)
+ pll_mult = 7;
+ else if (srate < (XTAL*8)/2)
+ pll_mult = 8;
+ else
+ pll_mult = 9;
+
+
+ sample_rate = pll_mult * XTAL;
+
+ /*
+ SYSSymbolRate[21:0] = (srate << 23) / sample_rate
+
+ We have to use 32 bit unsigned arithmetic without precision loss.
+ The maximum srate is 45000000 or 0x02AEA540. This number has
+ only 6 clear bits on top, hence we can shift it left only 6 bits
+ at a time. Borrowed from cx24110.c
+ */
+
+ tmp = srate << 6;
+ ratio = tmp / sample_rate;
+
+ tmp = (tmp % sample_rate) << 6;
+ ratio = (ratio << 6) + (tmp / sample_rate);
+
+ tmp = (tmp % sample_rate) << 6;
+ ratio = (ratio << 6) + (tmp / sample_rate);
+
+ tmp = (tmp % sample_rate) << 5;
+ ratio = (ratio << 5) + (tmp / sample_rate);
+
+
+ cx24123_writereg(state, 0x01, pll_mult * 6);
- val = (srate / 1185) * 100;
+ cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f );
+ cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff );
+ cx24123_writereg(state, 0x0a, (ratio ) & 0xff );
- /* Compensate for scaling up, by removing 17 symbols per 1Msps */
- val = val - (17 * (srate / 1000000));
+ /* also set the demodulator sample gain */
+ sample_gain = cx24123_int_log2(sample_rate, srate);
+ tmp = cx24123_readreg(state, 0x0c) & ~0xe0;
+ cx24123_writereg(state, 0x0c, tmp | sample_gain << 5);
- cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
- cx24123_writereg(state, 0x09, (val >> 8) & 0xff );
- cx24123_writereg(state, 0x0a, (val ) & 0xff );
+ dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", __FUNCTION__, srate, ratio, sample_rate, sample_gain);
return 0;
}
@@ -437,6 +531,9 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
struct cx24123_state *state = fe->demodulator_priv;
u32 ndiv = 0, adiv = 0, vco_div = 0;
int i = 0;
+ int pump = 2;
+ int band = 0;
+ int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]);
/* Defaults for low freq, low rate */
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -444,38 +541,49 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
state->bandselectarg = cx24123_bandselect_vals[0].progdata;
vco_div = cx24123_bandselect_vals[0].VCOdivider;
- /* For the given symbolerate, determine the VCA and VGA programming bits */
+ /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
{
if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
- (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
+ (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
+ state->FILTune = cx24123_AGC_vals[i].FILTune;
}
}
- /* For the given frequency, determine the bandselect programming bits */
- for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
+ /* determine the band to use */
+ if(force_band < 1 || force_band > num_bands)
{
- if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
- (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
- state->bandselectarg = cx24123_bandselect_vals[i].progdata;
- vco_div = cx24123_bandselect_vals[i].VCOdivider;
+ for (i = 0; i < num_bands; i++)
+ {
+ if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
+ (cx24123_bandselect_vals[i].freq_high >= p->frequency) )
+ band = i;
}
}
+ else
+ band = force_band - 1;
+
+ state->bandselectarg = cx24123_bandselect_vals[band].progdata;
+ vco_div = cx24123_bandselect_vals[band].VCOdivider;
+
+ /* determine the charge pump current */
+ if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 )
+ pump = 0x01;
+ else
+ pump = 0x02;
/* Determine the N/A dividers for the requested lband freq (in kHz). */
- /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
- ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
- adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
+ /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */
+ ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
+ adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
if (adiv == 0)
- adiv++;
+ ndiv++;
- /* determine the correct pll frequency values. */
- /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
- state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
- state->pllarg |= (ndiv << 5) | adiv;
+ /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
+ state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
return 0;
}
@@ -489,6 +597,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
struct cx24123_state *state = fe->demodulator_priv;
unsigned long timeout;
+ dprintk("%s: pll writereg called, data=0x%08x\n",__FUNCTION__,data);
+
/* align the 21 bytes into to bit23 boundary */
data = data << 3;
@@ -538,6 +648,9 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
+ u8 val;
+
+ dprintk("frequency=%i\n", p->frequency);
if (cx24123_pll_calculate(fe, p) != 0) {
printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
@@ -552,6 +665,14 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet
cx24123_pll_writereg(fe, p, state->bandselectarg);
cx24123_pll_writereg(fe, p, state->pllarg);
+ /* set the FILTUNE voltage */
+ val = cx24123_readreg(state, 0x28) & ~0x3;
+ cx24123_writereg(state, 0x27, state->FILTune >> 2);
+ cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3));
+
+ dprintk("%s: pll tune VCA=%d, band=%d, pll=%d\n",__FUNCTION__,state->VCAarg,
+ state->bandselectarg,state->pllarg);
+
return 0;
}
@@ -560,6 +681,8 @@ static int cx24123_initfe(struct dvb_frontend* fe)
struct cx24123_state *state = fe->demodulator_priv;
int i;
+ dprintk("%s: init frontend\n",__FUNCTION__);
+
/* Configure the demod to a good set of defaults */
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
@@ -587,10 +710,13 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
switch (voltage) {
case SEC_VOLTAGE_13:
+ dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__);
return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
case SEC_VOLTAGE_18:
+ dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__);
return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
case SEC_VOLTAGE_OFF:
+ dprintk("%s: isl5421 voltage off\n",__FUNCTION__);
return cx24123_writelnbreg(state, 0x0, val & 0x30);
default:
return -EINVAL;
@@ -624,13 +750,93 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
return 0;
}
-static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
- struct dvb_diseqc_master_cmd *cmd)
+/* wait for diseqc queue to become ready (or timeout) */
+static void cx24123_wait_for_diseqc(struct cx24123_state *state)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(200);
+ while (!(cx24123_readreg(state, 0x29) & 0x40)) {
+ if(time_after(jiffies, timeout)) {
+ printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+ break;
+ }
+ msleep(10);
+ }
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{
- /* fixme: Implement diseqc */
- printk("%s: No support yet\n",__FUNCTION__);
+ struct cx24123_state *state = fe->demodulator_priv;
+ int i, val;
+
+ dprintk("%s:\n",__FUNCTION__);
+
+ /* check if continuous tone has been stopped */
+ if (state->config->use_isl6421)
+ val = cx24123_readlnbreg(state, 0x00) & 0x10;
+ else
+ val = cx24123_readreg(state, 0x29) & 0x10;
- return -ENOTSUPP;
+
+ if (val) {
+ printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
+ return -ENOTSUPP;
+ }
+
+ /* wait for diseqc queue ready */
+ cx24123_wait_for_diseqc(state);
+
+ /* select tone mode */
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+
+ for (i = 0; i < cmd->msg_len; i++)
+ cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
+
+ val = cx24123_readreg(state, 0x29);
+ cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+
+ /* wait for diseqc message to finish sending */
+ cx24123_wait_for_diseqc(state);
+
+ return 0;
+}
+
+static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ int val;
+
+ dprintk("%s:\n", __FUNCTION__);
+
+ /* check if continuous tone has been stoped */
+ if (state->config->use_isl6421)
+ val = cx24123_readlnbreg(state, 0x00) & 0x10;
+ else
+ val = cx24123_readreg(state, 0x29) & 0x10;
+
+
+ if (val) {
+ printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
+ return -ENOTSUPP;
+ }
+
+ cx24123_wait_for_diseqc(state);
+
+ /* select tone mode */
+ val = cx24123_readreg(state, 0x2a) & 0xf8;
+ cx24123_writereg(state, 0x2a, val | 0x04);
+
+ val = cx24123_readreg(state, 0x29);
+
+ if (burst == SEC_MINI_A)
+ cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
+ else if (burst == SEC_MINI_B)
+ cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08));
+ else
+ return -EINVAL;
+
+ cx24123_wait_for_diseqc(state);
+
+ return 0;
}
static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
@@ -642,13 +848,15 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
*status = 0;
if (lock & 0x01)
- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ *status |= FE_HAS_SIGNAL;
+ if (sync & 0x02)
+ *status |= FE_HAS_CARRIER;
if (sync & 0x04)
*status |= FE_HAS_VITERBI;
if (sync & 0x08)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SYNC;
if (sync & 0x80)
- *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+ *status |= FE_HAS_LOCK;
return 0;
}
@@ -681,6 +889,8 @@ static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
else
state->snr = 0;
+ dprintk("%s: BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
+
*ber = state->lastber;
return 0;
@@ -691,6 +901,8 @@ static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_str
struct cx24123_state *state = fe->demodulator_priv;
*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+ dprintk("%s: Signal strength = %d\n",__FUNCTION__,*signal_strength);
+
return 0;
}
@@ -699,6 +911,8 @@ static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
struct cx24123_state *state = fe->demodulator_priv;
*snr = state->snr;
+ dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
+
return 0;
}
@@ -707,6 +921,8 @@ static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
struct cx24123_state *state = fe->demodulator_priv;
*ucblocks = state->lastber;
+ dprintk("%s: ucblocks (ber) = %d\n",__FUNCTION__,*ucblocks);
+
return 0;
}
@@ -714,6 +930,8 @@ static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24123_state *state = fe->demodulator_priv;
+ dprintk("%s: set_frontend\n",__FUNCTION__);
+
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
@@ -737,6 +955,8 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24123_state *state = fe->demodulator_priv;
+ dprintk("%s: get_frontend\n",__FUNCTION__);
+
if (cx24123_get_inversion(state, &p->inversion) != 0) {
printk("%s: Failed to get inversion status\n",__FUNCTION__);
return -EREMOTEIO;
@@ -763,8 +983,10 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
+ dprintk("%s: isl6421 sec tone on\n",__FUNCTION__);
return cx24123_writelnbreg(state, 0x0, val | 0x10);
case SEC_TONE_OFF:
+ dprintk("%s: isl6421 sec tone off\n",__FUNCTION__);
return cx24123_writelnbreg(state, 0x0, val & 0x2f);
default:
printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
@@ -855,12 +1077,13 @@ static struct dvb_frontend_ops cx24123_ops = {
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
- .frequency_tolerance = 29500,
+ .frequency_tolerance = 5000,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_RECOVER
},
@@ -875,12 +1098,16 @@ static struct dvb_frontend_ops cx24123_ops = {
.read_snr = cx24123_read_snr,
.read_ucblocks = cx24123_read_ucblocks,
.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+ .diseqc_send_burst = cx24123_diseqc_send_burst,
.set_tone = cx24123_set_tone,
.set_voltage = cx24123_set_voltage,
};
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+module_param(force_band, int, 0644);
+MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off).");
MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
MODULE_AUTHOR("Steven Toth");
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index b6e2c387a04c..791706ec1da3 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -235,8 +235,8 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
.max = 863000000,
.count = 3,
.entries = {
- { 160000000, 44000000, 62500, 0xce, 0x01 },
- { 455000000, 44000000, 62500, 0xce, 0x02 },
+ { 165000000, 44000000, 62500, 0xce, 0x01 },
+ { 450000000, 44000000, 62500, 0xce, 0x02 },
{ 999999999, 44000000, 62500, 0xce, 0x04 },
},
};
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
index 84f8f9f52869..7d8e6e87bdbb 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -1,7 +1,6 @@
config DVB_PLUTO2
tristate "Pluto2 cards"
- depends on DVB_CORE && PCI
- select I2C
+ depends on DVB_CORE && PCI && I2C
select I2C_ALGOBIT
select DVB_TDA1004X
help
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
index 86ca84b2be6e..ce6a9aaf937e 100644
--- a/drivers/media/dvb/pluto2/Makefile
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_DVB_PLUTO2) = pluto2.o
+obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 5b2aadb8385c..b5ac7dfde52f 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -1,8 +1,7 @@
config DVB_AV7110
tristate "AV7110 cards"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select FW_LOADER
- select VIDEO_DEV
select VIDEO_SAA7146_VV
select DVB_VES1820
select DVB_VES1X93
@@ -59,7 +58,7 @@ config DVB_AV7110_OSD
config DVB_BUDGET
tristate "Budget cards"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
select DVB_STV0299
select DVB_VES1X93
@@ -80,7 +79,7 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
select DVB_STV0297
select DVB_STV0299
@@ -100,8 +99,7 @@ config DVB_BUDGET_CI
config DVB_BUDGET_AV
tristate "Budget cards with analog video inputs"
- depends on DVB_CORE && PCI
- select VIDEO_DEV
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
select DVB_STV0299
select DVB_TDA1004X
@@ -119,7 +117,7 @@ config DVB_BUDGET_AV
config DVB_BUDGET_PATCH
tristate "AV7110 cards with Budget Patch"
- depends on DVB_CORE && DVB_BUDGET
+ depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
select DVB_AV7110
select DVB_STV0299
select DVB_VES1X93
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8efe3ce5f66c..8a7cd7d505cf 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1190,8 +1190,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
SAA7146_HPS_SYNC_PORT_A);
saa7113_setinput(budget_av, 0);
- } else {
- ciintf_init(budget_av);
}
/* fixme: find some sane values here... */
@@ -1211,6 +1209,10 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
budget_av->budget.dvb_adapter.priv = budget_av;
frontend_init(budget_av);
+ if (!budget_av->has_saa7113) {
+ ciintf_init(budget_av);
+ }
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 5f91036f5b87..e64a609cf4ff 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -71,6 +71,7 @@ struct budget_ci {
struct tasklet_struct msp430_irq_tasklet;
struct tasklet_struct ciintf_irq_tasklet;
int slot_status;
+ int ci_irq;
struct dvb_ca_en50221 ca;
char ir_dev_name[50];
u8 tuner_pll_address; /* used for philips_tdm1316l configs */
@@ -276,8 +277,10 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
if (slot != 0)
return -EINVAL;
- // trigger on RISING edge during reset so we know when READY is re-asserted
- saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+ if (budget_ci->ci_irq) {
+ // trigger on RISING edge during reset so we know when READY is re-asserted
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+ }
budget_ci->slot_status = SLOTSTATUS_RESET;
ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
msleep(1);
@@ -370,11 +373,50 @@ static void ciintf_interrupt(unsigned long data)
}
}
+static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+ struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
+ unsigned int flags;
+
+ // ensure we don't get spurious IRQs during initialisation
+ if (!budget_ci->budget.ci_present)
+ return -EINVAL;
+
+ // read the CAM status
+ flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+ if (flags & CICONTROL_CAMDETECT) {
+ // mark it as present if it wasn't before
+ if (budget_ci->slot_status & SLOTSTATUS_NONE) {
+ budget_ci->slot_status = SLOTSTATUS_PRESENT;
+ }
+
+ // during a RESET, we check if we can read from IO memory to see when CAM is ready
+ if (budget_ci->slot_status & SLOTSTATUS_RESET) {
+ if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
+ budget_ci->slot_status = SLOTSTATUS_READY;
+ }
+ }
+ } else {
+ budget_ci->slot_status = SLOTSTATUS_NONE;
+ }
+
+ if (budget_ci->slot_status != SLOTSTATUS_NONE) {
+ if (budget_ci->slot_status & SLOTSTATUS_READY) {
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ }
+ return DVB_CA_EN50221_POLL_CAM_PRESENT;
+ }
+
+ return 0;
+}
+
static int ciintf_init(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
int flags;
int result;
+ int ci_version;
+ int ca_flags;
memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
@@ -382,16 +424,29 @@ static int ciintf_init(struct budget_ci *budget_ci)
saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
// test if it is there
- if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) {
+ ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
+ if ((ci_version & 0xa0) != 0xa0) {
result = -ENODEV;
goto error;
}
+
// determine whether a CAM is present or not
flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
budget_ci->slot_status = SLOTSTATUS_NONE;
if (flags & CICONTROL_CAMDETECT)
budget_ci->slot_status = SLOTSTATUS_PRESENT;
+ // version 0xa2 of the CI firmware doesn't generate interrupts
+ if (ci_version == 0xa2) {
+ ca_flags = 0;
+ budget_ci->ci_irq = 0;
+ } else {
+ ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
+ DVB_CA_EN50221_FLAG_IRQ_FR |
+ DVB_CA_EN50221_FLAG_IRQ_DA;
+ budget_ci->ci_irq = 1;
+ }
+
// register CI interface
budget_ci->ca.owner = THIS_MODULE;
budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
@@ -401,23 +456,27 @@ static int ciintf_init(struct budget_ci *budget_ci)
budget_ci->ca.slot_reset = ciintf_slot_reset;
budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
+ budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
budget_ci->ca.data = budget_ci;
if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
&budget_ci->ca,
- DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
- DVB_CA_EN50221_FLAG_IRQ_FR |
- DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) {
+ ca_flags, 1)) != 0) {
printk("budget_ci: CI interface detected, but initialisation failed.\n");
goto error;
}
+
// Setup CI slot IRQ
- tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
- if (budget_ci->slot_status != SLOTSTATUS_NONE) {
- saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
- } else {
- saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+ if (budget_ci->ci_irq) {
+ tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+ if (budget_ci->slot_status != SLOTSTATUS_NONE) {
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+ } else {
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+ }
+ saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
}
- saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
+
+ // enable interface
ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
CICONTROL_RESET, 1, 0);
@@ -426,10 +485,12 @@ static int ciintf_init(struct budget_ci *budget_ci)
budget_ci->budget.ci_present = 1;
// forge a fake CI IRQ so the CAM state is setup correctly
- flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
- if (budget_ci->slot_status != SLOTSTATUS_NONE)
- flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
- dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
+ if (budget_ci->ci_irq) {
+ flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+ if (budget_ci->slot_status != SLOTSTATUS_NONE)
+ flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+ dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
+ }
return 0;
@@ -443,9 +504,13 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
struct saa7146_dev *saa = budget_ci->budget.dev;
// disable CI interrupts
- saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
- saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
- tasklet_kill(&budget_ci->ciintf_irq_tasklet);
+ if (budget_ci->ci_irq) {
+ saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
+ tasklet_kill(&budget_ci->ciintf_irq_tasklet);
+ }
+
+ // reset interface
ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
msleep(1);
ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
@@ -473,7 +538,7 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
if (*isr & MASK_10)
ttpci_budget_irq10_handler(dev, isr);
- if ((*isr & MASK_03) && (budget_ci->budget.ci_present))
+ if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
}
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 248fdc7accfb..6ceae38125c7 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1507,7 +1507,11 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
mutex_unlock(&ttusb->semi2c);
- dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
+ if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+ ttusb_free_iso_urbs(ttusb);
+ kfree(ttusb);
+ return result;
+ }
ttusb->adapter.priv = ttusb;
/* i2c */
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index d318be383de6..3fff75763693 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -7,7 +7,7 @@ menu "Radio Adapters"
config RADIO_CADET
tristate "ADS Cadet AM/FM Tuner"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these AM/FM radio cards, and then
fill in the port address below.
@@ -25,7 +25,7 @@ config RADIO_CADET
config RADIO_RTRACK
tristate "AIMSlab RadioTrack (aka RadioReveal) support"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -59,7 +59,7 @@ config RADIO_RTRACK_PORT
config RADIO_RTRACK2
tristate "AIMSlab RadioTrack II support"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below.
@@ -82,7 +82,7 @@ config RADIO_RTRACK2_PORT
config RADIO_AZTECH
tristate "Aztech/Packard Bell Radio"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -106,7 +106,7 @@ config RADIO_AZTECH_PORT
config RADIO_GEMTEK
tristate "GemTek Radio Card support"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below.
@@ -131,7 +131,7 @@ config RADIO_GEMTEK_PORT
config RADIO_GEMTEK_PCI
tristate "GemTek PCI Radio Card support"
- depends on VIDEO_DEV && PCI
+ depends on VIDEO_V4L1 && PCI
---help---
Choose Y here if you have this PCI FM radio card.
@@ -145,7 +145,7 @@ config RADIO_GEMTEK_PCI
config RADIO_MAXIRADIO
tristate "Guillemot MAXI Radio FM 2000 radio"
- depends on VIDEO_DEV && PCI
+ depends on VIDEO_V4L1 && PCI
---help---
Choose Y here if you have this radio card. This card may also be
found as Gemtek PCI FM.
@@ -160,7 +160,7 @@ config RADIO_MAXIRADIO
config RADIO_MAESTRO
tristate "Maestro on board radio"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L1
---help---
Say Y here to directly support the on-board radio tuner on the
Maestro 2 or 2E sound card.
@@ -175,7 +175,7 @@ config RADIO_MAESTRO
config RADIO_MIROPCM20
tristate "miroSOUND PCM20 radio"
- depends on ISA && VIDEO_DEV && SOUND_ACI_MIXER
+ depends on ISA && VIDEO_V4L1 && SOUND_ACI_MIXER
---help---
Choose Y here if you have this FM radio card. You also need to say Y
to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound")
@@ -208,7 +208,7 @@ config RADIO_MIROPCM20_RDS
config RADIO_SF16FMI
tristate "SF16FMI Radio"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards. If you
compile the driver into the kernel and your card is not PnP one, you
@@ -225,7 +225,7 @@ config RADIO_SF16FMI
config RADIO_SF16FMR2
tristate "SF16FMR2 Radio"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards.
@@ -239,7 +239,7 @@ config RADIO_SF16FMR2
config RADIO_TERRATEC
tristate "TerraTec ActiveRadio ISA Standalone"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below. (TODO)
@@ -268,7 +268,7 @@ config RADIO_TERRATEC_PORT
config RADIO_TRUST
tristate "Trust FM radio card"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
help
This is a driver for the Trust FM radio cards. Say Y if you have
such a card and want to use it under Linux.
@@ -286,7 +286,7 @@ config RADIO_TRUST_PORT
config RADIO_TYPHOON
tristate "Typhoon Radio (a.k.a. EcoRadio)"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address and the frequency used for muting below.
@@ -330,7 +330,7 @@ config RADIO_TYPHOON_MUTEFREQ
config RADIO_ZOLTRIX
tristate "Zoltrix Radio"
- depends on ISA && VIDEO_DEV
+ depends on ISA && VIDEO_V4L1
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 85888a8a93c9..6b4197018561 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -2,10 +2,10 @@
# Multimedia Video device configuration
#
-menu "Video For Linux"
+menu "Video Capture Adapters"
depends on VIDEO_DEV
-comment "Video Adapters"
+comment "Video Capture Adapters"
config VIDEO_ADV_DEBUG
bool "Enable advanced debug functionality"
@@ -16,11 +16,23 @@ config VIDEO_ADV_DEBUG
V4L devices.
In doubt, say N.
+config VIDEO_VIVI
+ tristate "Virtual Video Driver"
+ depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+ select VIDEO_BUF
+ default n
+ ---help---
+ Enables a virtual video driver. This device shows a color bar
+ and a timestamp, as a real device would generate by using V4L2
+ api.
+ Say Y here if you want to test video apps or debug V4L devices.
+ In doubt, say N.
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_SAA6588
tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
- depends on VIDEO_DEV && I2C && VIDEO_BT848
+ depends on I2C && VIDEO_BT848
help
Support for Radio Data System (RDS) decoder. This allows seeing
@@ -32,7 +44,7 @@ config VIDEO_SAA6588
config VIDEO_PMS
tristate "Mediavision Pro Movie Studio Video For Linux"
- depends on VIDEO_DEV && ISA
+ depends on ISA && VIDEO_V4L1
help
Say Y if you have such a thing.
@@ -41,7 +53,7 @@ config VIDEO_PMS
config VIDEO_PLANB
tristate "PlanB Video-In on PowerMac"
- depends on PPC_PMAC && VIDEO_DEV && BROKEN
+ depends on PPC_PMAC && VIDEO_V4L1 && BROKEN
help
PlanB is the V4L driver for the PowerMac 7x00/8x00 series video
input hardware. If you want to experiment with this, say Y.
@@ -52,7 +64,7 @@ config VIDEO_PLANB
config VIDEO_BWQCAM
tristate "Quickcam BW Video For Linux"
- depends on VIDEO_DEV && PARPORT
+ depends on PARPORT && VIDEO_V4L1
help
Say Y have if you the black and white version of the QuickCam
camera. See the next option for the color version.
@@ -62,7 +74,7 @@ config VIDEO_BWQCAM
config VIDEO_CQCAM
tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
- depends on EXPERIMENTAL && VIDEO_DEV && PARPORT
+ depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1
help
This is the video4linux driver for the colour version of the
Connectix QuickCam. If you have one of these cameras, say Y here,
@@ -73,7 +85,7 @@ config VIDEO_CQCAM
config VIDEO_W9966
tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
- depends on PARPORT_1284 && VIDEO_DEV && PARPORT
+ depends on PARPORT_1284 && PARPORT && VIDEO_V4L1
help
Video4linux driver for Winbond's w9966 based Webcams.
Currently tested with the LifeView FlyCam Supra.
@@ -86,7 +98,7 @@ config VIDEO_W9966
config VIDEO_CPIA
tristate "CPiA Video For Linux"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L1
---help---
This is the video4linux driver for cameras based on Vision's CPiA
(Colour Processor Interface ASIC), such as the Creative Labs Video
@@ -123,7 +135,7 @@ source "drivers/media/video/cpia2/Kconfig"
config VIDEO_SAA5246A
tristate "SAA5246A, SAA5281 Teletext processor"
- depends on VIDEO_DEV && I2C
+ depends on I2C && VIDEO_V4L1
help
Support for I2C bus based teletext using the SAA5246A or SAA5281
chip. Useful only if you live in Europe.
@@ -150,7 +162,7 @@ config TUNER_3036
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
- depends on VIDEO_DEV && I2C && SGI_IP22 && EXPERIMENTAL
+ depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L1
select I2C_ALGO_SGI
help
Say Y here to build in support for the Vino video input system found
@@ -158,7 +170,7 @@ config VIDEO_VINO
config VIDEO_STRADIS
tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && VIDEO_DEV && PCI
+ depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && !PPC64
help
Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
driver for PCI. There is a product page at
@@ -166,7 +178,7 @@ config VIDEO_STRADIS
config VIDEO_ZORAN
tristate "Zoran ZR36057/36067 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C_ALGOBIT
+ depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
help
Say Y for support for MJPEG capture cards based on the Zoran
36057/36067 PCI controller chipset. This includes the Iomega
@@ -214,7 +226,7 @@ config VIDEO_ZORAN_LML33R10
config VIDEO_ZR36120
tristate "Zoran ZR36120/36125 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && BROKEN
+ depends on PCI && I2C && VIDEO_V4L1 && BROKEN
help
Support for ZR36120/ZR36125 based frame grabber/overlay boards.
This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
@@ -226,7 +238,7 @@ config VIDEO_ZR36120
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
- depends on VIDEO_DEV && PCI && SONYPI
+ depends on PCI && SONYPI && VIDEO_V4L1
---help---
This is the video4linux driver for the Motion Eye camera found
in the Vaio Picturebook laptops. Please read the material in
@@ -242,7 +254,7 @@ source "drivers/media/video/saa7134/Kconfig"
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
- depends on VIDEO_DEV && PCI
+ depends on PCI && VIDEO_V4L1
select VIDEO_SAA7146_VV
select VIDEO_TUNER
---help---
@@ -254,8 +266,9 @@ config VIDEO_MXB
config VIDEO_DPC
tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
- depends on VIDEO_DEV && PCI
+ depends on PCI && VIDEO_V4L1
select VIDEO_SAA7146_VV
+ select VIDEO_V4L2
---help---
This is a video4linux driver for the 'dpc7146 demonstration
board' by Philips-Semiconductors. It's the reference design
@@ -268,8 +281,9 @@ config VIDEO_DPC
config VIDEO_HEXIUM_ORION
tristate "Hexium HV-PCI6 and Orion frame grabber"
- depends on VIDEO_DEV && PCI
+ depends on PCI && VIDEO_V4L1
select VIDEO_SAA7146_VV
+ select VIDEO_V4L2
---help---
This is a video4linux driver for the Hexium HV-PCI6 and
Orion frame grabber cards by Hexium.
@@ -279,8 +293,9 @@ config VIDEO_HEXIUM_ORION
config VIDEO_HEXIUM_GEMINI
tristate "Hexium Gemini frame grabber"
- depends on VIDEO_DEV && PCI
+ depends on PCI && VIDEO_V4L1
select VIDEO_SAA7146_VV
+ select VIDEO_V4L2
---help---
This is a video4linux driver for the Hexium Gemini frame
grabber card by Hexium. Please note that the Gemini Dual
@@ -293,7 +308,7 @@ source "drivers/media/video/cx88/Kconfig"
config VIDEO_OVCAMCHIP
tristate "OmniVision Camera Chip support"
- depends on VIDEO_DEV && I2C
+ depends on I2C && VIDEO_V4L1
---help---
Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
This driver is intended to be used with the ov511 and w9968cf USB
@@ -304,7 +319,7 @@ config VIDEO_OVCAMCHIP
config VIDEO_M32R_AR
tristate "AR devices"
- depends on M32R
+ depends on M32R && VIDEO_V4L1
---help---
This is a video4linux driver for the Renesas AR (Artificial Retina)
camera module.
@@ -365,17 +380,17 @@ config VIDEO_WM8739
source "drivers/media/video/cx25840/Kconfig"
config VIDEO_SAA711X
- tristate "Philips SAA7113/4/5 video decoders"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
+ depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
---help---
- Support for the Philips SAA7113/4/5 video decoders.
+ Old support for the Philips SAA7113/4 video decoders.
To compile this driver as a module, choose M here: the
module will be called saa7115.
config VIDEO_SAA7127
tristate "Philips SAA7127/9 digital video encoders"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
---help---
Support for the Philips SAA7127/9 digital video encoders.
@@ -384,7 +399,7 @@ config VIDEO_SAA7127
config VIDEO_UPD64031A
tristate "NEC Electronics uPD64031A Ghost Reduction"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
---help---
Support for the NEC Electronics uPD64031A Ghost Reduction
video chip. It is most often found in NTSC TV cards made for
@@ -396,7 +411,7 @@ config VIDEO_UPD64031A
config VIDEO_UPD64083
tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
---help---
Support for the NEC Electronics uPD64083 3-Dimensional Y/C
separation video chip. It is used to improve the quality of
@@ -418,7 +433,7 @@ source "drivers/media/video/em28xx/Kconfig"
config USB_DSBR
tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_DEV && EXPERIMENTAL
+ depends on USB && VIDEO_V4L1 && EXPERIMENTAL
---help---
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
@@ -434,7 +449,7 @@ source "drivers/media/video/et61x251/Kconfig"
config USB_OV511
tristate "USB OV511 Camera support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want to connect this type of camera to your
computer's USB port. See <file:Documentation/video4linux/ov511.txt>
@@ -445,7 +460,7 @@ config USB_OV511
config USB_SE401
tristate "USB SE401 Camera support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want to connect this type of camera to your
computer's USB port. See <file:Documentation/video4linux/se401.txt>
@@ -458,7 +473,7 @@ source "drivers/media/video/sn9c102/Kconfig"
config USB_STV680
tristate "USB STV680 (Pencam) Camera support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want to connect this type of camera to your
computer's USB port. This includes the Pencam line of cameras.
@@ -470,7 +485,7 @@ config USB_STV680
config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support"
- depends on USB && VIDEO_DEV && I2C
+ depends on USB && VIDEO_V4L1 && I2C
select VIDEO_OVCAMCHIP
---help---
Say Y here if you want support for cameras based on OV681 or
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b3ea2d63db9b..e5bf2687b76d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,11 @@ tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
+
+ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
+ obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
+endif
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_BT848) += tvaudio.o tda7432.o tda9875.o ir-kbd-i2c.o
@@ -84,4 +88,8 @@ obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
+obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
+
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 085477c12612..153f6a4a96c9 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
index db641a36b197..a096a03418aa 100644
--- a/drivers/media/video/bt8xx/Makefile
+++ b/drivers/media/video/bt8xx/Makefile
@@ -8,5 +8,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
obj-$(CONFIG_VIDEO_BT848) += bttv.o
-EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index f209a7492051..2b64aa835b42 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -2991,13 +2991,13 @@ void __devinit bttv_idcard(struct bttv *btv)
if (UNSET != audiomux[0]) {
gpiobits = 0;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < 4; i++) {
bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i];
gpiobits |= audiomux[i];
}
} else {
gpiobits = audioall;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < 4; i++) {
bttv_tvcards[btv->c.type].gpiomux[i] = audioall;
}
}
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index 16323a5d68ac..afcfe71e3792 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -233,7 +233,7 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int skip_even, int skip_odd)
{
- int instructions,rc,line,maxy,start,end,skip,nskips;
+ int dwords,rc,line,maxy,start,end,skip,nskips;
struct btcx_skiplist *skips;
u32 *rp,ri,ra;
u32 addr;
@@ -242,12 +242,12 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
return -ENOMEM;
- /* estimate risc mem: worst case is (clip+1) * lines instructions
+ /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
+ sync + jump (all 2 dwords) */
- instructions = (ov->nclips + 1) *
- ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) {
+ dwords = (3 * ov->nclips + 2) *
+ ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
+ dwords += 4;
+ if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
kfree(skips);
return rc;
}
@@ -276,8 +276,6 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
if (line > maxy)
btcx_calc_skips(line, ov->w.width, &maxy,
skips, &nskips, ov->clips, ov->nclips);
- else
- nskips = 0;
/* write out risc code */
for (start = 0, skip = 0; start < ov->w.width; start = end) {
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index f59ced181c55..1958d4016ea1 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -39,29 +39,12 @@
#define FWDEV(x) &((x)->adapter->dev)
-static int fastfw = 1;
static char *firmware = FWFILE;
-module_param(fastfw, bool, 0444);
module_param(firmware, charp, 0444);
-MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
-static void set_i2c_delay(struct i2c_client *client, int delay)
-{
- struct i2c_algo_bit_data *algod = client->adapter->algo_data;
-
- /* We aren't guaranteed to be using algo_bit,
- * so avoid the null pointer dereference
- * and disable the 'fast firmware load' */
- if (algod) {
- algod->udelay = delay;
- } else {
- fastfw = 0;
- }
-}
-
static void start_fw_load(struct i2c_client *client)
{
/* DL_ADDR_LB=0 DL_ADDR_HB=0 */
@@ -71,16 +54,10 @@ static void start_fw_load(struct i2c_client *client)
cx25840_write(client, 0x803, 0x0b);
/* AUTO_INC_DIS=1 */
cx25840_write(client, 0x000, 0x20);
-
- if (fastfw)
- set_i2c_delay(client, 3);
}
static void end_fw_load(struct i2c_client *client)
{
- if (fastfw)
- set_i2c_delay(client, 10);
-
/* AUTO_INC_DIS=0 */
cx25840_write(client, 0x000, 0x00);
/* DL_ENABLE=0 */
@@ -107,30 +84,8 @@ static int fw_write(struct i2c_client *client, u8 * data, int size)
int sent;
if ((sent = i2c_master_send(client, data, size)) < size) {
-
- if (fastfw) {
- v4l_err(client, "333MHz i2c firmware load failed\n");
- fastfw = 0;
- set_i2c_delay(client, 10);
-
- if (sent > 2) {
- u16 dl_addr = cx25840_read(client, 0x801) << 8;
- dl_addr |= cx25840_read(client, 0x800);
- dl_addr -= sent - 2;
- cx25840_write(client, 0x801, dl_addr >> 8);
- cx25840_write(client, 0x800, dl_addr & 0xff);
- }
-
- if (i2c_master_send(client, data, size) < size) {
- v4l_err(client, "100MHz i2c firmware load failed\n");
- return -ENOSYS;
- }
-
- } else {
- v4l_err(client, "firmware load i2c failure\n");
- return -ENOSYS;
- }
-
+ v4l_err(client, "firmware load i2c failure\n");
+ return -ENOSYS;
}
return 0;
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index f9d87b86492c..320b3d9384ba 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -616,7 +616,7 @@ static struct snd_kcontrol_new snd_cx88_capture_volume = {
* Only boards with eeprom and byte 1 at eeprom=1 have it
*/
-static struct pci_device_id cx88_audio_pci_tbl[] = {
+static struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
{0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
{0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
{0, }
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index c7042cf41231..f80154b87d22 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -564,7 +564,7 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_PCHDTV_HD3000] = {
.name = "pcHDTV HD3000 HDTV",
- .tuner_type = TUNER_THOMSON_DTT7610,
+ .tuner_type = TUNER_THOMSON_DTT761X,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 2c3d9f1999be..e1092d5d4628 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -146,9 +146,11 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
fields++;
/* estimate risc mem: worst case is one write per page border +
- one write per scan line + syncs + jump (all 2 dwords) */
- instructions = (bpl * lines * fields) / PAGE_SIZE + lines * fields;
- instructions += 3 + 4;
+ one write per scan line + syncs + jump (all 2 dwords). Padding
+ can cause next bpl to start close to a page border. First DMA
+ region may be smaller than PAGE_SIZE */
+ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions += 2;
if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
return rc;
@@ -176,9 +178,11 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int rc;
/* estimate risc mem: worst case is one write per page border +
- one write per scan line + syncs + jump (all 2 dwords) */
- instructions = (bpl * lines) / PAGE_SIZE + lines;
- instructions += 3 + 4;
+ one write per scan line + syncs + jump (all 2 dwords). Here
+ there is no padding and no sync. First DMA region may be smaller
+ than PAGE_SIZE */
+ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
+ instructions += 1;
if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
return rc;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index f0ea9b5cdbc2..3619a449aefd 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -372,7 +372,7 @@ static int or51132_set_ts_param(struct dvb_frontend* fe,
static struct or51132_config pchdtv_hd3000 = {
.demod_address = 0x15,
.pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt7610,
+ .pll_desc = &dvb_pll_thomson_dtt761x,
.set_ts_params = or51132_set_ts_param,
};
#endif
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 72a417b31745..694d1d80ff3f 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -35,8 +35,10 @@
#include "cx88.h"
#include <media/v4l2-common.h>
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* Include V4L1 specific functions. Should be removed soon */
#include <linux/videodev.h>
+#endif
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 5a793ae7cc23..dfb15bfb83dc 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_EM28XX
tristate "Empia EM2800/2820/2840 USB video capture support"
- depends on VIDEO_DEV && USB && I2C
+ depends on VIDEO_V4L1 && USB && I2C
select VIDEO_BUF
select VIDEO_TUNER
select VIDEO_TVEEPROM
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index ddc92cbb5276..cf7cdf9ef617 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1576,8 +1576,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
errCode = em28xx_config(dev);
if (errCode) {
em28xx_errdev("error configuring device\n");
- kfree(dev);
em28xx_devused&=~(1<<dev->devno);
+ kfree(dev);
return -ENOMEM;
}
@@ -1603,8 +1603,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->vdev = video_device_alloc();
if (NULL == dev->vdev) {
em28xx_errdev("cannot allocate video_device.\n");
- kfree(dev);
em28xx_devused&=~(1<<dev->devno);
+ kfree(dev);
return -ENOMEM;
}
@@ -1612,8 +1612,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (NULL == dev->vbi_dev) {
em28xx_errdev("cannot allocate video_device.\n");
kfree(dev->vdev);
- kfree(dev);
em28xx_devused&=~(1<<dev->devno);
+ kfree(dev);
return -ENOMEM;
}
@@ -1650,8 +1650,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
mutex_unlock(&dev->lock);
list_del(&dev->devlist);
video_device_release(dev->vdev);
- kfree(dev);
em28xx_devused&=~(1<<dev->devno);
+ kfree(dev);
return -ENODEV;
}
@@ -1662,8 +1662,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
list_del(&dev->devlist);
video_device_release(dev->vbi_dev);
video_device_release(dev->vdev);
- kfree(dev);
em28xx_devused&=~(1<<dev->devno);
+ kfree(dev);
return -ENODEV;
} else {
printk("registered VBI\n");
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index 6c43a90c6569..c6bff705688d 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,6 +1,6 @@
config USB_ET61X251
tristate "USB ET61X[12]51 PC Camera Controller support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want support for cameras based on Etoms ET61X151
or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 86376556f108..53cbc950f95c 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -1,6 +1,6 @@
config USB_PWC
tristate "USB Philips Cameras"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y or M here if you want to use one of these Philips & OEM
webcams:
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 8326684f49f3..33d60126c024 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -1,20 +1,3 @@
-ifneq ($(KERNELRELEASE),)
-
pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
obj-$(CONFIG_USB_PWC) += pwc.o
-
-else
-
-KDIR := /lib/modules/$(shell uname -r)/build
-PWD := $(shell pwd)
-
-default:
- $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
-
-endif
-
-clean:
- rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c
- rm -rf .tmp_versions
-
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 133f9e5252fe..c271e2e14105 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -142,6 +142,7 @@ struct i2c_reg_value {
static const struct i2c_reg_value saa7129_init_config_extra[] = {
{ SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
{ SAA7127_REG_VTRIG, 0xfa },
+ { 0, 0 }
};
static const struct i2c_reg_value saa7127_init_config_common[] = {
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index e666a4465ca4..86eae3528330 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -3504,6 +3504,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
+ break;
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
/* this turns the remote control chip off to work around a bug in it */
saa_writeb(SAA7134_GPIO_GPMODE1, 0x80);
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 13de05532e0a..f0c2111f14ad 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -548,6 +548,8 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
if (report & SAA7134_IRQ_REPORT_GPIO16) {
switch (dev->has_remote) {
case SAA7134_REMOTE_GPIO:
+ if (!dev->remote)
+ break;
if (dev->remote->mask_keydown & 0x10000) {
saa7134_input_irq(dev);
}
@@ -564,6 +566,8 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
if (report & SAA7134_IRQ_REPORT_GPIO18) {
switch (dev->has_remote) {
case SAA7134_REMOTE_GPIO:
+ if (!dev->remote)
+ break;
if ((dev->remote->mask_keydown & 0x40000) ||
(dev->remote->mask_keyup & 0x40000)) {
saa7134_input_irq(dev);
@@ -676,7 +680,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
SAA7134_IRQ2_INTE_PE |
SAA7134_IRQ2_INTE_AR;
- if (dev->has_remote == SAA7134_REMOTE_GPIO) {
+ if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) {
if (dev->remote->mask_keydown & 0x10000)
irq2_mask |= SAA7134_IRQ2_INTE_GPIO16;
else if (dev->remote->mask_keydown & 0x40000)
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index aeef80f88a6b..e4156ec9c6d7 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -31,8 +31,10 @@
#include "saa7134.h"
#include <media/v4l2-common.h>
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* Include V4L1 specific functions. Should be removed soon */
#include <linux/videodev.h>
+#endif
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
index 55f2bc11964b..cf552e6b8ecf 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -1,6 +1,6 @@
config USB_SN9C102
tristate "USB SN9C10x PC Camera Controller support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want support for cameras based on SONiX SN9C101,
SN9C102 or SN9C103 PC Camera Controllers.
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 72e0f01db563..a1ae036b44ec 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -877,8 +877,8 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x8e, 0x01 },
- { 16 * 455.00 /*MHz*/, 0x8e, 0x02 },
+ { 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
+ { 16 * 450.00 /*MHz*/, 0x8e, 0x02 },
{ 16 * 999.99 , 0x8e, 0x04 },
};
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 431c3e2f6c42..b463e996961a 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -218,7 +218,7 @@ hauppauge_tuner[] =
/* 110-119 */
{ TUNER_ABSENT, "Thompson DTT75105"},
{ TUNER_ABSENT, "Conexant_CX24109"},
- { TUNER_ABSENT, "TCL M2523_5N_E"},
+ { TUNER_TCL_2002N, "TCL M2523_5N_E"},
{ TUNER_ABSENT, "TCL M2523_3DB_E"},
{ TUNER_ABSENT, "Philips 8275A"},
{ TUNER_ABSENT, "Microtune MT2060"},
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 08a5d20bb2c0..39269a2c5635 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_USBVIDEO
config USB_VICAM
tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
- depends on USB && VIDEO_DEV && EXPERIMENTAL
+ depends on USB && VIDEO_V4L1 && EXPERIMENTAL
select VIDEO_USBVIDEO
---help---
Say Y here if you have 3com homeconnect camera (vicam).
@@ -13,7 +13,7 @@ config USB_VICAM
config USB_IBMCAM
tristate "USB IBM (Xirlink) C-it Camera support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want to connect a IBM "C-It" camera, also known as
@@ -28,7 +28,7 @@ config USB_IBMCAM
config USB_KONICAWC
tristate "USB Konica Webcam support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want support for webcams based on a Konica
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 5e813404d068..779db26771c0 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -26,6 +26,11 @@
#include <linux/random.h>
#include <linux/version.h>
#include <linux/videodev2.h>
+#include <linux/dma-mapping.h>
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+#endif
#include <linux/interrupt.h>
#include <media/video-buf.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index c3bf886b80cd..115833e4f4dd 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,6 +1,6 @@
config USB_ZC0301
tristate "USB ZC0301 Image Processor and Control Chip support"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_V4L1
---help---
Say Y here if you want support for cameras based on the ZC0301
Image Processor and Control Chip.
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 266414ca2814..a30084076ac8 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1189,7 +1189,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->diagPending = 0;
spin_lock_init(&ioc->diagLock);
spin_lock_init(&ioc->fc_rescan_work_lock);
- spin_lock_init(&ioc->fc_rport_lock);
spin_lock_init(&ioc->initializing_hba_lock);
/* Initialize the event logging.
@@ -1606,6 +1605,21 @@ mpt_resume(struct pci_dev *pdev)
}
#endif
+static int
+mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
+{
+ if ((MptDriverClass[index] == MPTSPI_DRIVER &&
+ ioc->bus_type != SPI) ||
+ (MptDriverClass[index] == MPTFC_DRIVER &&
+ ioc->bus_type != FC) ||
+ (MptDriverClass[index] == MPTSAS_DRIVER &&
+ ioc->bus_type != SAS))
+ /* make sure we only call the relevant reset handler
+ * for the bus */
+ return 0;
+ return (MptResetHandlers[index])(ioc, reset_phase);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mpt_do_ioc_recovery - Initialize or recover MPT adapter.
@@ -1886,14 +1900,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((ret == 0) && MptResetHandlers[ii]) {
dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
ioc->name, ii));
- rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
+ rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
handlers++;
}
if (alt_ioc_ready && MptResetHandlers[ii]) {
drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, ii));
- rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+ rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
}
}
@@ -3268,11 +3282,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
if (MptResetHandlers[ii]) {
dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
ioc->name, ii));
- r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
+ r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
if (ioc->alt_ioc) {
dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, ii));
- r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+ r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
}
}
@@ -5707,11 +5721,11 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
if (MptResetHandlers[ii]) {
dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
ioc->name, ii));
- r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
+ r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
if (ioc->alt_ioc) {
dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, ii));
- r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+ r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
}
}
}
@@ -5736,11 +5750,13 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
return rc;
}
+# define EVENT_DESCR_STR_SZ 100
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void
EventDescriptionStr(u8 event, u32 evData0, char *evStr)
{
- char *ds;
+ char *ds = NULL;
switch(event) {
case MPI_EVENT_NONE:
@@ -5777,9 +5793,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
ds = "Loop State(LIP) Change";
else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
- ds = "Loop State(LPE) Change"; /* ??? */
+ ds = "Loop State(LPE) Change"; /* ??? */
else
- ds = "Loop State(LPB) Change"; /* ??? */
+ ds = "Loop State(LPB) Change"; /* ??? */
break;
case MPI_EVENT_LOGOUT:
ds = "Logout";
@@ -5841,27 +5857,32 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
{
- char buf[50];
u8 id = (u8)(evData0);
u8 ReasonCode = (u8)(evData0 >> 16);
switch (ReasonCode) {
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
- sprintf(buf,"SAS Device Status Change: Added: id=%d", id);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Added: id=%d", id);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
- sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Deleted: id=%d", id);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
- sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: SMART Data: id=%d",
+ id);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
- sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: No Persistancy "
+ "Added: id=%d", id);
break;
default:
- sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id);
- break;
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Unknown: id=%d", id);
+ break;
}
- ds = buf;
break;
}
case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
@@ -5878,41 +5899,46 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_SAS_PHY_LINK_STATUS:
{
- char buf[50];
u8 LinkRates = (u8)(evData0 >> 8);
u8 PhyNumber = (u8)(evData0);
LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
switch (LinkRates) {
case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Rate Unknown",PhyNumber);
break;
case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Phy Disabled",PhyNumber);
break;
case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Failed Speed Nego",PhyNumber);
break;
case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Sata OOB Completed",PhyNumber);
break;
case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Rate 1.5 Gbps",PhyNumber);
break;
case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
- sprintf(buf,"SAS PHY Link Status: Phy=%d:"
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
" Rate 3.0 Gpbs",PhyNumber);
break;
default:
- sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d", PhyNumber);
break;
}
- ds = buf;
break;
}
case MPI_EVENT_SAS_DISCOVERY_ERROR:
@@ -5921,9 +5947,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
case MPI_EVENT_IR_RESYNC_UPDATE:
{
u8 resync_complete = (u8)(evData0 >> 16);
- char buf[40];
- sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete);
- ds = buf;
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "IR Resync Update: Complete = %d:",resync_complete);
break;
}
case MPI_EVENT_IR2:
@@ -5976,7 +6001,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
ds = "Unknown";
break;
}
- strcpy(evStr,ds);
+ if (ds)
+ strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5998,7 +6024,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
int ii;
int r = 0;
int handlers = 0;
- char evStr[100];
+ char evStr[EVENT_DESCR_STR_SZ];
u8 event;
/*
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index be7e8501b53c..f673cca507e1 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.03.08"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.08"
+#define MPT_LINUX_VERSION_COMMON "3.03.09"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.09"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -489,7 +489,6 @@ typedef struct _RaidCfgData {
#define MPT_RPORT_INFO_FLAGS_REGISTERED 0x01 /* rport registered */
#define MPT_RPORT_INFO_FLAGS_MISSING 0x02 /* missing from DevPage0 scan */
-#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04 /* target mapped in vdev */
/*
* data allocated for each fc rport device
@@ -501,7 +500,6 @@ struct mptfc_rport_info
struct scsi_target *starget;
FCDevicePage0_t pg0;
u8 flags;
- u8 remap_needed;
};
/*
@@ -628,11 +626,11 @@ typedef struct _MPT_ADAPTER
struct work_struct mptscsih_persistTask;
struct list_head fc_rports;
- spinlock_t fc_rport_lock; /* list and ri flags */
spinlock_t fc_rescan_work_lock;
int fc_rescan_work_count;
struct work_struct fc_rescan_work;
-
+ char fc_rescan_work_q_name[KOBJ_NAME_LEN];
+ struct workqueue_struct *fc_rescan_work_q;
} MPT_ADAPTER;
/*
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index b343f2a68b1c..856487741ef4 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
rid->port_id = pg0->PortIdentifier;
rid->roles = FC_RPORT_ROLE_UNKNOWN;
- rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
- if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
- rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
return 0;
}
@@ -355,15 +352,18 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
struct fc_rport *rport;
struct mptfc_rport_info *ri;
int new_ri = 1;
- u64 pn;
- unsigned long flags;
+ u64 pn, nn;
VirtTarget *vtarget;
+ u32 roles = FC_RPORT_ROLE_UNKNOWN;
if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
return;
+ roles |= FC_RPORT_ROLE_FCP_TARGET;
+ if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+ roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
/* scan list looking for a match */
- spin_lock_irqsave(&ioc->fc_rport_lock, flags);
list_for_each_entry(ri, &ioc->fc_rports, list) {
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
if (pn == rport_ids.port_name) { /* match */
@@ -373,11 +373,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
}
}
if (new_ri) { /* allocate one */
- spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
if (!ri)
return;
- spin_lock_irqsave(&ioc->fc_rport_lock, flags);
list_add_tail(&ri->list, &ioc->fc_rports);
}
@@ -387,14 +385,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
- spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
- spin_lock_irqsave(&ioc->fc_rport_lock, flags);
if (rport) {
ri->rport = rport;
if (new_ri) /* may have been reset by user */
rport->dev_loss_tmo = mptfc_dev_loss_tmo;
- *((struct mptfc_rport_info **)rport->dd_data) = ri;
/*
* if already mapped, remap here. If not mapped,
* target_alloc will allocate vtarget and map,
@@ -406,16 +401,21 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
vtarget->target_id = pg0->CurrentTargetID;
vtarget->bus_id = pg0->CurrentBus;
}
- ri->remap_needed = 0;
}
+ *((struct mptfc_rport_info **)rport->dd_data) = ri;
+ /* scan will be scheduled once rport becomes a target */
+ fc_remote_port_rolechg(rport,roles);
+
+ pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+ nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
dfcprintk ((MYIOC_s_INFO_FMT
"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
"rport tid %d, tmo %d\n",
ioc->name,
ioc->sh->host_no,
pg0->PortIdentifier,
- pg0->WWNN,
- pg0->WWPN,
+ (unsigned long long)nn,
+ (unsigned long long)pn,
pg0->CurrentTargetID,
ri->rport->scsi_target_id,
ri->rport->dev_loss_tmo));
@@ -425,8 +425,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
ri = NULL;
}
}
- spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
-
}
/*
@@ -476,7 +474,6 @@ mptfc_target_alloc(struct scsi_target *starget)
vtarget->target_id = ri->pg0.CurrentTargetID;
vtarget->bus_id = ri->pg0.CurrentBus;
ri->starget = starget;
- ri->remap_needed = 0;
rc = 0;
}
}
@@ -502,10 +499,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
VirtDevice *vdev;
struct scsi_target *starget;
struct fc_rport *rport;
- unsigned long flags;
- rport = starget_to_rport(scsi_target(sdev));
+ starget = scsi_target(sdev);
+ rport = starget_to_rport(starget);
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
@@ -519,10 +516,8 @@ mptfc_slave_alloc(struct scsi_device *sdev)
return -ENOMEM;
}
- spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
sdev->hostdata = vdev;
- starget = scsi_target(sdev);
vtarget = starget->hostdata;
if (vtarget->num_luns == 0) {
@@ -535,14 +530,16 @@ mptfc_slave_alloc(struct scsi_device *sdev)
vdev->vtarget = vtarget;
vdev->lun = sdev->lun;
- spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
-
vtarget->num_luns++;
+
#ifdef DMPT_DEBUG_FC
- {
+ {
+ u64 nn, pn;
struct mptfc_rport_info *ri;
ri = *((struct mptfc_rport_info **)rport->dd_data);
+ pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+ nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
dfcprintk ((MYIOC_s_INFO_FMT
"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
"CurrentTargetID %d, %x %llx %llx\n",
@@ -550,7 +547,9 @@ mptfc_slave_alloc(struct scsi_device *sdev)
sdev->host->host_no,
vtarget->num_luns,
sdev->id, ri->pg0.CurrentTargetID,
- ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
+ ri->pg0.PortIdentifier,
+ (unsigned long long)pn,
+ (unsigned long long)nn));
}
#endif
@@ -570,11 +569,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
done(SCpnt);
return 0;
}
+
+ /* dd_data is null until finished adding target */
ri = *((struct mptfc_rport_info **)rport->dd_data);
- if (unlikely(ri->remap_needed))
- return SCSI_MLQUEUE_HOST_BUSY;
+ if (unlikely(!ri)) {
+ dfcprintk ((MYIOC_s_INFO_FMT
+ "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
+ ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
+ ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
+ SCpnt->device->id,SCpnt->device->lun));
+ SCpnt->result = DID_IMM_RETRY << 16;
+ done(SCpnt);
+ return 0;
+ }
- return mptscsih_qcmd(SCpnt,done);
+ err = mptscsih_qcmd(SCpnt,done);
+#ifdef DMPT_DEBUG_FC
+ if (unlikely(err)) {
+ dfcprintk ((MYIOC_s_INFO_FMT
+ "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n",
+ ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
+ ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
+ SCpnt->device->id,SCpnt->device->lun));
+ }
+#endif
+ return err;
}
static void
@@ -615,18 +634,17 @@ mptfc_rescan_devices(void *arg)
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
int ii;
int work_to_do;
+ u64 pn;
unsigned long flags;
struct mptfc_rport_info *ri;
do {
/* start by tagging all ports as missing */
- spin_lock_irqsave(&ioc->fc_rport_lock,flags);
list_for_each_entry(ri, &ioc->fc_rports, list) {
if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
}
}
- spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
/*
* now rescan devices known to adapter,
@@ -639,33 +657,24 @@ mptfc_rescan_devices(void *arg)
}
/* delete devices still missing */
- spin_lock_irqsave(&ioc->fc_rport_lock, flags);
list_for_each_entry(ri, &ioc->fc_rports, list) {
/* if newly missing, delete it */
- if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
- MPT_RPORT_INFO_FLAGS_MISSING))
- == (MPT_RPORT_INFO_FLAGS_REGISTERED |
- MPT_RPORT_INFO_FLAGS_MISSING)) {
+ if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
MPT_RPORT_INFO_FLAGS_MISSING);
- ri->remap_needed = 1;
- fc_remote_port_delete(ri->rport);
- /*
- * remote port not really deleted 'cause
- * binding is by WWPN and driver only
- * registers FCP_TARGETs but cannot trust
- * data structures.
- */
+ fc_remote_port_delete(ri->rport); /* won't sleep */
ri->rport = NULL;
+
+ pn = (u64)ri->pg0.WWPN.High << 32 |
+ (u64)ri->pg0.WWPN.Low;
dfcprintk ((MYIOC_s_INFO_FMT
"mptfc_rescan.%d: %llx deleted\n",
ioc->name,
ioc->sh->host_no,
- ri->pg0.WWPN));
+ (unsigned long long)pn));
}
}
- spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
/*
* allow multiple passes as target state
@@ -870,10 +879,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_mptfc_probe;
}
- for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
- mptfc_init_host_attr(ioc,ii);
- mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
- }
+ /* initialize workqueue */
+
+ snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
+ sh->host_no);
+ ioc->fc_rescan_work_q =
+ create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
+ if (!ioc->fc_rescan_work_q)
+ goto out_mptfc_probe;
+
+ /*
+ * scan for rports -
+ * by doing it via the workqueue, some locking is eliminated
+ */
+
+ ioc->fc_rescan_work_count = 1;
+ queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
+ flush_workqueue(ioc->fc_rescan_work_q);
return 0;
@@ -949,8 +971,18 @@ mptfc_init(void)
static void __devexit
mptfc_remove(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct mptfc_rport_info *p, *n;
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ struct mptfc_rport_info *p, *n;
+ struct workqueue_struct *work_q;
+ unsigned long flags;
+
+ /* destroy workqueue */
+ if ((work_q=ioc->fc_rescan_work_q)) {
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+ ioc->fc_rescan_work_q = NULL;
+ spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+ destroy_workqueue(work_q);
+ }
fc_remove_host(ioc->sh);
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index e9716b10acea..af6ec553ff7c 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -91,6 +91,7 @@ enum mptsas_hotplug_action {
MPTSAS_DEL_DEVICE,
MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID,
+ MPTSAS_IGNORE_EVENT,
};
struct mptsas_hotplug_event {
@@ -298,6 +299,26 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
return rc;
}
+/*
+ * Returns true if there is a scsi end device
+ */
+static inline int
+mptsas_is_end_device(struct mptsas_devinfo * attached)
+{
+ if ((attached->handle) &&
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_END_DEVICE) &&
+ ((attached->device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET) |
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_STP_TARGET) |
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
+ return 1;
+ else
+ return 0;
+}
+
static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
u32 form, u32 form_specific)
@@ -872,7 +893,11 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
SasDevicePage0_t *buffer;
dma_addr_t dma_handle;
__le64 sas_address;
- int error;
+ int error=0;
+
+ if (ioc->sas_discovery_runtime &&
+ mptsas_is_end_device(device_info))
+ goto out;
hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
hdr.ExtPageLength = 0;
@@ -1009,7 +1034,11 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
CONFIGPARMS cfg;
SasExpanderPage1_t *buffer;
dma_addr_t dma_handle;
- int error;
+ int error=0;
+
+ if (ioc->sas_discovery_runtime &&
+ mptsas_is_end_device(&phy_info->attached))
+ goto out;
hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
hdr.ExtPageLength = 0;
@@ -1068,26 +1097,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
return error;
}
-/*
- * Returns true if there is a scsi end device
- */
-static inline int
-mptsas_is_end_device(struct mptsas_devinfo * attached)
-{
- if ((attached->handle) &&
- (attached->device_info &
- MPI_SAS_DEVICE_INFO_END_DEVICE) &&
- ((attached->device_info &
- MPI_SAS_DEVICE_INFO_SSP_TARGET) |
- (attached->device_info &
- MPI_SAS_DEVICE_INFO_STP_TARGET) |
- (attached->device_info &
- MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
- return 1;
- else
- return 0;
-}
-
static void
mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info)
@@ -1737,6 +1746,9 @@ mptsas_hotplug_work(void *arg)
break;
case MPTSAS_ADD_DEVICE:
+ if (ev->phys_disk_num_valid)
+ mpt_findImVolumes(ioc);
+
/*
* Refresh sas device pg0 data
*/
@@ -1868,6 +1880,9 @@ mptsas_hotplug_work(void *arg)
scsi_device_put(sdev);
mpt_findImVolumes(ioc);
break;
+ case MPTSAS_IGNORE_EVENT:
+ default:
+ break;
}
kfree(ev);
@@ -1940,7 +1955,8 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
EVENT_DATA_RAID *raid_event_data)
{
struct mptsas_hotplug_event *ev;
- RAID_VOL0_STATUS * volumeStatus;
+ int status = le32_to_cpu(raid_event_data->SettingsStatus);
+ int state = (status >> 8) & 0xff;
if (ioc->bus_type != SAS)
return;
@@ -1955,6 +1971,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
ev->ioc = ioc;
ev->id = raid_event_data->VolumeID;
+ ev->event_type = MPTSAS_IGNORE_EVENT;
switch (raid_event_data->ReasonCode) {
case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
@@ -1966,6 +1983,25 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->event_type = MPTSAS_DEL_DEVICE;
break;
+ case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
+ switch (state) {
+ case MPI_PD_STATE_ONLINE:
+ ioc->raid_data.isRaid = 1;
+ ev->phys_disk_num_valid = 1;
+ ev->phys_disk_num = raid_event_data->PhysDiskNum;
+ ev->event_type = MPTSAS_ADD_DEVICE;
+ break;
+ case MPI_PD_STATE_MISSING:
+ case MPI_PD_STATE_NOT_COMPATIBLE:
+ case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
+ case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
+ case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
+ ev->event_type = MPTSAS_DEL_DEVICE;
+ break;
+ default:
+ break;
+ }
+ break;
case MPI_EVENT_RAID_RC_VOLUME_DELETED:
ev->event_type = MPTSAS_DEL_RAID;
break;
@@ -1973,11 +2009,18 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
ev->event_type = MPTSAS_ADD_RAID;
break;
case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
- volumeStatus = (RAID_VOL0_STATUS *) &
- raid_event_data->SettingsStatus;
- ev->event_type = (volumeStatus->State ==
- MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
- MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
+ switch (state) {
+ case MPI_RAIDVOL0_STATUS_STATE_FAILED:
+ case MPI_RAIDVOL0_STATUS_STATE_MISSING:
+ ev->event_type = MPTSAS_DEL_RAID;
+ break;
+ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
+ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
+ ev->event_type = MPTSAS_ADD_RAID;
+ break;
+ default:
+ break;
+ }
break;
default:
break;
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 3729062db317..84fa271eb8f4 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -632,7 +632,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
/* Spoof to SCSI Selection Timeout! */
- sc->result = DID_NO_CONNECT << 16;
+ if (ioc->bus_type != FC)
+ sc->result = DID_NO_CONNECT << 16;
+ /* else fibre, just stall until rescan event */
+ else
+ sc->result = DID_REQUEUE << 16;
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
@@ -877,7 +881,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
struct scsi_cmnd *sc;
dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
- vdevice->target_id, vdevice->lun, max));
+ vdevice->vtarget->target_id, vdevice->lun, max));
for (ii=0; ii < max; ii++) {
if ((sc = hd->ScsiLookup[ii]) != NULL) {
@@ -1645,7 +1649,6 @@ int
mptscsih_abort(struct scsi_cmnd * SCpnt)
{
MPT_SCSI_HOST *hd;
- MPT_ADAPTER *ioc;
MPT_FRAME_HDR *mf;
u32 ctx2abort;
int scpnt_idx;
@@ -1663,14 +1666,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
return FAILED;
}
- ioc = hd->ioc;
- if (hd->resetPending) {
- return FAILED;
- }
-
- if (hd->timeouts < -1)
- hd->timeouts++;
-
/* Find this command
*/
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -1684,6 +1679,13 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
return SUCCESS;
}
+ if (hd->resetPending) {
+ return FAILED;
+ }
+
+ if (hd->timeouts < -1)
+ hd->timeouts++;
+
printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
hd->ioc->name, SCpnt);
scsi_print_command(SCpnt);
@@ -1703,7 +1705,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
- ctx2abort, mptscsih_get_tm_timeout(ioc));
+ ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
hd->ioc->name,
@@ -2521,15 +2523,15 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
/* 7. FC: Rescan for blocked rports which might have returned.
*/
- else if (ioc->bus_type == FC) {
- int work_count;
- unsigned long flags;
-
+ if (ioc->bus_type == FC) {
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
- work_count = ++ioc->fc_rescan_work_count;
+ if (ioc->fc_rescan_work_q) {
+ if (ioc->fc_rescan_work_count++ == 0) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_rescan_work);
+ }
+ }
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
- if (work_count == 1)
- schedule_work(&ioc->fc_rescan_work);
}
dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
@@ -2544,7 +2546,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
MPT_SCSI_HOST *hd;
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- int work_count;
unsigned long flags;
devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
@@ -2569,10 +2570,13 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_RESCAN: /* 06 */
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
- work_count = ++ioc->fc_rescan_work_count;
+ if (ioc->fc_rescan_work_q) {
+ if (ioc->fc_rescan_work_count++ == 0) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_rescan_work);
+ }
+ }
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
- if (work_count == 1)
- schedule_work(&ioc->fc_rescan_work);
break;
/*
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 09c745b19cc8..3201de053943 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -783,6 +783,72 @@ static struct pci_device_id mptspi_pci_table[] = {
};
MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
+
+/*
+ * renegotiate for a given target
+ */
+static void
+mptspi_dv_renegotiate_work(void *data)
+{
+ struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+ struct _MPT_SCSI_HOST *hd = wqw->hd;
+ struct scsi_device *sdev;
+
+ kfree(wqw);
+
+ shost_for_each_device(sdev, hd->ioc->sh)
+ mptspi_dv_device(hd, sdev);
+}
+
+static void
+mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
+{
+ struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
+
+ if (!wqw)
+ return;
+
+ INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw);
+ wqw->hd = hd;
+
+ schedule_work(&wqw->work);
+}
+
+/*
+ * spi module reset handler
+ */
+static int
+mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+ struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ int rc;
+
+ rc = mptscsih_ioc_reset(ioc, reset_phase);
+
+ if (reset_phase == MPT_IOC_POST_RESET)
+ mptspi_dv_renegotiate(hd);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+/*
+ * spi module resume handler
+ */
+static int
+mptspi_resume(struct pci_dev *pdev)
+{
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ int rc;
+
+ rc = mptscsih_resume(pdev);
+ mptspi_dv_renegotiate(hd);
+
+ return rc;
+}
+#endif
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -1032,7 +1098,7 @@ static struct pci_driver mptspi_driver = {
.shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
- .resume = mptscsih_resume,
+ .resume = mptspi_resume,
#endif
};
@@ -1061,7 +1127,7 @@ mptspi_init(void)
": Registered for IOC event notifications\n"));
}
- if (mpt_reset_register(mptspiDoneCtx, mptscsih_ioc_reset) == 0) {
+ if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) {
dprintk((KERN_INFO MYNAM
": Registered for IOC reset notifications\n"));
}
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 5ea133c59afb..7bd4d85d0b42 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -55,6 +55,7 @@ struct i2o_exec_wait {
u32 m; /* message id */
struct i2o_message *msg; /* pointer to the reply message */
struct list_head list; /* node in global wait list */
+ spinlock_t lock; /* lock before modifying */
};
/* Work struct needed to handle LCT NOTIFY replies */
@@ -87,6 +88,7 @@ static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
return NULL;
INIT_LIST_HEAD(&wait->list);
+ spin_lock_init(&wait->lock);
return wait;
};
@@ -125,6 +127,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
DECLARE_WAIT_QUEUE_HEAD(wq);
struct i2o_exec_wait *wait;
static u32 tcntxt = 0x80000000;
+ long flags;
int rc = 0;
wait = i2o_exec_wait_alloc();
@@ -146,33 +149,28 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
wait->tcntxt = tcntxt++;
msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
+ wait->wq = &wq;
+ /*
+ * we add elements to the head, because if a entry in the list will
+ * never be removed, we have to iterate over it every time
+ */
+ list_add(&wait->list, &i2o_exec_wait_list);
+
/*
* Post the message to the controller. At some point later it will
* return. If we time out before it returns then complete will be zero.
*/
i2o_msg_post(c, msg);
- if (!wait->complete) {
- wait->wq = &wq;
- /*
- * we add elements add the head, because if a entry in the list
- * will never be removed, we have to iterate over it every time
- */
- list_add(&wait->list, &i2o_exec_wait_list);
-
- wait_event_interruptible_timeout(wq, wait->complete,
- timeout * HZ);
+ wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
- wait->wq = NULL;
- }
+ spin_lock_irqsave(&wait->lock, flags);
- barrier();
+ wait->wq = NULL;
- if (wait->complete) {
+ if (wait->complete)
rc = le32_to_cpu(wait->msg->body[0]) >> 24;
- i2o_flush_reply(c, wait->m);
- i2o_exec_wait_free(wait);
- } else {
+ else {
/*
* We cannot remove it now. This is important. When it does
* terminate (which it must do if the controller has not
@@ -186,6 +184,13 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
rc = -ETIMEDOUT;
}
+ spin_unlock_irqrestore(&wait->lock, flags);
+
+ if (rc != -ETIMEDOUT) {
+ i2o_flush_reply(c, wait->m);
+ i2o_exec_wait_free(wait);
+ }
+
return rc;
};
@@ -213,7 +218,6 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
{
struct i2o_exec_wait *wait, *tmp;
unsigned long flags;
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
int rc = 1;
/*
@@ -223,23 +227,24 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
* already expired. Not much we can do about that except log it for
* debug purposes, increase timeout, and recompile.
*/
- spin_lock_irqsave(&lock, flags);
list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
if (wait->tcntxt == context) {
- list_del(&wait->list);
+ spin_lock_irqsave(&wait->lock, flags);
- spin_unlock_irqrestore(&lock, flags);
+ list_del(&wait->list);
wait->m = m;
wait->msg = msg;
wait->complete = 1;
- barrier();
-
- if (wait->wq) {
- wake_up_interruptible(wait->wq);
+ if (wait->wq)
rc = 0;
- } else {
+ else
+ rc = -1;
+
+ spin_unlock_irqrestore(&wait->lock, flags);
+
+ if (rc) {
struct device *dev;
dev = &c->pdev->dev;
@@ -248,15 +253,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
c->name);
i2o_dma_free(dev, &wait->dma);
i2o_exec_wait_free(wait);
- rc = -1;
- }
+ } else
+ wake_up_interruptible(wait->wq);
return rc;
}
}
- spin_unlock_irqrestore(&lock, flags);
-
osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
context);
@@ -322,14 +325,9 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
static int i2o_exec_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_controller *c = i2o_dev->iop;
i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
- c->exec = i2o_dev;
-
- i2o_exec_lct_notify(c, c->lct->change_ind + 1);
-
device_create_file(dev, &dev_attr_vendor_id);
device_create_file(dev, &dev_attr_product_id);
@@ -523,6 +521,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
struct device *dev;
struct i2o_message *msg;
+ down(&c->lct_lock);
+
dev = &c->pdev->dev;
if (i2o_dma_realloc
@@ -545,6 +545,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
i2o_msg_post(c, msg);
+ up(&c->lct_lock);
+
return 0;
};
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 492167446936..febbdd4e0605 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -804,8 +804,6 @@ void i2o_iop_remove(struct i2o_controller *c)
/* Ask the IOP to switch to RESET state */
i2o_iop_reset(c);
-
- put_device(&c->device);
}
/**
@@ -1059,7 +1057,7 @@ struct i2o_controller *i2o_iop_alloc(void)
snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name);
if (i2o_pool_alloc
- (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4,
+ (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32),
I2O_MSG_INPOOL_MIN)) {
kfree(c);
return ERR_PTR(-ENOMEM);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 003b077c2324..45bcf098e762 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -84,7 +84,7 @@ config MMC_WBSD
config MMC_AU1X
tristate "Alchemy AU1XX0 MMC Card Interface support"
- depends on SOC_AU1X00 && MMC
+ depends on MMC && SOC_AU1200
help
This selects the AMD Alchemy(R) Multimedia card interface.
If you have a Alchemy platform with a MMC slot, say Y or M here.
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index 6061c2d101a0..88f0eef9cf33 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -621,9 +621,6 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct at91mci_host *host = mmc_priv(mmc);
unsigned long at91_master_clock = clk_get_rate(mci_clk);
- DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
-
if (host)
host->bus_mode = ios->bus_mode;
else
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index c0326bbc5f28..5dc4bee7abeb 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -310,7 +310,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
}
else
data->bytes_xfered =
- (data->blocks * (1 << data->blksz_bits)) -
+ (data->blocks * data->blksz) -
host->pio.len;
}
@@ -575,7 +575,7 @@ static int
au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
{
- int datalen = data->blocks * (1 << data->blksz_bits);
+ int datalen = data->blocks * data->blksz;
if (dma != 0)
host->flags |= HOST_F_DMA;
@@ -596,7 +596,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
if (host->dma.len == 0)
return MMC_ERR_TIMEOUT;
- au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host));
+ au_writel(data->blksz - 1, HOST_BLKSIZE(host));
if (host->flags & HOST_F_DMA) {
int i;
@@ -720,10 +720,6 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
{
struct au1xmmc_host *host = mmc_priv(mmc);
- DBG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n",
- host->id, ios->power_mode, ios->clock, ios->vdd,
- ios->bus_mode);
-
if (ios->power_mode == MMC_POWER_OFF)
au1xmmc_set_power(host, 0);
else if (ios->power_mode == MMC_POWER_ON) {
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index ffb7f55d3467..a4eb1d0e7a71 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -102,6 +102,7 @@ struct imxmci_host {
#define IMXMCI_PEND_CPU_DATA_b 5
#define IMXMCI_PEND_CARD_XCHG_b 6
#define IMXMCI_PEND_SET_INIT_b 7
+#define IMXMCI_PEND_STARTED_b 8
#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b)
#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b)
@@ -111,6 +112,7 @@ struct imxmci_host {
#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b)
#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
+#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b)
static void imxmci_stop_clock(struct imxmci_host *host)
{
@@ -131,23 +133,52 @@ static void imxmci_stop_clock(struct imxmci_host *host)
dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
}
-static void imxmci_start_clock(struct imxmci_host *host)
+static int imxmci_start_clock(struct imxmci_host *host)
{
- int i = 0;
+ unsigned int trials = 0;
+ unsigned int delay_limit = 128;
+ unsigned long flags;
+
MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
- while(i < 0x1000) {
- if(!(i & 0x7f))
- MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
- if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) {
- /* Check twice before cut */
+ clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
+
+ /*
+ * Command start of the clock, this usually succeeds in less
+ * then 6 delay loops, but during card detection (low clockrate)
+ * it takes up to 5000 delay loops and sometimes fails for the first time
+ */
+ MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+
+ do {
+ unsigned int delay = delay_limit;
+
+ while(delay--){
if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
- return;
+ /* Check twice before cut */
+ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+ return 0;
+
+ if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+ return 0;
}
- i++;
- }
- dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+ local_irq_save(flags);
+ /*
+ * Ensure, that request is not doubled under all possible circumstances.
+ * It is possible, that cock running state is missed, because some other
+ * IRQ or schedule delays this function execution and the clocks has
+ * been already stopped by other means (response processing, SDHC HW)
+ */
+ if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+ MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+ local_irq_restore(flags);
+
+ } while(++trials<256);
+
+ dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+
+ return -1;
}
static void imxmci_softreset(void)
@@ -187,8 +218,10 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host,
if(!loops)
return 0;
- dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
- loops, where, *pstat, stat_mask);
+ /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
+ if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
+ dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
+ loops, where, *pstat, stat_mask);
return loops;
}
@@ -302,6 +335,9 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
WARN_ON(host->cmd != NULL);
host->cmd = cmd;
+ /* Ensure, that clock are stopped else command programming and start fails */
+ imxmci_stop_clock(host);
+
if (cmd->flags & MMC_RSP_BUSY)
cmdat |= CMD_DAT_CONT_BUSY;
@@ -498,7 +534,7 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
data_error = imxmci_finish_data(host, stat);
- if (host->req->stop && (data_error == MMC_ERR_NONE)) {
+ if (host->req->stop) {
imxmci_stop_clock(host);
imxmci_start_cmd(host, host->req->stop, 0);
} else {
@@ -522,7 +558,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
int trans_done = 0;
unsigned int stat = *pstat;
- if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+ if(host->actual_bus_width != MMC_BUS_WIDTH_4)
burst_len = 16;
else
burst_len = 64;
@@ -560,8 +596,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
stat = MMC_STATUS;
/* Flush extra bytes from FIFO */
- while(flush_len >= 2){
- flush_len -= 2;
+ while(flush_len && !(stat & STATUS_DATA_TRANS_DONE)){
i = MMC_BUFFER_ACCESS;
stat = MMC_STATUS;
stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */
@@ -622,6 +657,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
atomic_set(&host->stuck_timeout, 0);
host->status_reg = stat;
set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+ set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
tasklet_schedule(&host->tasklet);
return IRQ_RETVAL(handled);;
@@ -714,10 +750,6 @@ static void imxmci_tasklet_fnc(unsigned long data)
data_dir_mask = STATUS_DATA_TRANS_DONE;
}
- imxmci_busy_wait_for_status(host, &stat,
- data_dir_mask,
- 50, "imxmci_tasklet_fnc data");
-
if(stat & data_dir_mask) {
clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
imxmci_data_done(host, stat);
@@ -775,10 +807,6 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct imxmci_host *host = mmc_priv(mmc);
int prescaler;
- dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n",
- ios->clock, ios->power_mode, ios->vdd,
- (ios->bus_width==MMC_BUS_WIDTH_4)?4:1);
-
if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
host->actual_bus_width = MMC_BUS_WIDTH_4;
imx_gpio_mode(PB11_PF_SD_DAT3);
@@ -837,7 +865,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
imxmci_stop_clock(host);
MMC_CLK_RATE = (prescaler<<3) | clk;
- imxmci_start_clock(host);
+ /*
+ * Under my understanding, clock should not be started there, because it would
+ * initiate SDHC sequencer and send last or random command into card
+ */
+ /*imxmci_start_clock(host);*/
dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
} else {
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index da6ddd910fc5..6201f3086a02 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -59,21 +59,23 @@ static const unsigned int tacc_mant[] = {
/**
- * mmc_request_done - finish processing an MMC command
- * @host: MMC host which completed command
- * @mrq: MMC request which completed
+ * mmc_request_done - finish processing an MMC request
+ * @host: MMC host which completed request
+ * @mrq: MMC request which request
*
* MMC drivers should call this function when they have completed
- * their processing of a command. This should be called before the
- * data part of the command has completed.
+ * their processing of a request.
*/
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
- int err = mrq->cmd->error;
- pr_debug("MMC: req done (%02x): %d: %08x %08x %08x %08x\n",
- cmd->opcode, err, cmd->resp[0], cmd->resp[1],
- cmd->resp[2], cmd->resp[3]);
+ int err = cmd->error;
+
+ pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), cmd->opcode, err,
+ mrq->data ? mrq->data->error : 0,
+ mrq->stop ? mrq->stop->error : 0,
+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
if (err && cmd->retries) {
cmd->retries--;
@@ -97,8 +99,9 @@ EXPORT_SYMBOL(mmc_request_done);
void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
- pr_debug("MMC: starting cmd %02x arg %08x flags %08x\n",
- mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+ pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->cmd->opcode,
+ mrq->cmd->arg, mrq->cmd->flags);
WARN_ON(host->card_busy == NULL);
@@ -312,6 +315,18 @@ void mmc_release_host(struct mmc_host *host)
EXPORT_SYMBOL(mmc_release_host);
+static inline void mmc_set_ios(struct mmc_host *host)
+{
+ struct mmc_ios *ios = &host->ios;
+
+ pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+ mmc_hostname(host), ios->clock, ios->bus_mode,
+ ios->power_mode, ios->chip_select, ios->vdd,
+ ios->bus_width);
+
+ host->ops->set_ios(host, ios);
+}
+
static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@@ -364,7 +379,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
}
}
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
return MMC_ERR_NONE;
}
@@ -415,7 +430,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
ocr = 3 << bit;
host->ios.vdd = bit;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
} else {
ocr = 0;
}
@@ -549,6 +564,7 @@ static void mmc_decode_csd(struct mmc_card *card)
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
} else {
@@ -583,6 +599,7 @@ static void mmc_decode_csd(struct mmc_card *card)
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
}
@@ -666,7 +683,7 @@ static void mmc_idle_cards(struct mmc_host *host)
struct mmc_command cmd;
host->ios.chip_select = MMC_CS_HIGH;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
mmc_delay(1);
@@ -679,7 +696,7 @@ static void mmc_idle_cards(struct mmc_host *host)
mmc_delay(1);
host->ios.chip_select = MMC_CS_DONTCARE;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
mmc_delay(1);
}
@@ -704,13 +721,13 @@ static void mmc_power_up(struct mmc_host *host)
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
mmc_delay(1);
host->ios.clock = host->f_min;
host->ios.power_mode = MMC_POWER_ON;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
mmc_delay(2);
}
@@ -723,7 +740,7 @@ static void mmc_power_off(struct mmc_host *host)
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
}
static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
@@ -934,6 +951,7 @@ static void mmc_read_scrs(struct mmc_host *host)
data.timeout_ns = card->csd.tacc_ns * 10;
data.timeout_clks = card->csd.tacc_clks * 10;
data.blksz_bits = 3;
+ data.blksz = 1 << 3;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
@@ -971,7 +989,8 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host)
if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
max_dtr = card->csd.max_dtr;
- pr_debug("MMC: selected %d.%03dMHz transfer rate\n",
+ pr_debug("%s: selected %d.%03dMHz transfer rate\n",
+ mmc_hostname(host),
max_dtr / 1000000, (max_dtr / 1000) % 1000);
return max_dtr;
@@ -1046,7 +1065,7 @@ static void mmc_setup(struct mmc_host *host)
} else {
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.clock = host->f_min;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
/*
* We should remember the OCR mask from the existing
@@ -1082,7 +1101,7 @@ static void mmc_setup(struct mmc_host *host)
* Ok, now switch to push-pull mode.
*/
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
mmc_read_csds(host);
@@ -1128,7 +1147,7 @@ static void mmc_rescan(void *data)
* attached cards and the host support.
*/
host->ios.clock = mmc_calculate_clock(host);
- host->ops->set_ios(host, &host->ios);
+ mmc_set_ios(host);
}
mmc_release_host(host);
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 8eb2a2ede64b..587458b370b9 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -175,6 +175,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.timeout_ns = card->csd.tacc_ns * 10;
brq.data.timeout_clks = card->csd.tacc_clks * 10;
brq.data.blksz_bits = md->block_bits;
+ brq.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
@@ -187,6 +188,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.opcode = MMC_WRITE_BLOCK;
brq.data.flags |= MMC_DATA_WRITE;
brq.data.blocks = 1;
+
+ /*
+ * Scale up the timeout by the r2w factor
+ */
+ brq.data.timeout_ns <<= card->csd.r2w_factor;
+ brq.data.timeout_clks <<= card->csd.r2w_factor;
}
if (brq.data.blocks > 1) {
@@ -346,7 +353,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
printk(KERN_ERR "%s: unable to select block size for "
"writing (rb%u wb%u rp%u wp%u)\n",
- md->disk->disk_name,
+ mmc_card_id(card),
1 << card->csd.read_blkbits,
1 << card->csd.write_blkbits,
card->csd.read_partial,
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index df7e861e2fc7..da8e4d7339cc 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -402,9 +402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct mmci_host *host = mmc_priv(mmc);
u32 clk = 0, pwr = 0;
- DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
-
if (ios->clock) {
if (ios->clock >= host->mclk) {
clk = MCI_CLK_BYPASS;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index eb9a8826e9b5..b49368fd96b8 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -65,11 +65,6 @@ struct pxamci_host {
unsigned int dma_dir;
};
-static inline unsigned int ns_to_clocks(unsigned int ns)
-{
- return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
-}
-
static void pxamci_stop_clock(struct pxamci_host *host)
{
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
@@ -113,6 +108,7 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
{
unsigned int nob = data->blocks;
+ unsigned long long clks;
unsigned int timeout;
u32 dcmd;
int i;
@@ -123,9 +119,11 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
nob = 0xffff;
writel(nob, host->base + MMC_NOB);
- writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
+ writel(data->blksz, host->base + MMC_BLKLEN);
- timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks;
+ clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+ do_div(clks, 1000000000UL);
+ timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
writel((timeout + 255) / 256, host->base + MMC_RDTO);
if (data->flags & MMC_DATA_READ) {
@@ -200,7 +198,6 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd,
static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
{
- pr_debug("PXAMCI: request done\n");
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
@@ -286,14 +283,14 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
* data blocks as being in error.
*/
if (data->error == MMC_ERR_NONE)
- data->bytes_xfered = data->blocks << data->blksz_bits;
+ data->bytes_xfered = data->blocks * data->blksz;
else
data->bytes_xfered = 0;
pxamci_disable_irq(host, DATA_TRAN_DONE);
host->data = NULL;
- if (host->mrq->stop && data->error == MMC_ERR_NONE) {
+ if (host->mrq->stop) {
pxamci_stop_clock(host);
pxamci_start_cmd(host, host->mrq->stop, 0);
} else {
@@ -311,12 +308,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
ireg = readl(host->base + MMC_I_REG);
- pr_debug("PXAMCI: irq %08x\n", ireg);
-
if (ireg) {
unsigned stat = readl(host->base + MMC_STAT);
- pr_debug("PXAMCI: stat %08x\n", stat);
+ pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
if (ireg & END_CMD_RES)
handled |= pxamci_cmd_done(host, stat);
@@ -370,10 +365,6 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct pxamci_host *host = mmc_priv(mmc);
- pr_debug("pxamci_set_ios: clock %u power %u vdd %u.%02u\n",
- ios->clock, ios->power_mode, ios->vdd / 100,
- ios->vdd % 100);
-
if (ios->clock) {
unsigned int clk = CLOCKRATE / ios->clock;
if (CLOCKRATE / clk > ios->clock)
@@ -399,7 +390,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cmdat |= CMDAT_INIT;
}
- pr_debug("pxamci_set_ios: clkrt = %x cmdat = %x\n",
+ pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
host->clkrt, host->cmdat);
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index bdbfca050029..6bfcdbc7491e 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -570,10 +570,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave(&host->lock, flags);
- DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
- ios->vdd, ios->bus_width);
-
/*
* Reset the chip on each power off.
* Should clear out any weird states.
@@ -1077,7 +1073,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
tasklet_init(&host->finish_tasklet,
sdhci_tasklet_finish, (unsigned long)host);
- setup_timer(&host->timer, sdhci_timeout_timer, (int)host);
+ setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ,
host->slot_descr, host);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 511f7b0b31d2..8167332d4013 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -662,14 +662,14 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
unsigned long dmaflags;
DBGF("blksz %04x blks %04x flags %08x\n",
- 1 << data->blksz_bits, data->blocks, data->flags);
+ data->blksz, data->blocks, data->flags);
DBGF("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);
/*
* Calculate size.
*/
- host->size = data->blocks << data->blksz_bits;
+ host->size = data->blocks * data->blksz;
/*
* Check timeout values for overflow.
@@ -696,12 +696,12 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
* Two bytes are needed for each data line.
*/
if (host->bus_width == MMC_BUS_WIDTH_1) {
- blksize = (1 << data->blksz_bits) + 2;
+ blksize = data->blksz + 2;
wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
} else if (host->bus_width == MMC_BUS_WIDTH_4) {
- blksize = (1 << data->blksz_bits) + 2 * 4;
+ blksize = data->blksz + 2 * 4;
wbsd_write_index(host, WBSD_IDX_PBSMSB,
((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
@@ -931,10 +931,6 @@ static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct wbsd_host *host = mmc_priv(mmc);
u8 clk, setup, pwr;
- DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
- ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
- ios->vdd, ios->bus_width);
-
spin_lock_bh(&host->lock);
/*
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index f6b775e63ac8..5ac265dde423 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -78,7 +78,7 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
option.
The option specifies which Flash sectors holds the RedBoot
- partition table. A zero or positive value gives an absolete
+ partition table. A zero or positive value gives an absolute
erase block number. A negative value specifies a number of
sectors before the end of the device.
@@ -103,7 +103,7 @@ config MTD_CMDLINE_PARTS
bool "Command line partition table parsing"
depends on MTD_PARTITIONS = "y"
---help---
- Allow generic configuration of the MTD paritition tables via the kernel
+ Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
different kinds of flash memory are available.
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index a7ec5954caf5..6d8f30deb868 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -30,7 +30,6 @@ config MTD_JEDECPROBE
config MTD_GEN_PROBE
tristate
- select OBSOLETE_INTERMODULE
config MTD_CFI_ADV_OPTIONS
bool "Flash chip driver advanced configuration options"
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
index 8afe3092c4e3..75bc1c2a0f43 100644
--- a/drivers/mtd/chips/Makefile
+++ b/drivers/mtd/chips/Makefile
@@ -3,13 +3,6 @@
#
# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
-# *** BIG UGLY NOTE ***
-#
-# The removal of get_module_symbol() and replacement with
-# inter_module_register() et al has introduced a link order dependency
-# here where previously there was none. We now have to ensure that
-# the CFI command set drivers are linked before gen_probe.o
-
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 57115618c496..16eaca69fb5a 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -97,7 +97,6 @@ struct amd_flash_private {
int interleave;
int numchips;
unsigned long chipshift;
-// const char *im_name;
struct flchip chips[0];
};
@@ -131,12 +130,6 @@ static struct mtd_chip_driver amd_flash_chipdrv = {
.module = THIS_MODULE
};
-
-
-static const char im_name[] = "amd_flash";
-
-
-
static inline __u32 wide_read(struct map_info *map, __u32 addr)
{
if (map->buswidth == 1) {
@@ -737,6 +730,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
offset += dev_size;
}
mtd->type = MTD_NORFLASH;
+ mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->erase = amd_flash_erase;
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 1c074d63ff3a..0d435814aaa1 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -331,13 +331,6 @@ read_pri_intelext(struct map_info *map, __u16 adr)
return extp;
}
-/* 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
- * addresses passed back in cfi are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -406,7 +399,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
- cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+ cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq));
}
@@ -415,6 +408,11 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
return cfi_intelext_setup(mtd);
}
+struct mtd_info *cfi_cmdset_0003(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
+struct mtd_info *cfi_cmdset_0200(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
+EXPORT_SYMBOL_GPL(cfi_cmdset_0001);
+EXPORT_SYMBOL_GPL(cfi_cmdset_0003);
+EXPORT_SYMBOL_GPL(cfi_cmdset_0200);
static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
{
@@ -547,12 +545,12 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
if (extp->MinorVersion >= '4') {
struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
- MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
+ mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
- mtd->flags |= MTD_PROGRAM_REGIONS;
+ mtd->flags &= ~MTD_BIT_WRITEABLE;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
- map->name, MTD_PROGREGION_SIZE(mtd),
+ map->name, mtd->writesize,
MTD_PROGREGION_CTRLMODE_VALID(mtd),
MTD_PROGREGION_CTRLMODE_INVALID(mtd));
}
@@ -896,26 +894,33 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
/*
* When a delay is required for the flash operation to complete, the
- * xip_udelay() function is polling for both the given timeout and pending
- * (but still masked) hardware interrupts. Whenever there is an interrupt
- * pending then the flash erase or write operation is suspended, array mode
- * restored and interrupts unmasked. Task scheduling might also happen at that
- * point. The CPU eventually returns from the interrupt or the call to
- * schedule() and the suspended flash operation is resumed for the remaining
- * of the delay period.
+ * xip_wait_for_operation() function is polling for both the given timeout
+ * and pending (but still masked) hardware interrupts. Whenever there is an
+ * interrupt pending then the flash erase or write operation is suspended,
+ * array mode restored and interrupts unmasked. Task scheduling might also
+ * happen at that point. The CPU eventually returns from the interrupt or
+ * the call to schedule() and the suspended flash operation is resumed for
+ * the remaining of the delay period.
*
* Warning: this function _will_ fool interrupt latency tracing tools.
*/
-static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
- unsigned long adr, int usec)
+static int __xipram xip_wait_for_operation(
+ struct map_info *map, struct flchip *chip,
+ unsigned long adr, int *chip_op_time )
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
map_word status, OK = CMD(0x80);
- unsigned long suspended, start = xip_currtime();
+ unsigned long usec, suspended, start, done;
flstate_t oldstate, newstate;
+ start = xip_currtime();
+ usec = *chip_op_time * 8;
+ if (usec == 0)
+ usec = 500000;
+ done = 0;
+
do {
cpu_relax();
if (xip_irqpending() && cfip &&
@@ -932,9 +937,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* we resume the whole thing at once). Yes, it
* can happen!
*/
+ usec -= done;
map_write(map, CMD(0xb0), adr);
map_write(map, CMD(0x70), adr);
- usec -= xip_elapsed_since(start);
suspended = xip_currtime();
do {
if (xip_elapsed_since(suspended) > 100000) {
@@ -944,7 +949,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* This is a critical error but there
* is not much we can do here.
*/
- return;
+ return -EIO;
}
status = map_read(map, adr);
} while (!map_word_andequal(map, status, OK, OK));
@@ -1004,65 +1009,107 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
xip_cpu_idle();
}
status = map_read(map, adr);
+ done = xip_elapsed_since(start);
} while (!map_word_andequal(map, status, OK, OK)
- && xip_elapsed_since(start) < usec);
-}
+ && done < usec);
-#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)
+ return (done >= usec) ? -ETIME : 0;
+}
/*
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
* the flash is actively programming or erasing since we have to poll for
* the operation to complete anyway. We can't do that in a generic way with
* a XIP setup so do it before the actual flash operation in this case
- * and stub it out from INVALIDATE_CACHE_UDELAY.
+ * and stub it out from INVAL_CACHE_AND_WAIT.
*/
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
- UDELAY(map, chip, cmd_adr, usec)
-
-/*
- * Extra notes:
- *
- * Activating this XIP support changes the way the code works a bit. For
- * example the code to suspend the current process when concurrent access
- * happens is never executed because xip_udelay() will always return with the
- * same chip state as it was entered with. This is why there is no care for
- * the presence of add_wait_queue() or schedule() calls from within a couple
- * xip_disable()'d areas of code, like in do_erase_oneblock for example.
- * The queueing and scheduling are always happening within xip_udelay().
- *
- * Similarly, get_chip() and put_chip() just happen to always be executed
- * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
- * is in array mode, therefore never executing many cases therein and not
- * causing any problem with XIP.
- */
+#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, p_usec) \
+ xip_wait_for_operation(map, chip, cmd_adr, p_usec)
#else
#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
#define XIP_INVAL_CACHED_RANGE(x...)
+#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operation
+
+static int inval_cache_and_wait_for_operation(
+ struct map_info *map, struct flchip *chip,
+ unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
+ int *chip_op_time )
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ map_word status, status_OK = CMD(0x80);
+ int z, chip_state = chip->state;
+ unsigned long timeo;
+
+ spin_unlock(chip->mutex);
+ if (inval_len)
+ INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
+ if (*chip_op_time)
+ cfi_udelay(*chip_op_time);
+ spin_lock(chip->mutex);
+
+ timeo = *chip_op_time * 8 * HZ / 1000000;
+ if (timeo < HZ/2)
+ timeo = HZ/2;
+ timeo += jiffies;
+
+ z = 0;
+ for (;;) {
+ if (chip->state != chip_state) {
+ /* Someone's suspended the operation: sleep */
+ DECLARE_WAITQUEUE(wait, current);
+
+ 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 / 2); /* FIXME */
+ spin_lock(chip->mutex);
+ continue;
+ }
-#define UDELAY(map, chip, adr, usec) \
-do { \
- spin_unlock(chip->mutex); \
- cfi_udelay(usec); \
- spin_lock(chip->mutex); \
-} while (0)
-
-#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
-do { \
- spin_unlock(chip->mutex); \
- INVALIDATE_CACHED_RANGE(map, adr, len); \
- cfi_udelay(usec); \
- spin_lock(chip->mutex); \
-} while (0)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
+ return -ETIME;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ z++;
+ spin_unlock(chip->mutex);
+ cfi_udelay(1);
+ spin_lock(chip->mutex);
+ }
+
+ if (!z) {
+ if (!--(*chip_op_time))
+ *chip_op_time = 1;
+ } else if (z > 1)
+ ++(*chip_op_time);
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ return 0;
+}
#endif
+#define WAIT_TIMEOUT(map, chip, adr, udelay) \
+ ({ int __udelay = (udelay); \
+ INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, &__udelay); })
+
+
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
{
unsigned long cmd_addr;
@@ -1252,14 +1299,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
unsigned long adr, map_word datum, int mode)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK, write_cmd;
- unsigned long timeo;
- int z, ret=0;
+ map_word status, write_cmd;
+ int ret=0;
adr += chip->start;
- /* Let's determine those according to the interleave only once */
- status_OK = CMD(0x80);
switch (mode) {
case FL_WRITING:
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
@@ -1285,57 +1329,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
map_write(map, datum, adr);
chip->state = mode;
- INVALIDATE_CACHE_UDELAY(map, chip, adr,
- adr, map_bankwidth(map),
- chip->word_write_time);
-
- timeo = jiffies + (HZ/2);
- z = 0;
- for (;;) {
- if (chip->state != mode) {
- /* 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);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- timeo = jiffies + (HZ / 2); /* FIXME */
- spin_lock(chip->mutex);
- continue;
- }
-
- status = map_read(map, adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
- ret = -EIO;
- goto out;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- z++;
- UDELAY(map, chip, adr, 1);
- }
- if (!z) {
- chip->word_write_time--;
- if (!chip->word_write_time)
- chip->word_write_time = 1;
+ ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
+ adr, map_bankwidth(map),
+ &chip->word_write_time);
+ if (ret) {
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
+ goto out;
}
- if (z > 1)
- chip->word_write_time++;
-
- /* Done and happy. */
- chip->state = FL_STATUS;
/* check for errors */
+ status = map_read(map, adr);
if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status);
@@ -1452,9 +1456,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long *pvec_seek, int len)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK, write_cmd, datum;
- unsigned long cmd_adr, timeo;
- int wbufsize, z, ret=0, word_gap, words;
+ map_word status, write_cmd, datum;
+ unsigned long cmd_adr;
+ int ret, wbufsize, word_gap, words;
const struct kvec *vec;
unsigned long vec_seek;
@@ -1463,7 +1467,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
cmd_adr = adr & ~(wbufsize-1);
/* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
spin_lock(chip->mutex);
@@ -1477,12 +1480,14 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
ENABLE_VPP(map);
xip_disable(map, chip, cmd_adr);
- /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
+ /* §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
we're just pissing in the wind */
- if (chip->state != FL_STATUS)
+ if (chip->state != FL_STATUS) {
map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
+ }
status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x30))) {
xip_enable(map, chip, cmd_adr);
@@ -1493,32 +1498,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
}
chip->state = FL_WRITING_TO_BUFFER;
-
- z = 0;
- for (;;) {
- map_write(map, write_cmd, cmd_adr);
-
+ map_write(map, write_cmd, cmd_adr);
+ ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
+ if (ret) {
+ /* Argh. Not ready for write to buffer */
+ map_word Xstatus = map_read(map, cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
status = map_read(map, cmd_adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- UDELAY(map, chip, cmd_adr, 1);
-
- if (++z > 20) {
- /* Argh. Not ready for write to buffer */
- map_word Xstatus;
- map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- Xstatus = map_read(map, cmd_adr);
- /* Odd. Clear status bits */
- map_write(map, CMD(0x50), cmd_adr);
- map_write(map, CMD(0x70), cmd_adr);
- xip_enable(map, chip, cmd_adr);
- printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
- map->name, status.x[0], Xstatus.x[0]);
- ret = -EIO;
- goto out;
- }
+ map_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
+ xip_enable(map, chip, cmd_adr);
+ printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
+ map->name, Xstatus.x[0], status.x[0]);
+ goto out;
}
/* Figure out the number of words to write */
@@ -1573,56 +1566,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr,
- adr, len,
- chip->buffer_write_time);
-
- timeo = jiffies + (HZ/2);
- z = 0;
- 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);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- timeo = jiffies + (HZ / 2); /* FIXME */
- spin_lock(chip->mutex);
- continue;
- }
-
- status = map_read(map, cmd_adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, cmd_adr);
- printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
- ret = -EIO;
- goto out;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- z++;
- UDELAY(map, chip, cmd_adr, 1);
- }
- if (!z) {
- chip->buffer_write_time--;
- if (!chip->buffer_write_time)
- chip->buffer_write_time = 1;
+ ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
+ adr, len,
+ &chip->buffer_write_time);
+ if (ret) {
+ map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, cmd_adr);
+ printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
+ goto out;
}
- if (z > 1)
- chip->buffer_write_time++;
-
- /* Done and happy. */
- chip->state = FL_STATUS;
/* check for errors */
+ status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status);
@@ -1693,6 +1649,11 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
if (chipnum == cfi->numchips)
return 0;
}
+
+ /* Be nice and reschedule with the chip in a usable state for other
+ processes. */
+ cond_resched();
+
} while (len);
return 0;
@@ -1713,17 +1674,12 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK;
- unsigned long timeo;
+ map_word status;
int retries = 3;
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
+ int ret;
adr += chip->start;
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
retry:
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_ERASING);
@@ -1745,48 +1701,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- INVALIDATE_CACHE_UDELAY(map, chip, adr,
- adr, len,
- chip->erase_time*1000/2);
-
- /* FIXME. Use a timer to check this, and return immediately. */
- /* Once the state machine's known to be working I'll do that */
-
- timeo = jiffies + (HZ*20);
- for (;;) {
- if (chip->state != FL_ERASING) {
- /* Someone's suspended the erase. Sleep */
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- 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;
- }
-
- status = map_read(map, adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
- ret = -EIO;
- goto out;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- UDELAY(map, chip, adr, 1000000/HZ);
+ ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
+ adr, len,
+ &chip->erase_time);
+ if (ret) {
+ map_write(map, CMD(0x70), adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
+ goto out;
}
/* We've broken this before. It doesn't hurt to be safe */
@@ -1815,7 +1738,6 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
ret = -EIO;
} else if (chipstatus & 0x20 && retries--) {
printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
- timeo = jiffies + HZ;
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
goto retry;
@@ -1921,15 +1843,11 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- map_word status, status_OK;
- unsigned long timeo = jiffies + HZ;
+ int udelay;
int ret;
adr += chip->start;
- /* Let's determine this according to the interleave only once */
- status_OK = CMD(0x80);
-
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) {
@@ -1954,41 +1872,21 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
* If Instant Individual Block Locking supported then no need
* to delay.
*/
+ udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
- if (!extp || !(extp->FeatureSupport & (1 << 5)))
- UDELAY(map, chip, adr, 1000000/HZ);
-
- /* FIXME. Use a timer to check this, and return immediately. */
- /* Once the state machine's known to be working I'll do that */
-
- timeo = jiffies + (HZ*20);
- for (;;) {
-
- status = map_read(map, adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
- put_chip(map, chip, adr);
- spin_unlock(chip->mutex);
- return -EIO;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- UDELAY(map, chip, adr, 1);
+ ret = WAIT_TIMEOUT(map, chip, adr, udelay);
+ if (ret) {
+ map_write(map, CMD(0x70), adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
+ goto out;
}
- /* Done and happy. */
- chip->state = FL_STATUS;
xip_enable(map, chip, adr);
- put_chip(map, chip, adr);
+out: put_chip(map, chip, adr);
spin_unlock(chip->mutex);
- return 0;
+ return ret;
}
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
@@ -2445,28 +2343,8 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
kfree(mtd->eraseregions);
}
-static char im_name_0001[] = "cfi_cmdset_0001";
-static char im_name_0003[] = "cfi_cmdset_0003";
-static char im_name_0200[] = "cfi_cmdset_0200";
-
-static int __init cfi_intelext_init(void)
-{
- inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);
- inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);
- inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001);
- return 0;
-}
-
-static void __exit cfi_intelext_exit(void)
-{
- inter_module_unregister(im_name_0001);
- inter_module_unregister(im_name_0003);
- inter_module_unregister(im_name_0200);
-}
-
-module_init(cfi_intelext_init);
-module_exit(cfi_intelext_exit);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");
+MODULE_ALIAS("cfi_cmdset_0003");
+MODULE_ALIAS("cfi_cmdset_0200");
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index aed10bd5c3c3..1e01ad38b26e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -236,6 +236,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->resume = cfi_amdstd_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
+ mtd->writesize = 1;
if (cfi->cfi_mode==CFI_MODE_CFI){
unsigned char bootloc;
@@ -326,7 +327,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
return cfi_amdstd_setup(mtd);
}
-
+EXPORT_SYMBOL_GPL(cfi_cmdset_0002);
static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
{
@@ -1758,25 +1759,6 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd)
kfree(mtd->eraseregions);
}
-static char im_name[]="cfi_cmdset_0002";
-
-
-static 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);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 0807c1c91e55..fae70a5db540 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -162,6 +162,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
return cfi_staa_setup(map);
}
+EXPORT_SYMBOL_GPL(cfi_cmdset_0020);
static struct mtd_info *cfi_staa_setup(struct map_info *map)
{
@@ -237,9 +238,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->unlock = cfi_staa_unlock;
mtd->suspend = cfi_staa_suspend;
mtd->resume = cfi_staa_resume;
- mtd->flags = MTD_CAP_NORFLASH;
- mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
- mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+ mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
+ mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE);
mtd->name = map->name;
@@ -1410,20 +1410,4 @@ static void cfi_staa_destroy(struct mtd_info *mtd)
kfree(cfi);
}
-static char im_name[]="cfi_cmdset_0020";
-
-static int __init cfi_staa_init(void)
-{
- inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
- return 0;
-}
-
-static void __exit cfi_staa_exit(void)
-{
- inter_module_unregister(im_name);
-}
-
-module_init(cfi_staa_init);
-module_exit(cfi_staa_exit);
-
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index e636aa86bc24..4bf9f8cac0dd 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -349,12 +349,12 @@ static void print_cfi_ident(struct cfi_ident *cfip)
else
printk("No Vpp line\n");
- printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
- printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
+ printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
+ printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
- printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
- printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
+ printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
+ printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
}
else
printk("Full buffer write not supported\n");
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index 41bd59d20d85..cdb0f590b40c 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -37,8 +37,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */
- if (mtd)
+ if (mtd) {
+ if (mtd->size > map->size) {
+ printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
+ (unsigned long)mtd->size >> 10,
+ (unsigned long)map->size >> 10);
+ mtd->size = map->size;
+ }
return mtd;
+ }
printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
@@ -100,7 +107,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
* Align bitmap storage size to full byte.
*/
max_chips = map->size >> cfi.chipshift;
- mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
+ if (!max_chips) {
+ printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n");
+ max_chips = 1;
+ }
+
+ mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
chip_map = kmalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
@@ -194,25 +206,28 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
-#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)
- char probename[32];
+#ifdef CONFIG_MODULES
+ char probename[16+sizeof(MODULE_SYMBOL_PREFIX)];
cfi_cmdset_fn_t *probe_function;
- sprintf(probename, "cfi_cmdset_%4.4X", type);
+ sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type);
- probe_function = inter_module_get_request(probename, probename);
+ probe_function = __symbol_get(probename);
+ if (!probe_function) {
+ request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1);
+ probe_function = __symbol_get(probename);
+ }
if (probe_function) {
struct mtd_info *mtd;
mtd = (*probe_function)(map, primary);
/* If it was happy, it'll have increased its own use count */
- inter_module_put(probename);
+ symbol_put_addr(probe_function);
return mtd;
}
#endif
- printk(KERN_NOTICE "Support for command set %04X not present\n",
- type);
+ printk(KERN_NOTICE "Support for command set %04X not present\n", type);
return NULL;
}
@@ -226,12 +241,8 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
return NULL;
switch(type){
- /* Urgh. Ifdefs. The version with weak symbols was
- * _much_ nicer. Shame it didn't seem to work on
- * anything but x86, really.
- * But we can't rely in inter_module_get() because
- * that'd mean we depend on link order.
- */
+ /* We need these for the !CONFIG_MODULES case,
+ because symbol_get() doesn't work there */
#ifdef CONFIG_MTD_CFI_INTELEXT
case 0x0001:
case 0x0003:
@@ -246,9 +257,9 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
case 0x0020:
return cfi_cmdset_0020(map, primary);
#endif
+ default:
+ return cfi_cmdset_unknown(map, primary);
}
-
- return cfi_cmdset_unknown(map, primary);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index bd2e876a814b..763925747db6 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -70,7 +70,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->read = mapram_read;
mtd->write = mapram_write;
mtd->sync = mapram_nop;
- mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
+ mtd->flags = MTD_CAP_RAM;
mtd->erasesize = PAGE_SIZE;
while(mtd->size & (mtd->erasesize - 1))
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index 624c12c232c8..bc6ee9ef8a31 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -46,9 +46,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->write = maprom_write;
mtd->sync = maprom_nop;
mtd->flags = MTD_CAP_ROM;
- mtd->erasesize = 131072;
- while(mtd->size & (mtd->erasesize - 1))
- mtd->erasesize >>= 1;
+ mtd->erasesize = map->size;
__module_get(THIS_MODULE);
return mtd;
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 3cc0b23c5865..967abbecdff9 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -140,6 +140,7 @@ static struct mtd_info *sharp_probe(struct map_info *map)
mtd->suspend = sharp_suspend;
mtd->resume = sharp_resume;
mtd->flags = MTD_CAP_NORFLASH;
+ mtd->writesize = 1;
mtd->name = map->name;
memset(sharp, 0, sizeof(*sharp));
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 7fac438b5c32..16c02b5ccf7e 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -47,6 +47,11 @@ config MTD_MS02NV
accelerator. Say Y here if you have a DECstation 5000/2x0 or a
DECsystem 5900 equipped with such a module.
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module will
+ be called ms02-nv.o.
+
config MTD_DATAFLASH
tristate "Support for AT45xxx DataFlash"
depends on MTD && SPI_MASTER && EXPERIMENTAL
@@ -209,7 +214,6 @@ config MTD_DOC2001PLUS
config MTD_DOCPROBE
tristate
select MTD_DOCECC
- select OBSOLETE_INTERMODULE
config MTD_DOCECC
tristate
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index b6573670316f..0f788d5c4bf8 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -3,13 +3,6 @@
#
# $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $
-# *** BIG UGLY NOTE ***
-#
-# The removal of get_module_symbol() and replacement with
-# inter_module_register() et al has introduced a link order dependency
-# here where previously there was none. We now have to ensure that
-# doc200[01].o are linked before docprobe.o
-
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 4160b8334c53..0d98c223c5fc 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -4,7 +4,7 @@
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004,2005 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
*/
@@ -331,7 +331,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
dev->mtd.writev = default_mtd_writev;
dev->mtd.sync = block2mtd_sync;
dev->mtd.read = block2mtd_read;
- dev->mtd.readv = default_mtd_readv;
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
@@ -351,6 +350,12 @@ devinit_err:
}
+/* This function works similar to reguler strtoul. In addition, it
+ * allows some suffixes for a more human-readable number format:
+ * ki, Ki, kiB, KiB - multiply result with 1024
+ * Mi, MiB - multiply result with 1024^2
+ * Gi, GiB - multiply result with 1024^3
+ */
static int ustrtoul(const char *cp, char **endp, unsigned int base)
{
unsigned long result = simple_strtoul(cp, endp, base);
@@ -359,11 +364,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
result *= 1024;
case 'M':
result *= 1024;
+ case 'K':
case 'k':
result *= 1024;
/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
- if ((*endp)[1] == 'i')
- (*endp) += 2;
+ if ((*endp)[1] == 'i') {
+ if ((*endp)[2] == 'B')
+ (*endp) += 3;
+ else
+ (*endp) += 2;
+ }
}
return result;
}
@@ -418,7 +428,8 @@ static inline void kill_final_newline(char *str)
static int block2mtd_setup(const char *val, struct kernel_param *kp)
{
- char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
+ char buf[80+12]; /* 80 for device, 12 for erase size */
+ char *str = buf;
char *token[2];
char *name;
size_t erase_size = PAGE_SIZE;
@@ -430,7 +441,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
strcpy(str, val);
kill_final_newline(str);
- for (i=0; i<2; i++)
+ for (i = 0; i < 2; i++)
token[i] = strsep(&str, ",");
if (str)
@@ -449,8 +460,10 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
if (token[1]) {
ret = parse_num(&erase_size, token[1]);
- if (ret)
+ if (ret) {
+ kfree(name);
parse_err("illegal erase size");
+ }
}
add_device(name, erase_size);
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index 23e7a5c7d2c1..c54e40464d82 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -59,13 +59,10 @@ static int doc_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);
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, struct nand_oobinfo *oobsel);
-static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *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,
- size_t *retlen, const u_char *buf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
@@ -517,16 +514,9 @@ static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
-static const char im_name[] = "DoC2k_init";
-
-/* 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
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoC2k_init(struct mtd_info *mtd)
+/* This routine is found from the docprobe code by symbol_get(),
+ * which will bump the use count of this module. */
+void DoC2k_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
@@ -586,7 +576,7 @@ static void DoC2k_init(struct mtd_info *mtd)
mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
- mtd->oobblock = 512;
+ mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
@@ -594,9 +584,6 @@ static void DoC2k_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
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;
@@ -623,6 +610,7 @@ static void DoC2k_init(struct mtd_info *mtd)
return;
}
}
+EXPORT_SYMBOL_GPL(DoC2k_init);
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
@@ -971,72 +959,18 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return 0;
}
-static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
- u_char *eccbuf, struct nand_oobinfo *oobsel)
-{
- static char static_buf[512];
- static DEFINE_MUTEX(writev_buf_mutex);
-
- size_t totretlen = 0;
- size_t thisvecofs = 0;
- int ret= 0;
-
- mutex_lock(&writev_buf_mutex);
-
- while(count) {
- size_t thislen, thisretlen;
- unsigned char *buf;
-
- buf = vecs->iov_base + thisvecofs;
- thislen = vecs->iov_len - thisvecofs;
-
-
- 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);
-
- totretlen += thisretlen;
-
- if (ret || thisretlen != thislen)
- break;
-
- to += thislen;
- }
-
- mutex_unlock(&writev_buf_mutex);
- *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)
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
struct DiskOnChip *this = mtd->priv;
int len256 = 0, ret;
struct Nand *mychip;
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
mutex_lock(&this->lock);
@@ -1077,7 +1011,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
DoC_ReadBuf(this, &buf[len256], len - len256);
- *retlen = len;
+ ops->retlen = len;
/* Reading the full OOB data drops us off of the end of the page,
* causing the flash device to go into busy mode, so we need
* to wait until ready 11.4.1 and Toshiba TC58256FT docs */
@@ -1192,17 +1126,20 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
}
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t * retlen, const u_char * buf)
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
- struct DiskOnChip *this = mtd->priv;
- int ret;
+ struct DiskOnChip *this = mtd->priv;
+ int ret;
- mutex_lock(&this->lock);
- ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf);
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ mutex_lock(&this->lock);
+ ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len,
+ &ops->retlen, ops->oobbuf);
- mutex_unlock(&this->lock);
- return ret;
+ mutex_unlock(&this->lock);
+ return ret;
}
static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
@@ -1277,12 +1214,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
-static int __init init_doc2000(void)
-{
- inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
- return 0;
-}
-
static void __exit cleanup_doc2000(void)
{
struct mtd_info *mtd;
@@ -1298,11 +1229,9 @@ static void __exit cleanup_doc2000(void)
kfree(this->chips);
kfree(mtd);
}
- inter_module_unregister(im_name);
}
module_exit(cleanup_doc2000);
-module_init(init_doc2000);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 681a9c73a2a3..0cf022a69e65 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -43,10 +43,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
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,
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,
- size_t *retlen, const u_char *buf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
static struct mtd_info *docmillist = NULL;
@@ -324,16 +324,9 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
-static const char im_name[] = "DoCMil_init";
-
-/* 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
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoCMil_init(struct mtd_info *mtd)
+/* This routine is found from the docprobe code by symbol_get(),
+ * which will bump the use count of this module. */
+void DoCMil_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
@@ -368,7 +361,7 @@ static void DoCMil_init(struct mtd_info *mtd)
/* FIXME: erase size is not always 8KiB */
mtd->erasesize = 0x2000;
- mtd->oobblock = 512;
+ mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
@@ -376,8 +369,6 @@ static void DoCMil_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
- mtd->read_ecc = doc_read_ecc;
- mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
@@ -401,6 +392,7 @@ static void DoCMil_init(struct mtd_info *mtd)
return;
}
}
+EXPORT_SYMBOL_GPL(DoCMil_init);
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
@@ -670,8 +662,8 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
return ret;
}
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, u_char *buf)
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
@@ -680,6 +672,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
@@ -716,13 +714,13 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
#endif
buf[len - 1] = ReadDOC(docptr, LastDataRead);
- *retlen = len;
+ ops->retlen = len;
return 0;
}
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, const u_char *buf)
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
@@ -732,6 +730,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
@@ -783,12 +787,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
printk("Error programming oob data\n");
/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
- *retlen = 0;
+ ops->retlen = 0;
ret = -EIO;
}
dummy = ReadDOC(docptr, LastDataRead);
- *retlen = len;
+ ops->retlen = len;
return ret;
}
@@ -856,12 +860,6 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
-static int __init init_doc2001(void)
-{
- inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
- return 0;
-}
-
static void __exit cleanup_doc2001(void)
{
struct mtd_info *mtd;
@@ -877,11 +875,9 @@ static void __exit cleanup_doc2001(void)
kfree(this->chips);
kfree(mtd);
}
- inter_module_unregister(im_name);
}
module_exit(cleanup_doc2001);
-module_init(init_doc2001);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 5f57f29efee4..66cb1e50469a 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -47,10 +47,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
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,
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,
- size_t *retlen, const u_char *buf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
static struct mtd_info *docmilpluslist = NULL;
@@ -447,16 +447,9 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
-static const char im_name[] = "DoCMilPlus_init";
-
-/* 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
- * addresses passed back in mtd are valid as long as the use count of
- * this module is non-zero, i.e. between inter_module_get and
- * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
- */
-static void DoCMilPlus_init(struct mtd_info *mtd)
+/* This routine is found from the docprobe code by symbol_get(),
+ * which will bump the use count of this module. */
+void DoCMilPlus_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
@@ -490,7 +483,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
mtd->size = 0;
mtd->erasesize = 0;
- mtd->oobblock = 512;
+ mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
@@ -498,8 +491,6 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
- mtd->read_ecc = doc_read_ecc;
- mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
@@ -524,6 +515,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
return;
}
}
+EXPORT_SYMBOL_GPL(DoCMilPlus_init);
#if 0
static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
@@ -876,14 +868,20 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return ret;
}
-static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, u_char *buf)
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
loff_t fofs, base;
struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
DoC_CheckASIC(docptr);
@@ -949,12 +947,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
- *retlen = len;
+ ops->retlen = len;
return 0;
}
-static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
- size_t *retlen, const u_char *buf)
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ struct mtd_oob_ops *ops)
{
volatile char dummy;
loff_t fofs, base;
@@ -963,6 +961,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
int ret = 0;
+ uint8_t *buf = ops->oobbuf;
+ size_t len = ops->len;
+
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ ofs += ops->ooboffs;
DoC_CheckASIC(docptr);
@@ -1038,7 +1042,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
printk("MTD: Error 0x%x programming oob at 0x%x\n",
dummy, (int)ofs);
/* FIXME: implement Bad Block Replacement */
- *retlen = 0;
+ ops->retlen = 0;
ret = -EIO;
}
dummy = ReadDOC(docptr, Mplus_LastDataRead);
@@ -1051,7 +1055,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
- *retlen = len;
+ ops->retlen = len;
return ret;
}
@@ -1122,12 +1126,6 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
-static int __init init_doc2001plus(void)
-{
- inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
- return 0;
-}
-
static void __exit cleanup_doc2001plus(void)
{
struct mtd_info *mtd;
@@ -1143,11 +1141,9 @@ static void __exit cleanup_doc2001plus(void)
kfree(this->chips);
kfree(mtd);
}
- inter_module_unregister(im_name);
}
module_exit(cleanup_doc2001plus);
-module_init(init_doc2001plus);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index 13178b9dd00a..593bb033a3fa 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -231,6 +231,10 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
static int docfound;
+extern void DoC2k_init(struct mtd_info *);
+extern void DoCMil_init(struct mtd_info *);
+extern void DoCMilPlus_init(struct mtd_info *);
+
static void __init DoC_Probe(unsigned long physadr)
{
void __iomem *docptr;
@@ -239,8 +243,6 @@ static void __init DoC_Probe(unsigned long physadr)
int ChipID;
char namebuf[15];
char *name = namebuf;
- char *im_funcname = NULL;
- char *im_modname = NULL;
void (*initroutine)(struct mtd_info *) = NULL;
docptr = ioremap(physadr, DOC_IOREMAP_LEN);
@@ -278,41 +280,33 @@ static void __init DoC_Probe(unsigned long physadr)
switch(ChipID) {
case DOC_ChipID_Doc2kTSOP:
name="2000 TSOP";
- im_funcname = "DoC2k_init";
- im_modname = "doc2000";
+ initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_Doc2k:
name="2000";
- im_funcname = "DoC2k_init";
- im_modname = "doc2000";
+ initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_DocMil:
name="Millennium";
#ifdef DOC_SINGLE_DRIVER
- im_funcname = "DoC2k_init";
- im_modname = "doc2000";
+ initroutine = symbol_request(DoC2k_init);
#else
- im_funcname = "DoCMil_init";
- im_modname = "doc2001";
+ initroutine = symbol_request(DoCMil_init);
#endif /* DOC_SINGLE_DRIVER */
break;
case DOC_ChipID_DocMilPlus16:
case DOC_ChipID_DocMilPlus32:
name="MillenniumPlus";
- im_funcname = "DoCMilPlus_init";
- im_modname = "doc2001plus";
+ initroutine = symbol_request(DoCMilPlus_init);
break;
}
- if (im_funcname)
- initroutine = inter_module_get_request(im_funcname, im_modname);
-
if (initroutine) {
(*initroutine)(mtd);
- inter_module_put(im_funcname);
+ symbol_put_addr(initroutine);
return;
}
printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 29b0ddaa324e..4ea50a1dda85 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -635,6 +635,7 @@ int __init lart_flash_init (void)
printk ("%s: This looks like a LART board to me.\n",module_name);
mtd.name = module_name;
mtd.type = MTD_NORFLASH;
+ mtd.writesize = 1;
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;
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 04e65d5dae00..a8466141e914 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -465,6 +465,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.name = spi->dev.bus_id;
flash->mtd.type = MTD_NORFLASH;
+ flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
flash->mtd.erasesize = info->sector_size;
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 485f663493d2..4ab7670770e4 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -219,7 +219,7 @@ static int __init ms02nv_init_one(ulong addr)
mp->uaddr = phys_to_virt(fixaddr);
mtd->type = MTD_RAM;
- mtd->flags = MTD_CAP_RAM | MTD_XIP;
+ mtd->flags = MTD_CAP_RAM;
mtd->size = fixsize;
mtd->name = (char *)ms02nv_name;
mtd->owner = THIS_MODULE;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index 1443117fd8f4..b4438eacfd80 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -106,6 +106,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM;
mtd->size = size;
+ mtd->writesize = 1;
mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index e8685ee6c1e4..e09e416667d3 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -1,8 +1,8 @@
/**
* $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
*
- * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
- * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
+ * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
@@ -142,7 +142,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
new->mtd.name = name;
new->mtd.size = len;
- new->mtd.flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
+ new->mtd.flags = MTD_CAP_RAM;
new->mtd.erase = phram_erase;
new->mtd.point = phram_point;
new->mtd.unpoint = phram_unpoint;
@@ -266,12 +266,16 @@ static int phram_setup(const char *val, struct kernel_param *kp)
return 0;
ret = parse_num32(&start, token[1]);
- if (ret)
+ if (ret) {
+ kfree(name);
parse_err("illegal start address\n");
+ }
ret = parse_num32(&len, token[2]);
- if (ret)
+ if (ret) {
+ kfree(name);
parse_err("illegal device length\n");
+ }
register_device(name, start, len);
@@ -296,5 +300,5 @@ module_init(init_phram);
module_exit(cleanup_phram);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
MODULE_DESCRIPTION("MTD driver for physical RAM");
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 6faee6c6958c..b3f665e3c38b 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -200,8 +200,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->name = name;
(*curmtd)->mtdinfo->size = length;
- (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
- MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
+ (*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
(*curmtd)->mtdinfo->erase = slram_erase;
(*curmtd)->mtdinfo->point = slram_point;
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index a3b92479719d..1e21a2c3dd29 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -36,6 +36,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h>
#include <linux/mtd/inftl.h>
+#include <linux/mtd/nand.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -79,14 +80,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512;
inftl->mbd.tr = tr;
- memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
- inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
- if (INFTL_mount(inftl) < 0) {
+ if (INFTL_mount(inftl) < 0) {
printk(KERN_WARNING "INFTL: could not mount device\n");
kfree(inftl);
return;
- }
+ }
/* OK, it's a new one. Set up all the data structures. */
@@ -152,6 +151,69 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
*/
/*
+ * Read oob data from flash
+ */
+int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write oob data to flash
+ */
+int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write data and oob to flash
+ */
+static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf, uint8_t *oob)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs;
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = oob;
+ ops.datbuf = buf;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
* INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
* This function is used when the give Virtual Unit Chain.
*/
@@ -198,10 +260,11 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
u16 BlockMap[MAX_SECTORS_PER_UNIT];
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
unsigned int thisEUN, prevEUN, status;
+ struct mtd_info *mtd = inftl->mbd.mtd;
int block, silly;
unsigned int targetEUN;
struct inftl_oob oob;
- size_t retlen;
+ size_t retlen;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,"
"pending=%d)\n", inftl, thisVUC, pendingblock);
@@ -221,18 +284,18 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
* Scan to find the Erase Unit which holds the actual data for each
* 512-byte block within the Chain.
*/
- silly = MAX_LOOPS;
+ silly = MAX_LOOPS;
while (thisEUN < inftl->nb_blocks) {
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
continue;
- if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
- + (block * SECTORSIZE), 16 , &retlen,
- (char *)&oob) < 0)
+ if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
+ + (block * SECTORSIZE), 16, &retlen,
+ (char *)&oob) < 0)
status = SECTOR_IGNORE;
else
- status = oob.b.Status | oob.b.Status1;
+ status = oob.b.Status | oob.b.Status1;
switch(status) {
case SECTOR_FREE:
@@ -282,29 +345,31 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
continue;
}
- /*
+ /*
* Copy only in non free block (free blocks can only
* happen in case of media errors or deleted blocks).
*/
- if (BlockMap[block] == BLOCK_NIL)
- continue;
-
- ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
- BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
- &retlen, movebuf);
- if (ret < 0) {
- ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
- BlockMap[block]) + (block * SECTORSIZE),
- SECTORSIZE, &retlen, movebuf);
+ if (BlockMap[block] == BLOCK_NIL)
+ continue;
+
+ ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
+ (block * SECTORSIZE), SECTORSIZE, &retlen,
+ movebuf);
+ if (ret < 0 && ret != -EUCLEAN) {
+ ret = mtd->read(mtd,
+ (inftl->EraseSize * BlockMap[block]) +
+ (block * SECTORSIZE), SECTORSIZE,
+ &retlen, movebuf);
if (ret != -EIO)
- DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
- "away on retry?\n");
- }
- memset(&oob, 0xff, sizeof(struct inftl_oob));
- oob.b.Status = oob.b.Status1 = SECTOR_USED;
- MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
- (block * SECTORSIZE), SECTORSIZE, &retlen,
- movebuf, (char *)&oob, &inftl->oobinfo);
+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
+ "away on retry?\n");
+ }
+ memset(&oob, 0xff, sizeof(struct inftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
+
+ inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
+ (block * SECTORSIZE), SECTORSIZE, &retlen,
+ movebuf, (char *)&oob);
}
/*
@@ -329,17 +394,17 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
if (thisEUN == targetEUN)
break;
- if (INFTL_formatblock(inftl, thisEUN) < 0) {
+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
- } else {
+ } else {
/* Correctly erased : mark it as free */
inftl->PUtable[thisEUN] = BLOCK_FREE;
inftl->PUtable[prevEUN] = BLOCK_NIL;
inftl->numfreeEUNs++;
- }
+ }
}
return targetEUN;
@@ -415,6 +480,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
unsigned int thisEUN, writeEUN, prev_block, status;
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
+ struct mtd_info *mtd = inftl->mbd.mtd;
struct inftl_oob oob;
struct inftl_bci bci;
unsigned char anac, nacs, parity;
@@ -434,10 +500,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
silly = MAX_LOOPS;
while (thisEUN <= inftl->lastEUN) {
- MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
- blockofs, 8, &retlen, (char *)&bci);
+ inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
+ blockofs, 8, &retlen, (char *)&bci);
- status = bci.Status | bci.Status1;
+ status = bci.Status | bci.Status1;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
"EUN %d is %x\n", block , writeEUN, status);
@@ -522,8 +588,8 @@ hitused:
nacs = 0;
thisEUN = inftl->VUtable[thisVUC];
if (thisEUN != BLOCK_NIL) {
- MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize
- + 8, 8, &retlen, (char *)&oob.u);
+ inftl_read_oob(mtd, thisEUN * inftl->EraseSize
+ + 8, 8, &retlen, (char *)&oob.u);
anac = oob.u.a.ANAC + 1;
nacs = oob.u.a.NACs + 1;
}
@@ -544,8 +610,8 @@ hitused:
oob.u.a.parityPerField = parity;
oob.u.a.discarded = 0xaa;
- MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
+ inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,
+ &retlen, (char *)&oob.u);
/* Also back up header... */
oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
@@ -555,8 +621,8 @@ hitused:
oob.u.b.parityPerField = parity;
oob.u.b.discarded = 0xaa;
- MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
- SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
+ inftl_write_oob(mtd, writeEUN * inftl->EraseSize +
+ SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
inftl->VUtable[thisVUC] = writeEUN;
@@ -576,6 +642,7 @@ hitused:
*/
static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
{
+ struct mtd_info *mtd = inftl->mbd.mtd;
unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
unsigned int thisEUN, status;
@@ -606,9 +673,9 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
if (BlockUsed[block] || BlockDeleted[block])
continue;
- if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
- + (block * SECTORSIZE), 8 , &retlen,
- (char *)&bci) < 0)
+ if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
+ + (block * SECTORSIZE), 8 , &retlen,
+ (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
status = bci.Status | bci.Status1;
@@ -670,12 +737,12 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
thisEUN, thisVUC);
- if (INFTL_formatblock(inftl, thisEUN) < 0) {
+ if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
- } else {
+ } else {
/* Correctly erased : mark it as free */
inftl->PUtable[thisEUN] = BLOCK_FREE;
inftl->numfreeEUNs++;
@@ -697,6 +764,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
{
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
+ struct mtd_info *mtd = inftl->mbd.mtd;
unsigned int status;
int silly = MAX_LOOPS;
size_t retlen;
@@ -706,8 +774,8 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
"block=%d)\n", inftl, block);
while (thisEUN < inftl->nb_blocks) {
- if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
- blockofs, 8, &retlen, (char *)&bci) < 0)
+ if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
+ blockofs, 8, &retlen, (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
status = bci.Status | bci.Status1;
@@ -741,10 +809,10 @@ foundit:
if (thisEUN != BLOCK_NIL) {
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
- if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
+ if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
return -EIO;
bci.Status = bci.Status1 = SECTOR_DELETED;
- if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
+ if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
return -EIO;
INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
}
@@ -784,9 +852,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
memset(&oob, 0xff, sizeof(struct inftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
- MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
- blockofs, SECTORSIZE, &retlen, (char *)buffer,
- (char *)&oob, &inftl->oobinfo);
+
+ inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
+ blockofs, SECTORSIZE, &retlen, (char *)buffer,
+ (char *)&oob);
/*
* need to write SECTOR_USED flags since they are not written
* in mtd_writeecc
@@ -804,17 +873,18 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
struct INFTLrecord *inftl = (void *)mbd;
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
- unsigned int status;
+ struct mtd_info *mtd = inftl->mbd.mtd;
+ unsigned int status;
int silly = MAX_LOOPS;
- struct inftl_bci bci;
+ struct inftl_bci bci;
size_t retlen;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
"buffer=%p)\n", inftl, block, buffer);
while (thisEUN < inftl->nb_blocks) {
- if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
- blockofs, 8, &retlen, (char *)&bci) < 0)
+ if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
+ blockofs, 8, &retlen, (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
status = bci.Status | bci.Status1;
@@ -850,10 +920,12 @@ foundit:
/* The requested block is not on the media, return all 0x00 */
memset(buffer, 0, SECTORSIZE);
} else {
- size_t retlen;
+ size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
- if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
- buffer))
+ int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
+
+ /* Handle corrected bit flips gracefully */
+ if (ret < 0 && ret != -EUCLEAN)
return -EIO;
}
return 0;
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index 43fdc9433882..8f6006f1a519 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -43,6 +43,11 @@
char inftlmountrev[]="$Revision: 1.18 $";
+extern int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+extern int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
* contains the various device information of the INFTL partition and
@@ -57,6 +62,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
unsigned int i, block;
u8 buf[SECTORSIZE];
struct INFTLMediaHeader *mh = &inftl->MediaHdr;
+ struct mtd_info *mtd = inftl->mbd.mtd;
struct INFTLPartition *ip;
size_t retlen;
@@ -80,8 +86,8 @@ static int find_boot_record(struct INFTLrecord *inftl)
* Check for BNAND header first. Then whinge if it's found
* but later checks fail.
*/
- ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
- SECTORSIZE, &retlen, buf);
+ ret = mtd->read(mtd, block * inftl->EraseSize,
+ SECTORSIZE, &retlen, buf);
/* We ignore ret in case the ECC of the MediaHeader is invalid
(which is apparently acceptable) */
if (retlen != SECTORSIZE) {
@@ -106,8 +112,9 @@ static int find_boot_record(struct INFTLrecord *inftl)
}
/* To be safer with BIOS, also use erase mark as discriminant */
- if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +
- SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {
+ if ((ret = inftl_read_oob(mtd, block * inftl->EraseSize +
+ SECTORSIZE + 8, 8, &retlen,
+ (char *)&h1) < 0)) {
printk(KERN_WARNING "INFTL: ANAND header found at "
"0x%x in mtd%d, but OOB data read failed "
"(err %d)\n", block * inftl->EraseSize,
@@ -123,8 +130,8 @@ static int find_boot_record(struct INFTLrecord *inftl)
memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
/* Read the spare media header at offset 4096 */
- MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
- SECTORSIZE, &retlen, buf);
+ mtd->read(mtd, block * inftl->EraseSize + 4096,
+ SECTORSIZE, &retlen, buf);
if (retlen != SECTORSIZE) {
printk(KERN_WARNING "INFTL: Unable to read spare "
"Media Header\n");
@@ -233,7 +240,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
*/
instr->addr = ip->Reserved0 * inftl->EraseSize;
instr->len = inftl->EraseSize;
- MTD_ERASE(inftl->mbd.mtd, instr);
+ mtd->erase(mtd, instr);
}
if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
printk(KERN_WARNING "INFTL: Media Header "
@@ -350,21 +357,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
int len, int check_oob)
{
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
+ struct mtd_info *mtd = inftl->mbd.mtd;
size_t retlen;
int i;
- DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
- "address=0x%x,len=%d,check_oob=%d)\n", inftl,
- address, len, check_oob);
-
for (i = 0; i < len; i += SECTORSIZE) {
- if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
+ if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
- if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
+ if(inftl_read_oob(mtd, address, mtd->oobsize,
+ &retlen, &buf[SECTORSIZE]) < 0)
+ return -1;
+ if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
@@ -387,6 +394,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
size_t retlen;
struct inftl_unittail uci;
struct erase_info *instr = &inftl->instr;
+ struct mtd_info *mtd = inftl->mbd.mtd;
int physblock;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
@@ -404,8 +412,9 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
/* Erase one physical eraseblock at a time, even though the NAND api
allows us to group them. This way we if we have a failure, we can
mark only the failed block in the bbt. */
- for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
- MTD_ERASE(inftl->mbd.mtd, instr);
+ for (physblock = 0; physblock < inftl->EraseSize;
+ physblock += instr->len, instr->addr += instr->len) {
+ mtd->erase(inftl->mbd.mtd, instr);
if (instr->state == MTD_ERASE_FAILED) {
printk(KERN_WARNING "INFTL: error while formatting block %d\n",
@@ -414,10 +423,10 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
}
/*
- * Check the "freeness" of Erase Unit before updating metadata.
- * FixMe: is this check really necessary? Since we have check the
- * return code after the erase operation.
- */
+ * Check the "freeness" of Erase Unit before updating metadata.
+ * FixMe: is this check really necessary? Since we have check
+ * the return code after the erase operation.
+ */
if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
goto fail;
}
@@ -429,8 +438,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
uci.Reserved[2] = 0;
uci.Reserved[3] = 0;
instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
- if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
- 8, 8, &retlen, (char *)&uci) < 0)
+ if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0)
goto fail;
return 0;
fail:
@@ -549,6 +557,7 @@ void INFTL_dumpVUchains(struct INFTLrecord *s)
int INFTL_mount(struct INFTLrecord *s)
{
+ struct mtd_info *mtd = s->mbd.mtd;
unsigned int block, first_block, prev_block, last_block;
unsigned int first_logical_block, logical_block, erase_mark;
int chain_length, do_format_chain;
@@ -607,10 +616,11 @@ int INFTL_mount(struct INFTLrecord *s)
break;
}
- if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8,
- 8, &retlen, (char *)&h0) < 0 ||
- MTD_READOOB(s->mbd.mtd, block * s->EraseSize +
- 2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) {
+ if (inftl_read_oob(mtd, block * s->EraseSize + 8,
+ 8, &retlen, (char *)&h0) < 0 ||
+ inftl_read_oob(mtd, block * s->EraseSize +
+ 2 * SECTORSIZE + 8, 8, &retlen,
+ (char *)&h1) < 0) {
/* Should never happen? */
do_format_chain++;
break;
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 7abd7fee0dda..6bdaacc6d6f9 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -37,7 +37,7 @@ config MTD_PHYSMAP_START
config MTD_PHYSMAP_LEN
hex "Physical length of flash mapping"
depends on MTD_PHYSMAP
- default "0x4000000"
+ default "0"
help
This is the total length of the mapping of the flash chips on
your particular board. If there is space, or aliases, in the
@@ -78,7 +78,7 @@ config MTD_PNC2000
config MTD_SC520CDP
tristate "CFI Flash device mapped on AMD SC520 CDP"
- depends on X86 && MTD_CFI
+ depends on X86 && MTD_CFI && MTD_CONCAT
help
The SC520 CDP board has two banks of CFI-compliant chips and one
Dual-in-line JEDEC chip. This 'mapping' driver supports that
@@ -109,7 +109,7 @@ config MTD_TS5500
mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL.
Note that jumper 3 ("Write Enable Drive A") must be set
- otherwise detection won't succeeed.
+ otherwise detection won't succeed.
config MTD_SBC_GXX
tristate "CFI Flash device mapped on Arcom SBC-GXx boards"
@@ -200,8 +200,8 @@ config MTD_TSUNAMI
Support for the flash chip on Tsunami TIG bus.
config MTD_LASAT
- tristate "Flash chips on LASAT board"
- depends on LASAT
+ tristate "LASAT flash device"
+ depends on LASAT && MTD_CFI
help
Support for the flash chips on the Lasat 100 and 200 boards.
@@ -561,7 +561,6 @@ config MTD_PCMCIA
config MTD_PCMCIA_ANONYMOUS
bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards"
depends on MTD_PCMCIA
- default N
help
If this option is enabled, PCMCIA cards which do not report
anything about themselves are assumed to be MTD cards.
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c
index fd0f0d3187de..92b5d883d7b0 100644
--- a/drivers/mtd/maps/cfi_flagadm.c
+++ b/drivers/mtd/maps/cfi_flagadm.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
+ * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
*
* $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $
*
@@ -135,5 +135,5 @@ module_exit(cleanup_flagadm);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>");
+MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>");
MODULE_DESCRIPTION("MTD map driver for Flaga digital module");
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
index 652813cd6c2d..85c2a9e22b1e 100644
--- a/drivers/mtd/maps/dbox2-flash.c
+++ b/drivers/mtd/maps/dbox2-flash.c
@@ -122,5 +122,5 @@ module_exit(cleanup_dbox2_flash);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
+MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c
index d1e66e186746..5c25d4e552c6 100644
--- a/drivers/mtd/maps/mtx-1_flash.c
+++ b/drivers/mtd/maps/mtx-1_flash.c
@@ -4,7 +4,7 @@
* $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
*
* (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
- * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
*
*/
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 54a3102ab19a..0994b5b2e331 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -20,6 +20,8 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
#include <asm/io.h>
/****************************************************************************/
@@ -188,7 +190,7 @@ int nettel_eraseconfig(void)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
- ret = MTD_ERASE(mtd, &nettel_erase);
+ ret = mtd->erase(mtd, &nettel_erase);
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index d27f4129afd3..c861134cbc48 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -713,6 +713,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link)
if(dev->mtd_info) {
del_mtd_device(dev->mtd_info);
+ map_destroy(dev->mtd_info);
info("mtd%d: Removed", dev->mtd_info->index);
}
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index f49ebc3c4606..433c3cac3ca9 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -14,112 +14,229 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/config.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <asm/io.h>
-static struct mtd_info *mymtd;
-
-struct map_info physmap_map = {
- .name = "phys_mapped_flash",
- .phys = CONFIG_MTD_PHYSMAP_START,
- .size = CONFIG_MTD_PHYSMAP_LEN,
- .bankwidth = CONFIG_MTD_PHYSMAP_BANKWIDTH,
+struct physmap_flash_info {
+ struct mtd_info *mtd;
+ struct map_info map;
+ struct resource *res;
+#ifdef CONFIG_MTD_PARTITIONS
+ int nr_parts;
+ struct mtd_partition *parts;
+#endif
};
+
+static int physmap_flash_remove(struct platform_device *dev)
+{
+ struct physmap_flash_info *info;
+ struct physmap_flash_data *physmap_data;
+
+ info = platform_get_drvdata(dev);
+ if (info == NULL)
+ return 0;
+ platform_set_drvdata(dev, NULL);
+
+ physmap_data = dev->dev.platform_data;
+
+ if (info->mtd != NULL) {
#ifdef CONFIG_MTD_PARTITIONS
-static struct mtd_partition *mtd_parts;
-static int mtd_parts_nb;
+ if (info->nr_parts) {
+ del_mtd_partitions(info->mtd);
+ kfree(info->parts);
+ } else if (physmap_data->nr_parts) {
+ del_mtd_partitions(info->mtd);
+ } else {
+ del_mtd_device(info->mtd);
+ }
+#else
+ del_mtd_device(info->mtd);
+#endif
+ map_destroy(info->mtd);
+ }
-static int num_physmap_partitions;
-static struct mtd_partition *physmap_partitions;
+ if (info->map.virt != NULL)
+ iounmap((void *)info->map.virt);
-static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
+ if (info->res != NULL) {
+ release_resource(info->res);
+ kfree(info->res);
+ }
-void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
-{
- physmap_partitions=parts;
- num_physmap_partitions=num_parts;
+ return 0;
}
-#endif /* CONFIG_MTD_PARTITIONS */
-static int __init init_physmap(void)
+static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
+#endif
+
+static int physmap_flash_probe(struct platform_device *dev)
{
- static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
- const char **type;
+ struct physmap_flash_data *physmap_data;
+ struct physmap_flash_info *info;
+ const char **probe_type;
+ int err;
+
+ physmap_data = dev->dev.platform_data;
+ if (physmap_data == NULL)
+ return -ENODEV;
+
+ printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
+ (unsigned long long)dev->resource->end - dev->resource->start + 1,
+ (unsigned long long)dev->resource->start);
+
+ info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
+ if (info == NULL) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ memset(info, 0, sizeof(*info));
- printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
- physmap_map.virt = ioremap(physmap_map.phys, physmap_map.size);
+ platform_set_drvdata(dev, info);
- if (!physmap_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
+ info->res = request_mem_region(dev->resource->start,
+ dev->resource->end - dev->resource->start + 1,
+ dev->dev.bus_id);
+ if (info->res == NULL) {
+ dev_err(&dev->dev, "Could not reserve memory region\n");
+ err = -ENOMEM;
+ goto err_out;
}
- simple_map_init(&physmap_map);
+ info->map.name = dev->dev.bus_id;
+ info->map.phys = dev->resource->start;
+ info->map.size = dev->resource->end - dev->resource->start + 1;
+ info->map.bankwidth = physmap_data->width;
+ info->map.set_vpp = physmap_data->set_vpp;
+
+ info->map.virt = ioremap(info->map.phys, info->map.size);
+ if (info->map.virt == NULL) {
+ dev_err(&dev->dev, "Failed to ioremap flash region\n");
+ err = EIO;
+ goto err_out;
+ }
- mymtd = NULL;
- type = rom_probe_types;
- for(; !mymtd && *type; type++) {
- mymtd = do_map_probe(*type, &physmap_map);
+ simple_map_init(&info->map);
+
+ probe_type = rom_probe_types;
+ for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
+ info->mtd = do_map_probe(*probe_type, &info->map);
+ if (info->mtd == NULL) {
+ dev_err(&dev->dev, "map_probe failed\n");
+ err = -ENXIO;
+ goto err_out;
}
- if (mymtd) {
- mymtd->owner = THIS_MODULE;
+ info->mtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
- mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes,
- &mtd_parts, 0);
+ err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
+ if (err > 0) {
+ add_mtd_partitions(info->mtd, info->parts, err);
+ return 0;
+ }
- if (mtd_parts_nb > 0)
- {
- add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
- return 0;
- }
+ if (physmap_data->nr_parts) {
+ printk(KERN_NOTICE "Using physmap partition information\n");
+ add_mtd_partitions(info->mtd, physmap_data->parts,
+ physmap_data->nr_parts);
+ return 0;
+ }
+#endif
+
+ add_mtd_device(info->mtd);
+ return 0;
+
+err_out:
+ physmap_flash_remove(dev);
+ return err;
+}
+
+static struct platform_driver physmap_flash_driver = {
+ .probe = physmap_flash_probe,
+ .remove = physmap_flash_remove,
+ .driver = {
+ .name = "physmap-flash",
+ },
+};
- if (num_physmap_partitions != 0)
- {
- printk(KERN_NOTICE
- "Using physmap partition definition\n");
- add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
- return 0;
- }
+#ifdef CONFIG_MTD_PHYSMAP_LEN
+#if CONFIG_MTD_PHYSMAP_LEN != 0
+#warning using PHYSMAP compat code
+#define PHYSMAP_COMPAT
+#endif
#endif
- add_mtd_device(mymtd);
- return 0;
- }
+#ifdef PHYSMAP_COMPAT
+static struct physmap_flash_data physmap_flash_data = {
+ .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
+};
- iounmap(physmap_map.virt);
- return -ENXIO;
-}
+static struct resource physmap_flash_resource = {
+ .start = CONFIG_MTD_PHYSMAP_START,
+ .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
+ .flags = IORESOURCE_MEM,
+};
-static void __exit cleanup_physmap(void)
+static struct platform_device physmap_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &physmap_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &physmap_flash_resource,
+};
+
+void physmap_configure(unsigned long addr, unsigned long size,
+ int bankwidth, void (*set_vpp)(struct map_info *, int))
{
+ physmap_flash_resource.start = addr;
+ physmap_flash_resource.end = addr + size - 1;
+ physmap_flash_data.width = bankwidth;
+ physmap_flash_data.set_vpp = set_vpp;
+}
+
#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);
- }
-#else
- del_mtd_device(mymtd);
+void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
+{
+ physmap_flash_data.nr_parts = num_parts;
+ physmap_flash_data.parts = parts;
+}
+#endif
#endif
- map_destroy(mymtd);
- iounmap(physmap_map.virt);
- physmap_map.virt = NULL;
+static int __init physmap_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&physmap_flash_driver);
+#ifdef PHYSMAP_COMPAT
+ if (err == 0)
+ platform_device_register(&physmap_flash);
+#endif
+
+ return err;
}
-module_init(init_physmap);
-module_exit(cleanup_physmap);
+static void __exit physmap_exit(void)
+{
+#ifdef PHYSMAP_COMPAT
+ platform_device_unregister(&physmap_flash);
+#endif
+ platform_driver_unregister(&physmap_flash_driver);
+}
+module_init(physmap_init);
+module_exit(physmap_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 2cef280e388c..e5c78463ebfd 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -71,7 +71,7 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos,
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
- ret = MTD_ERASE(mtd, &erase);
+ ret = mtd->erase(mtd, &erase);
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
@@ -88,7 +88,7 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos,
* Next, writhe data to flash.
*/
- ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
+ ret = mtd->write(mtd, pos, len, &retlen, buf);
if (ret)
return ret;
if (retlen != len)
@@ -138,7 +138,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
mtd->name, pos, len);
if (!sect_size)
- return MTD_WRITE (mtd, pos, len, &retlen, buf);
+ return mtd->write(mtd, pos, len, &retlen, buf);
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
@@ -170,7 +170,8 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset != sect_start) {
/* fill the cache with the current sector */
mtdblk->cache_state = STATE_EMPTY;
- ret = MTD_READ(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);
+ ret = mtd->read(mtd, sect_start, sect_size,
+ &retlen, mtdblk->cache_data);
if (ret)
return ret;
if (retlen != sect_size)
@@ -207,7 +208,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
mtd->name, pos, len);
if (!sect_size)
- return MTD_READ (mtd, pos, len, &retlen, buf);
+ return mtd->read(mtd, pos, len, &retlen, buf);
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
@@ -226,7 +227,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset == sect_start) {
memcpy (buf, mtdblk->cache_data + offset, size);
} else {
- ret = MTD_READ (mtd, pos, size, &retlen, buf);
+ ret = mtd->read(mtd, pos, size, &retlen, buf);
if (ret)
return ret;
if (retlen != size)
@@ -288,8 +289,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
mutex_init(&mtdblk->cache_mutex);
mtdblk->cache_state = STATE_EMPTY;
- if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
- mtdblk->mtd->erasesize) {
+ if ( !(mtdblk->mtd->flags & MTD_NO_ERASE) && mtdblk->mtd->erasesize) {
mtdblk->cache_size = mtdblk->mtd->erasesize;
mtdblk->cache_data = NULL;
}
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 0c830ba41ef0..29563ed258a4 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -45,9 +45,7 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
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;
+ dev->readonly = 1;
add_mtd_blktrans_dev(dev);
}
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 6f044584bdc6..aa18d45b264b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -49,24 +49,18 @@ static struct mtd_notifier notifier = {
};
/*
- * We use file->private_data to store a pointer to the MTDdevice.
- * Since alighment is at least 32 bits, we have 2 bits free for OTP
- * modes as well.
+ * Data structure to hold the pointer to the mtd device as well
+ * as mode information ofr various use cases.
*/
-
-#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
-
-#define MTD_MODE_OTP_FACT 1
-#define MTD_MODE_OTP_USER 2
-#define MTD_MODE(file) ((long)((file)->private_data) & 3)
-
-#define SET_MTD_MODE(file, mode) \
- do { long __p = (long)((file)->private_data); \
- (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
+struct mtd_file_info {
+ struct mtd_info *mtd;
+ enum mtd_file_modes mode;
+};
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
{
- struct mtd_info *mtd = TO_MTD(file);
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
switch (orig) {
case 0:
@@ -97,6 +91,7 @@ static int mtd_open(struct inode *inode, struct file *file)
int minor = iminor(inode);
int devnum = minor >> 1;
struct mtd_info *mtd;
+ struct mtd_file_info *mfi;
DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");
@@ -117,14 +112,20 @@ static int mtd_open(struct inode *inode, struct file *file)
return -ENODEV;
}
- file->private_data = mtd;
-
/* You can't open it RW if it's not a writeable device */
if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
put_mtd_device(mtd);
return -EACCES;
}
+ mfi = kzalloc(sizeof(*mfi), GFP_KERNEL);
+ if (!mfi) {
+ put_mtd_device(mtd);
+ return -ENOMEM;
+ }
+ mfi->mtd = mtd;
+ file->private_data = mfi;
+
return 0;
} /* mtd_open */
@@ -132,16 +133,17 @@ static int mtd_open(struct inode *inode, struct file *file)
static int mtd_close(struct inode *inode, struct file *file)
{
- struct mtd_info *mtd;
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- mtd = TO_MTD(file);
-
if (mtd->sync)
mtd->sync(mtd);
put_mtd_device(mtd);
+ file->private_data = NULL;
+ kfree(mfi);
return 0;
} /* mtd_close */
@@ -153,7 +155,8 @@ static int mtd_close(struct inode *inode, struct file *file)
static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = TO_MTD(file);
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
size_t retlen=0;
size_t total_retlen=0;
int ret=0;
@@ -170,36 +173,58 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
/* FIXME: Use kiovec in 2.5 to lock down the user's buffers
and pass them directly to the MTD functions */
+
+ if (count > MAX_KMALLOC_SIZE)
+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
+ else
+ kbuf=kmalloc(count, GFP_KERNEL);
+
+ if (!kbuf)
+ return -ENOMEM;
+
while (count) {
+
if (count > MAX_KMALLOC_SIZE)
len = MAX_KMALLOC_SIZE;
else
len = count;
- kbuf=kmalloc(len,GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
-
- switch (MTD_MODE(file)) {
- case MTD_MODE_OTP_FACT:
+ switch (mfi->mode) {
+ case MTD_MODE_OTP_FACTORY:
ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
break;
case MTD_MODE_OTP_USER:
ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
break;
+ case MTD_MODE_RAW:
+ {
+ struct mtd_oob_ops ops;
+
+ ops.mode = MTD_OOB_RAW;
+ ops.datbuf = kbuf;
+ ops.oobbuf = NULL;
+ ops.len = len;
+
+ ret = mtd->read_oob(mtd, *ppos, &ops);
+ retlen = ops.retlen;
+ break;
+ }
default:
- ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ ret = mtd->read(mtd, *ppos, len, &retlen, kbuf);
}
/* Nand returns -EBADMSG on ecc errors, but it returns
* the data. For our userspace tools it is important
* to dump areas with ecc errors !
+ * For kernel internal usage it also might return -EUCLEAN
+ * to signal the caller that a bitflip has occured and has
+ * been corrected by the ECC algorithm.
* Userspace software which accesses NAND this way
* must be aware of the fact that it deals with NAND
*/
- if (!ret || (ret == -EBADMSG)) {
+ if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
*ppos += retlen;
if (copy_to_user(buf, kbuf, retlen)) {
- kfree(kbuf);
+ kfree(kbuf);
return -EFAULT;
}
else
@@ -215,15 +240,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
return ret;
}
- kfree(kbuf);
}
+ kfree(kbuf);
return total_retlen;
} /* mtd_read */
static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = TO_MTD(file);
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
char *kbuf;
size_t retlen;
size_t total_retlen=0;
@@ -241,25 +267,28 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
if (!count)
return 0;
+ if (count > MAX_KMALLOC_SIZE)
+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
+ else
+ kbuf=kmalloc(count, GFP_KERNEL);
+
+ if (!kbuf)
+ return -ENOMEM;
+
while (count) {
+
if (count > MAX_KMALLOC_SIZE)
len = MAX_KMALLOC_SIZE;
else
len = count;
- kbuf=kmalloc(len,GFP_KERNEL);
- if (!kbuf) {
- printk("kmalloc is null\n");
- return -ENOMEM;
- }
-
if (copy_from_user(kbuf, buf, len)) {
kfree(kbuf);
return -EFAULT;
}
- switch (MTD_MODE(file)) {
- case MTD_MODE_OTP_FACT:
+ switch (mfi->mode) {
+ case MTD_MODE_OTP_FACTORY:
ret = -EROFS;
break;
case MTD_MODE_OTP_USER:
@@ -269,6 +298,21 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
}
ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
break;
+
+ case MTD_MODE_RAW:
+ {
+ struct mtd_oob_ops ops;
+
+ ops.mode = MTD_OOB_RAW;
+ ops.datbuf = kbuf;
+ ops.oobbuf = NULL;
+ ops.len = len;
+
+ ret = mtd->write_oob(mtd, *ppos, &ops);
+ retlen = ops.retlen;
+ break;
+ }
+
default:
ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
}
@@ -282,10 +326,9 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
kfree(kbuf);
return ret;
}
-
- kfree(kbuf);
}
+ kfree(kbuf);
return total_retlen;
} /* mtd_write */
@@ -299,13 +342,45 @@ static void mtdchar_erase_callback (struct erase_info *instr)
wake_up((wait_queue_head_t *)instr->priv);
}
+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP)
+static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
+{
+ struct mtd_info *mtd = mfi->mtd;
+ int ret = 0;
+
+ switch (mode) {
+ case MTD_OTP_FACTORY:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ mfi->mode = MTD_MODE_OTP_FACTORY;
+ break;
+ case MTD_OTP_USER:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ mfi->mode = MTD_MODE_OTP_USER;
+ break;
+ default:
+ ret = -EINVAL;
+ case MTD_OTP_OFF:
+ break;
+ }
+ return ret;
+}
+#else
+# define otp_select_filemode(f,m) -EOPNOTSUPP
+#endif
+
static int mtd_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
- struct mtd_info *mtd = TO_MTD(file);
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
void __user *argp = (void __user *)arg;
int ret = 0;
u_long size;
+ struct mtd_info_user info;
DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
@@ -341,7 +416,15 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
}
case MEMGETINFO:
- if (copy_to_user(argp, mtd, sizeof(struct mtd_info_user)))
+ info.type = mtd->type;
+ info.flags = mtd->flags;
+ info.size = mtd->size;
+ info.erasesize = mtd->erasesize;
+ info.writesize = mtd->writesize;
+ info.oobsize = mtd->oobsize;
+ info.ecctype = mtd->ecctype;
+ info.eccsize = mtd->eccsize;
+ if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
return -EFAULT;
break;
@@ -400,8 +483,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
case MEMWRITEOOB:
{
struct mtd_oob_buf buf;
- void *databuf;
- ssize_t retlen;
+ struct mtd_oob_ops ops;
if(!(file->f_mode & 2))
return -EPERM;
@@ -409,7 +491,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
return -EFAULT;
- if (buf.length > 0x4096)
+ if (buf.length > 4096)
return -EINVAL;
if (!mtd->write_oob)
@@ -421,21 +503,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;
- databuf = kmalloc(buf.length, GFP_KERNEL);
- if (!databuf)
+ ops.len = buf.length;
+ ops.ooblen = buf.length;
+ ops.ooboffs = buf.start & (mtd->oobsize - 1);
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_PLACE;
+
+ if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
+ return -EINVAL;
+
+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
+ if (!ops.oobbuf)
return -ENOMEM;
- if (copy_from_user(databuf, buf.ptr, buf.length)) {
- kfree(databuf);
+ if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
+ kfree(ops.oobbuf);
return -EFAULT;
}
- ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
+ buf.start &= ~(mtd->oobsize - 1);
+ ret = mtd->write_oob(mtd, buf.start, &ops);
- if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t)))
+ if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
+ sizeof(uint32_t)))
ret = -EFAULT;
- kfree(databuf);
+ kfree(ops.oobbuf);
break;
}
@@ -443,13 +536,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
case MEMREADOOB:
{
struct mtd_oob_buf buf;
- void *databuf;
- ssize_t retlen;
+ struct mtd_oob_ops ops;
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
return -EFAULT;
- if (buf.length > 0x4096)
+ if (buf.length > 4096)
return -EINVAL;
if (!mtd->read_oob)
@@ -457,22 +549,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
else
ret = access_ok(VERIFY_WRITE, buf.ptr,
buf.length) ? 0 : -EFAULT;
-
if (ret)
return ret;
- databuf = kmalloc(buf.length, GFP_KERNEL);
- if (!databuf)
+ ops.len = buf.length;
+ ops.ooblen = buf.length;
+ ops.ooboffs = buf.start & (mtd->oobsize - 1);
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_PLACE;
+
+ if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
+ return -EINVAL;
+
+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
+ if (!ops.oobbuf)
return -ENOMEM;
- ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
+ buf.start &= ~(mtd->oobsize - 1);
+ ret = mtd->read_oob(mtd, buf.start, &ops);
- if (put_user(retlen, (uint32_t __user *)argp))
+ if (put_user(ops.retlen, (uint32_t __user *)argp))
ret = -EFAULT;
- else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
+ else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
+ ops.retlen))
ret = -EFAULT;
- kfree(databuf);
+ kfree(ops.oobbuf);
break;
}
@@ -504,16 +606,22 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
- case MEMSETOOBSEL:
- {
- if (copy_from_user(&mtd->oobinfo, argp, sizeof(struct nand_oobinfo)))
- return -EFAULT;
- break;
- }
-
+ /* Legacy interface */
case MEMGETOOBSEL:
{
- if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo)))
+ struct nand_oobinfo oi;
+
+ if (!mtd->ecclayout)
+ return -EOPNOTSUPP;
+ if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
+ return -EINVAL;
+
+ oi.useecc = MTD_NANDECC_AUTOPLACE;
+ memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
+ memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
+ sizeof(oi.oobfree));
+
+ if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
return -EFAULT;
break;
}
@@ -544,31 +652,17 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
-#ifdef CONFIG_MTD_OTP
+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP)
case OTPSELECT:
{
int mode;
if (copy_from_user(&mode, argp, sizeof(int)))
return -EFAULT;
- SET_MTD_MODE(file, 0);
- switch (mode) {
- case MTD_OTP_FACTORY:
- if (!mtd->read_fact_prot_reg)
- ret = -EOPNOTSUPP;
- else
- SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
- break;
- case MTD_OTP_USER:
- if (!mtd->read_fact_prot_reg)
- ret = -EOPNOTSUPP;
- else
- SET_MTD_MODE(file, MTD_MODE_OTP_USER);
- break;
- default:
- ret = -EINVAL;
- case MTD_OTP_OFF:
- break;
- }
+
+ mfi->mode = MTD_MODE_NORMAL;
+
+ ret = otp_select_filemode(mfi, mode);
+
file->f_pos = 0;
break;
}
@@ -580,8 +674,8 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (!buf)
return -ENOMEM;
ret = -EOPNOTSUPP;
- switch (MTD_MODE(file)) {
- case MTD_MODE_OTP_FACT:
+ switch (mfi->mode) {
+ case MTD_MODE_OTP_FACTORY:
if (mtd->get_fact_prot_info)
ret = mtd->get_fact_prot_info(mtd, buf, 4096);
break;
@@ -589,6 +683,8 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (mtd->get_user_prot_info)
ret = mtd->get_user_prot_info(mtd, buf, 4096);
break;
+ default:
+ break;
}
if (ret >= 0) {
if (cmd == OTPGETREGIONCOUNT) {
@@ -607,7 +703,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
{
struct otp_info info;
- if (MTD_MODE(file) != MTD_MODE_OTP_USER)
+ if (mfi->mode != MTD_MODE_OTP_USER)
return -EINVAL;
if (copy_from_user(&info, argp, sizeof(info)))
return -EFAULT;
@@ -618,6 +714,49 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
}
#endif
+ case ECCGETLAYOUT:
+ {
+ if (!mtd->ecclayout)
+ return -EOPNOTSUPP;
+
+ if (copy_to_user(argp, &mtd->ecclayout,
+ sizeof(struct nand_ecclayout)))
+ return -EFAULT;
+ break;
+ }
+
+ case ECCGETSTATS:
+ {
+ if (copy_to_user(argp, &mtd->ecc_stats,
+ sizeof(struct mtd_ecc_stats)))
+ return -EFAULT;
+ break;
+ }
+
+ case MTDFILEMODE:
+ {
+ mfi->mode = 0;
+
+ switch(arg) {
+ case MTD_MODE_OTP_FACTORY:
+ case MTD_MODE_OTP_USER:
+ ret = otp_select_filemode(mfi, arg);
+ break;
+
+ case MTD_MODE_RAW:
+ if (!mtd->read_oob || !mtd->write_oob)
+ return -EOPNOTSUPP;
+ mfi->mode = arg;
+
+ case MTD_MODE_NORMAL:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ file->f_pos = 0;
+ break;
+ }
+
default:
ret = -ENOTTY;
}
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 9af840364a74..1fea631b5852 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -19,6 +19,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/concat.h>
+#include <asm/div64.h>
+
/*
* Our storage structure:
* Subdev points to an array of pointers to struct mtd_info objects
@@ -54,7 +56,7 @@ 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 ret = 0, err;
int i;
*retlen = 0;
@@ -78,19 +80,29 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
err = subdev->read(subdev, from, size, &retsize, buf);
- if (err)
- break;
+ /* Save information about bitflips! */
+ if (unlikely(err)) {
+ if (err == -EBADMSG) {
+ mtd->ecc_stats.failed++;
+ ret = err;
+ } else if (err == -EUCLEAN) {
+ mtd->ecc_stats.corrected++;
+ /* Do not overwrite -EBADMSG !! */
+ if (!ret)
+ ret = err;
+ } else
+ return err;
+ }
*retlen += retsize;
len -= size;
if (len == 0)
- break;
+ return ret;
- err = -EINVAL;
buf += size;
from = 0;
}
- return err;
+ return -EINVAL;
}
static int
@@ -141,211 +153,185 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
}
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)
+concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t * retlen)
{
struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
+ struct kvec *vecs_copy;
+ unsigned long entry_low, entry_high;
+ size_t total_len = 0;
int i;
+ int err = -EINVAL;
- *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;
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
- if (subdev->read_ecc)
- err = subdev->read_ecc(subdev, from, size,
- &retsize, buf, eccbuf, oobsel);
- else
- err = -EINVAL;
+ *retlen = 0;
- if (err)
- break;
+ /* Calculate total length of data */
+ for (i = 0; i < count; i++)
+ total_len += vecs[i].iov_len;
- *retlen += retsize;
- len -= size;
- if (len == 0)
- break;
+ /* Do not allow write past end of device */
+ if ((to + total_len) > mtd->size)
+ return -EINVAL;
- 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;
+ /* Check alignment */
+ if (mtd->writesize > 1) {
+ loff_t __to = to;
+ if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))
+ return -EINVAL;
}
- return err;
-}
-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;
- int i;
-
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-
- *retlen = 0;
+ /* make a copy of vecs */
+ vecs_copy = kmalloc(sizeof(struct kvec) * count, GFP_KERNEL);
+ if (!vecs_copy)
+ return -ENOMEM;
+ memcpy(vecs_copy, vecs, sizeof(struct kvec) * count);
+ entry_low = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
+ size_t size, wsize, retsize, old_iov_len;
if (to >= subdev->size) {
- size = 0;
to -= subdev->size;
continue;
}
- if (to + len > subdev->size)
- size = subdev->size - to;
- else
- size = len;
+
+ size = min(total_len, (size_t)(subdev->size - to));
+ wsize = size; /* store for future use */
+
+ entry_high = entry_low;
+ while (entry_high < count) {
+ if (size <= vecs_copy[entry_high].iov_len)
+ break;
+ size -= vecs_copy[entry_high++].iov_len;
+ }
+
+ old_iov_len = vecs_copy[entry_high].iov_len;
+ vecs_copy[entry_high].iov_len = size;
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;
+ err = subdev->writev(subdev, &vecs_copy[entry_low],
+ entry_high - entry_low + 1, to, &retsize);
+
+ vecs_copy[entry_high].iov_len = old_iov_len - size;
+ vecs_copy[entry_high].iov_base += size;
+
+ entry_low = entry_high;
if (err)
break;
*retlen += retsize;
- len -= size;
- if (len == 0)
+ total_len -= wsize;
+
+ if (total_len == 0)
break;
err = -EINVAL;
- buf += size;
- if (eccbuf)
- eccbuf += subdev->oobsize;
to = 0;
}
+
+ kfree(vecs_copy);
return err;
}
static int
-concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf)
+concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
- int i;
+ struct mtd_oob_ops devops = *ops;
+ int i, err, ret = 0;
- *retlen = 0;
+ ops->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;
- if (subdev->read_oob)
- err = subdev->read_oob(subdev, from, size,
- &retsize, buf);
- else
- err = -EINVAL;
+ /* partial read ? */
+ if (from + devops.len > subdev->size)
+ devops.len = subdev->size - from;
+
+ err = subdev->read_oob(subdev, from, &devops);
+ ops->retlen += devops.retlen;
+
+ /* Save information about bitflips! */
+ if (unlikely(err)) {
+ if (err == -EBADMSG) {
+ mtd->ecc_stats.failed++;
+ ret = err;
+ } else if (err == -EUCLEAN) {
+ mtd->ecc_stats.corrected++;
+ /* Do not overwrite -EBADMSG !! */
+ if (!ret)
+ ret = err;
+ } else
+ return err;
+ }
- if (err)
- break;
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return ret;
- *retlen += retsize;
- len -= size;
- if (len == 0)
- break;
+ if (devops.datbuf)
+ devops.datbuf += devops.retlen;
+ if (devops.oobbuf)
+ devops.oobbuf += devops.ooblen;
- err = -EINVAL;
- buf += size;
from = 0;
}
- return err;
+ return -EINVAL;
}
static int
-concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
- size_t * retlen, const u_char * buf)
+concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
{
struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
- int i;
+ struct mtd_oob_ops devops = *ops;
+ int i, err;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
- *retlen = 0;
+ ops->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;
+ /* partial write ? */
+ if (to + devops.len > subdev->size)
+ devops.len = subdev->size - to;
+ err = subdev->write_oob(subdev, to, &devops);
+ ops->retlen += devops.retlen;
if (err)
- break;
+ return err;
- *retlen += retsize;
- len -= size;
- if (len == 0)
- break;
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return 0;
- err = -EINVAL;
- buf += size;
+ if (devops.datbuf)
+ devops.datbuf += devops.retlen;
+ if (devops.oobbuf)
+ devops.oobbuf += devops.ooblen;
to = 0;
}
- return err;
+ return -EINVAL;
}
static void concat_erase_callback(struct erase_info *instr)
@@ -636,6 +622,60 @@ static void concat_resume(struct mtd_info *mtd)
}
}
+static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, res = 0;
+
+ if (!concat->subdev[0]->block_isbad)
+ return res;
+
+ if (ofs > mtd->size)
+ return -EINVAL;
+
+ for (i = 0; i < concat->num_subdev; i++) {
+ struct mtd_info *subdev = concat->subdev[i];
+
+ if (ofs >= subdev->size) {
+ ofs -= subdev->size;
+ continue;
+ }
+
+ res = subdev->block_isbad(subdev, ofs);
+ break;
+ }
+
+ return res;
+}
+
+static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = -EINVAL;
+
+ if (!concat->subdev[0]->block_markbad)
+ return 0;
+
+ if (ofs > mtd->size)
+ return -EINVAL;
+
+ for (i = 0; i < concat->num_subdev; i++) {
+ struct mtd_info *subdev = concat->subdev[i];
+
+ if (ofs >= subdev->size) {
+ ofs -= subdev->size;
+ continue;
+ }
+
+ err = subdev->block_markbad(subdev, ofs);
+ if (!err)
+ mtd->ecc_stats.badblocks++;
+ break;
+ }
+
+ return err;
+}
+
/*
* This function constructs a virtual MTD device by concatenating
* num_devs MTD devices. A pointer to the new device object is
@@ -677,18 +717,22 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
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.writesize = subdev[0]->writesize;
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]->writev)
+ concat->mtd.writev = concat_writev;
if (subdev[0]->read_oob)
concat->mtd.read_oob = concat_read_oob;
if (subdev[0]->write_oob)
concat->mtd.write_oob = concat_write_oob;
+ if (subdev[0]->block_isbad)
+ concat->mtd.block_isbad = concat_block_isbad;
+ if (subdev[0]->block_markbad)
+ concat->mtd.block_markbad = concat_block_markbad;
+
+ concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
concat->subdev[0] = subdev[0];
@@ -717,12 +761,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
subdev[i]->flags & MTD_WRITEABLE;
}
concat->mtd.size += subdev[i]->size;
- if (concat->mtd.oobblock != subdev[i]->oobblock ||
+ concat->mtd.ecc_stats.badblocks +=
+ subdev[i]->ecc_stats.badblocks;
+ if (concat->mtd.writesize != subdev[i]->writesize ||
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);
@@ -734,14 +778,11 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
}
+ concat->mtd.ecclayout = subdev[0]->ecclayout;
+
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;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9905870f56e5..16a952dd486a 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -47,6 +47,7 @@ int add_mtd_device(struct mtd_info *mtd)
{
int i;
+ BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
for (i=0; i < MAX_MTD_DEVICES; i++)
@@ -254,37 +255,6 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
return ret;
}
-
-/* default_mtd_readv - default mtd readv method for MTD devices that dont
- * implement their own
- */
-
-int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen)
-{
- unsigned long i;
- size_t totlen = 0, thislen;
- int ret = 0;
-
- if(!mtd->read) {
- ret = -EIO;
- } else {
- for (i=0; i<count; i++) {
- if (!vecs[i].iov_len)
- continue;
- ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base);
- totlen += thislen;
- if (ret || thislen != vecs[i].iov_len)
- break;
- from += vecs[i].iov_len;
- }
- }
- if (retlen)
- *retlen = totlen;
- return ret;
-}
-
-
EXPORT_SYMBOL(add_mtd_device);
EXPORT_SYMBOL(del_mtd_device);
EXPORT_SYMBOL(get_mtd_device);
@@ -292,7 +262,6 @@ EXPORT_SYMBOL(put_mtd_device);
EXPORT_SYMBOL(register_mtd_user);
EXPORT_SYMBOL(unregister_mtd_user);
EXPORT_SYMBOL(default_mtd_writev);
-EXPORT_SYMBOL(default_mtd_readv);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 99395911d26f..77a7123a5c56 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -51,16 +51,21 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
+ int res;
+
if (from >= mtd->size)
len = 0;
else if (from + len > mtd->size)
len = mtd->size - from;
- 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);
+ res = part->master->read (part->master, from + part->offset,
+ len, retlen, buf);
+ if (unlikely(res)) {
+ if (res == -EUCLEAN)
+ mtd->ecc_stats.corrected++;
+ if (res == -EBADMSG)
+ mtd->ecc_stats.failed++;
+ }
+ return res;
}
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
@@ -74,6 +79,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
return part->master->point (part->master, from + part->offset,
len, retlen, buf);
}
+
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
{
struct mtd_part *part = PART(mtd);
@@ -81,31 +87,25 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
part->master->unpoint (part->master, addr, from + part->offset, len);
}
-
-static int part_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)
+static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
struct mtd_part *part = PART(mtd);
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
- if (from >= mtd->size)
- len = 0;
- else if (from + len > mtd->size)
- len = mtd->size - from;
- return part->master->read_ecc (part->master, from + part->offset,
- len, retlen, buf, eccbuf, oobsel);
-}
+ int res;
-static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
- len = 0;
- else if (from + len > mtd->size)
- len = mtd->size - from;
- return part->master->read_oob (part->master, from + part->offset,
- len, retlen, buf);
+ return -EINVAL;
+ if (from + ops->len > mtd->size)
+ return -EINVAL;
+ res = part->master->read_oob(part->master, from + part->offset, ops);
+
+ if (unlikely(res)) {
+ if (res == -EUCLEAN)
+ mtd->ecc_stats.corrected++;
+ if (res == -EBADMSG)
+ mtd->ecc_stats.failed++;
+ }
+ return res;
}
static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
@@ -148,44 +148,23 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
len = 0;
else if (to + len > mtd->size)
len = mtd->size - to;
- 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);
-
+ return part->master->write (part->master, to + part->offset,
+ len, retlen, buf);
}
-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, struct nand_oobinfo *oobsel)
+static int part_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
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)
- len = mtd->size - to;
- return part->master->write_ecc (part->master, to + part->offset,
- len, retlen, buf, eccbuf, oobsel);
-}
-static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
+
if (to >= mtd->size)
- len = 0;
- else if (to + len > mtd->size)
- len = mtd->size - to;
- return part->master->write_oob (part->master, to + part->offset,
- len, retlen, buf);
+ return -EINVAL;
+ if (to + ops->len > mtd->size)
+ return -EINVAL;
+ return part->master->write_oob(part->master, to + part->offset, ops);
}
static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
@@ -208,52 +187,8 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
- if (part->master->writev_ecc == NULL)
- return part->master->writev (part->master, vecs, count,
+ 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 kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen)
-{
- struct mtd_part *part = PART(mtd);
- 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 kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
- 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);
-}
-
-static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen,
- 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);
}
static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
@@ -329,12 +264,17 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
{
struct mtd_part *part = PART(mtd);
+ int res;
+
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (ofs >= mtd->size)
return -EINVAL;
ofs += part->offset;
- return part->master->block_markbad(part->master, ofs);
+ res = part->master->block_markbad(part->master, ofs);
+ if (!res)
+ mtd->ecc_stats.badblocks++;
+ return res;
}
/*
@@ -398,7 +338,7 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.type = master->type;
slave->mtd.flags = master->flags & ~parts[i].mask_flags;
slave->mtd.size = parts[i].size;
- slave->mtd.oobblock = master->oobblock;
+ slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
slave->mtd.ecctype = master->ecctype;
slave->mtd.eccsize = master->eccsize;
@@ -415,10 +355,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.unpoint = part_unpoint;
}
- if (master->read_ecc)
- slave->mtd.read_ecc = part_read_ecc;
- if (master->write_ecc)
- slave->mtd.write_ecc = part_write_ecc;
if (master->read_oob)
slave->mtd.read_oob = part_read_oob;
if (master->write_oob)
@@ -443,12 +379,6 @@ int add_mtd_partitions(struct mtd_info *master,
}
if (master->writev)
slave->mtd.writev = part_writev;
- if (master->readv)
- slave->mtd.readv = part_readv;
- if (master->writev_ecc)
- slave->mtd.writev_ecc = part_writev_ecc;
- if (master->readv_ecc)
- slave->mtd.readv_ecc = part_readv_ecc;
if (master->lock)
slave->mtd.lock = part_lock;
if (master->unlock)
@@ -528,8 +458,17 @@ int add_mtd_partitions(struct mtd_info *master,
parts[i].name);
}
- /* copy oobinfo from master */
- memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
+ slave->mtd.ecclayout = master->ecclayout;
+ if (master->block_isbad) {
+ uint32_t offs = 0;
+
+ while(offs < slave->mtd.size) {
+ if (master->block_isbad(master,
+ offs + slave->offset))
+ slave->mtd.ecc_stats.badblocks++;
+ offs += slave->mtd.erasesize;
+ }
+ }
if(parts[i].mtdp)
{ /* store the object pointer (caller may or may not register it */
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index cfe288a6e853..3db77eec0ed2 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -23,6 +23,14 @@ config MTD_NAND_VERIFY_WRITE
device thinks the write was successful, a bit could have been
flipped accidentaly due to device wear or something else.
+config MTD_NAND_ECC_SMC
+ bool "NAND ECC Smart Media byte order"
+ depends on MTD_NAND
+ default n
+ help
+ Software ECC according to the Smart Media Specification.
+ The original Linux implementation had byte 0 and 1 swapped.
+
config MTD_NAND_AUTCPU12
tristate "SmartMediaCard on autronix autcpu12 board"
depends on MTD_NAND && ARCH_AUTCPU12
@@ -49,12 +57,24 @@ config MTD_NAND_SPIA
help
If you had to ask, you don't have one. Say 'N'.
+config MTD_NAND_AMS_DELTA
+ tristate "NAND Flash device on Amstrad E3"
+ depends on MACH_AMS_DELTA && MTD_NAND
+ help
+ Support for NAND flash on Amstrad E3 (Delta).
+
config MTD_NAND_TOTO
tristate "NAND Flash device on TOTO board"
- depends on ARCH_OMAP && MTD_NAND
+ depends on ARCH_OMAP && MTD_NAND && BROKEN
help
Support for NAND flash on Texas Instruments Toto platform.
+config MTD_NAND_TS7250
+ tristate "NAND Flash device on TS-7250 board"
+ depends on MACH_TS72XX && MTD_NAND
+ help
+ Support for NAND flash on Technologic Systems TS-7250 platform.
+
config MTD_NAND_IDS
tristate
@@ -76,7 +96,7 @@ config MTD_NAND_RTC_FROM4
config MTD_NAND_PPCHAMELEONEVB
tristate "NAND Flash device on PPChameleonEVB board"
- depends on PPCHAMELEONEVB && MTD_NAND
+ depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
help
This enables the NAND flash driver on the PPChameleon EVB Board.
@@ -87,7 +107,7 @@ config MTD_NAND_S3C2410
This enables the NAND flash controller on the S3C2410 and S3C2440
SoCs
- No board specfic support is done by this driver, each board
+ No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
@@ -109,6 +129,22 @@ config MTD_NAND_S3C2410_HWECC
currently not be able to switch to software, as there is no
implementation for ECC method used by the S3C2410
+config MTD_NAND_NDFC
+ tristate "NDFC NanD Flash Controller"
+ depends on MTD_NAND && 44x
+ help
+ NDFC Nand Flash Controllers are integrated in EP44x SoCs
+
+config MTD_NAND_S3C2410_CLKSTOP
+ bool "S3C2410 NAND IDLE clock stop"
+ depends on MTD_NAND_S3C2410
+ default n
+ help
+ Stop the clock to the NAND controller when there is no chip
+ selected to save power. This will mean there is a small delay
+ when the is NAND chip selected or released, but will save
+ approximately 5mA of power when there is nothing happening.
+
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on MTD_NAND && EXPERIMENTAL
@@ -183,11 +219,24 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
+config MTD_NAND_CS553X
+ tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+ depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
+ help
+ The CS553x companion chips for the AMD Geode processor
+ include NAND flash controllers with built-in hardware ECC
+ capabilities; enabling this option will allow you to use
+ these. The driver will check the MSRs to verify that the
+ controller is enabled for NAND, and currently requires that
+ the controller be in MMIO mode.
+
+ If you say "m", the module will be called "cs553x_nand.ko".
+
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
depends on MTD_NAND && MTD_PARTITIONS
help
- The simulator may simulate verious NAND flash chips for the
+ The simulator may simulate various NAND flash chips for the
MTD nand layer.
endmenu
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 41742026a52e..f74759351c91 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
+obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
@@ -17,6 +18,9 @@ obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
+obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
+obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
+obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
nand-objs = nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
new file mode 100644
index 000000000000..d7897dc6b3c8
--- /dev/null
+++ b/drivers/mtd/nand/ams-delta.c
@@ -0,0 +1,237 @@
+/*
+ * drivers/mtd/nand/ams-delta.c
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * Derived from drivers/mtd/toto.c
+ *
+ * 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.
+ *
+ * Overview:
+ * This is a device driver for the NAND flash device found on the
+ * Amstrad E3 (Delta).
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/sizes.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board-ams-delta.h>
+
+/*
+ * MTD structure for E3 (Delta)
+ */
+static struct mtd_info *ams_delta_mtd = NULL;
+
+#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
+
+/*
+ * Define partitions for flash devices
+ */
+
+static struct mtd_partition partition_info[] = {
+ { .name = "Kernel",
+ .offset = 0,
+ .size = 3 * SZ_1M + SZ_512K },
+ { .name = "u-boot",
+ .offset = 3 * SZ_1M + SZ_512K,
+ .size = SZ_256K },
+ { .name = "u-boot params",
+ .offset = 3 * SZ_1M + SZ_512K + SZ_256K,
+ .size = SZ_256K },
+ { .name = "Amstrad LDR",
+ .offset = 4 * SZ_1M,
+ .size = SZ_256K },
+ { .name = "File system",
+ .offset = 4 * SZ_1M + 1 * SZ_256K,
+ .size = 27 * SZ_1M },
+ { .name = "PBL reserved",
+ .offset = 32 * SZ_1M - 3 * SZ_256K,
+ .size = 3 * SZ_256K },
+};
+
+static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+{
+ struct nand_chip *this = mtd->priv;
+
+ omap_writew(0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
+ omap_writew(byte, this->IO_ADDR_W);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
+ ndelay(40);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
+ AMS_DELTA_LATCH2_NAND_NWE);
+}
+
+static u_char ams_delta_read_byte(struct mtd_info *mtd)
+{
+ u_char res;
+ struct nand_chip *this = mtd->priv;
+
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
+ ndelay(40);
+ omap_writew(~0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
+ res = omap_readw(this->IO_ADDR_R);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
+ AMS_DELTA_LATCH2_NAND_NRE);
+
+ return res;
+}
+
+static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ ams_delta_write_byte(mtd, buf[i]);
+}
+
+static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ buf[i] = ams_delta_read_byte(mtd);
+}
+
+static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ if (buf[i] != ams_delta_read_byte(mtd))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Command control function
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 -> bit 2
+ * NAND_CLE: bit 1 -> bit 7
+ * NAND_ALE: bit 2 -> bit 6
+ */
+static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned long bits;
+
+ bits = (~ctrl & NAND_NCE) << 2;
+ bits |= (ctrl & NAND_CLE) << 7;
+ bits |= (ctrl & NAND_ALE) << 6;
+
+ ams_delta_latch2_write(0xC2, bits);
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ ams_delta_write_byte(mtd, cmd);
+}
+
+static int ams_delta_nand_ready(struct mtd_info *mtd)
+{
+ return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init ams_delta_init(void)
+{
+ struct nand_chip *this;
+ int err = 0;
+
+ /* Allocate memory for MTD device structure and private data */
+ ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
+ sizeof(struct nand_chip), GFP_KERNEL);
+ if (!ams_delta_mtd) {
+ printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ ams_delta_mtd->owner = THIS_MODULE;
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&ams_delta_mtd[1]);
+
+ /* Initialize structures */
+ memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ ams_delta_mtd->priv = this;
+
+ /* Set address of NAND IO lines */
+ this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
+ this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
+ this->read_byte = ams_delta_read_byte;
+ this->write_buf = ams_delta_write_buf;
+ this->read_buf = ams_delta_read_buf;
+ this->verify_buf = ams_delta_verify_buf;
+ this->cmd_ctrl = ams_delta_hwcontrol;
+ if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
+ this->dev_ready = ams_delta_nand_ready;
+ } else {
+ this->dev_ready = NULL;
+ printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
+ }
+ /* 25 us command delay time */
+ this->chip_delay = 30;
+ this->ecc.mode = NAND_ECC_SOFT;
+
+ /* Set chip enabled, but */
+ ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
+ AMS_DELTA_LATCH2_NAND_NWE |
+ AMS_DELTA_LATCH2_NAND_NCE |
+ AMS_DELTA_LATCH2_NAND_NWP);
+
+ /* Scan to find existance of the device */
+ if (nand_scan(ams_delta_mtd, 1)) {
+ err = -ENXIO;
+ goto out_mtd;
+ }
+
+ /* Register the partitions */
+ add_mtd_partitions(ams_delta_mtd, partition_info,
+ ARRAY_SIZE(partition_info));
+
+ goto out;
+
+ out_mtd:
+ kfree(ams_delta_mtd);
+ out:
+ return err;
+}
+
+module_init(ams_delta_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit ams_delta_cleanup(void)
+{
+ /* Release resources, unregister device */
+ nand_release(ams_delta_mtd);
+
+ /* Free the MTD device structure */
+ kfree(ams_delta_mtd);
+}
+module_exit(ams_delta_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
+MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index bde3550910a2..31228334da12 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -38,22 +39,21 @@
*/
static struct mtd_info *au1550_mtd = NULL;
static void __iomem *p_nand;
-static int nand_width = 1; /* default x8*/
+static int nand_width = 1; /* default x8 */
+static void (*au1550_write_byte)(struct mtd_info *, u_char);
/*
* Define partitions for flash device
*/
static const struct mtd_partition partition_info[] = {
{
- .name = "NAND FS 0",
- .offset = 0,
- .size = 8*1024*1024
- },
+ .name = "NAND FS 0",
+ .offset = 0,
+ .size = 8 * 1024 * 1024},
{
- .name = "NAND FS 1",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL
- }
+ .name = "NAND FS 1",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL}
};
/**
@@ -130,21 +130,6 @@ static u16 au_read_word(struct mtd_info *mtd)
}
/**
- * au_write_word - write one word to the chip
- * @mtd: MTD device structure
- * @word: data word to write
- *
- * write function for 16bit buswith without
- * endianess conversion
- */
-static void au_write_word(struct mtd_info *mtd, u16 word)
-{
- struct nand_chip *this = mtd->priv;
- writew(word, this->IO_ADDR_W);
- au_sync();
-}
-
-/**
* au_write_buf - write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
@@ -157,7 +142,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
int i;
struct nand_chip *this = mtd->priv;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
writeb(buf[i], this->IO_ADDR_W);
au_sync();
}
@@ -176,7 +161,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
int i;
struct nand_chip *this = mtd->priv;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
buf[i] = readb(this->IO_ADDR_R);
au_sync();
}
@@ -195,7 +180,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
int i;
struct nand_chip *this = mtd->priv;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
if (buf[i] != readb(this->IO_ADDR_R))
return -EFAULT;
au_sync();
@@ -219,7 +204,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
writew(p[i], this->IO_ADDR_W);
au_sync();
}
@@ -241,7 +226,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
p[i] = readw(this->IO_ADDR_R);
au_sync();
}
@@ -262,7 +247,7 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
if (p[i] != readw(this->IO_ADDR_R))
return -EFAULT;
au_sync();
@@ -270,32 +255,52 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
return 0;
}
+/* Select the chip by setting nCE to low */
+#define NAND_CTL_SETNCE 1
+/* Deselect the chip by setting nCE to high */
+#define NAND_CTL_CLRNCE 2
+/* Select the command latch by setting CLE to high */
+#define NAND_CTL_SETCLE 3
+/* Deselect the command latch by setting CLE to low */
+#define NAND_CTL_CLRCLE 4
+/* Select the address latch by setting ALE to high */
+#define NAND_CTL_SETALE 5
+/* Deselect the address latch by setting ALE to low */
+#define NAND_CTL_CLRALE 6
static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
{
register struct nand_chip *this = mtd->priv;
- switch(cmd){
+ switch (cmd) {
- case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;
- case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
+ case NAND_CTL_SETCLE:
+ this->IO_ADDR_W = p_nand + MEM_STNAND_CMD;
+ break;
+
+ case NAND_CTL_CLRCLE:
+ this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+ break;
+
+ case NAND_CTL_SETALE:
+ this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR;
+ break;
- case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
case NAND_CTL_CLRALE:
this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
- /* FIXME: Nobody knows why this is neccecary,
+ /* FIXME: Nobody knows why this is necessary,
* but it works only that way */
udelay(1);
break;
case NAND_CTL_SETNCE:
/* assert (force assert) chip enable */
- au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
+ au_writel((1 << (4 + NAND_CS)), MEM_STNDCTL);
break;
case NAND_CTL_CLRNCE:
- /* deassert chip enable */
- au_writel(0, MEM_STNDCTL); break;
+ /* deassert chip enable */
+ au_writel(0, MEM_STNDCTL);
break;
}
@@ -312,69 +317,200 @@ int au1550_device_ready(struct mtd_info *mtd)
return ret;
}
+/**
+ * au1550_select_chip - control -CE line
+ * Forbid driving -CE manually permitting the NAND controller to do this.
+ * Keeping -CE asserted during the whole sector reads interferes with the
+ * NOR flash and PCMCIA drivers as it causes contention on the static bus.
+ * We only have to hold -CE low for the NAND read commands since the flash
+ * chip needs it to be asserted during chip not ready time but the NAND
+ * controller keeps it released.
+ *
+ * @mtd: MTD device structure
+ * @chip: chipnumber to select, -1 for deselect
+ */
+static void au1550_select_chip(struct mtd_info *mtd, int chip)
+{
+}
+
+/**
+ * au1550_command - Send command to NAND device
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ */
+static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+ register struct nand_chip *this = mtd->priv;
+ int ce_override = 0, i;
+ ulong flags;
+
+ /* Begin command latch cycle */
+ au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
+ /*
+ * Write out the command to the device.
+ */
+ if (command == NAND_CMD_SEQIN) {
+ int readcmd;
+
+ if (column >= mtd->writesize) {
+ /* OOB area */
+ column -= mtd->writesize;
+ readcmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ readcmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ readcmd = NAND_CMD_READ1;
+ }
+ au1550_write_byte(mtd, readcmd);
+ }
+ au1550_write_byte(mtd, command);
+
+ /* Set ALE and clear CLE to start address cycle */
+ au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+ if (column != -1 || page_addr != -1) {
+ au1550_hwcontrol(mtd, NAND_CTL_SETALE);
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (this->options & NAND_BUSWIDTH_16)
+ column >>= 1;
+ au1550_write_byte(mtd, column);
+ }
+ if (page_addr != -1) {
+ au1550_write_byte(mtd, (u8)(page_addr & 0xff));
+
+ if (command == NAND_CMD_READ0 ||
+ command == NAND_CMD_READ1 ||
+ command == NAND_CMD_READOOB) {
+ /*
+ * NAND controller will release -CE after
+ * the last address byte is written, so we'll
+ * have to forcibly assert it. No interrupts
+ * are allowed while we do this as we don't
+ * want the NOR flash or PCMCIA drivers to
+ * steal our precious bytes of data...
+ */
+ ce_override = 1;
+ local_irq_save(flags);
+ au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
+ }
+
+ au1550_write_byte(mtd, (u8)(page_addr >> 8));
+
+ /* One more address cycle for devices > 32MiB */
+ if (this->chipsize > (32 << 20))
+ au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f));
+ }
+ /* Latch in address */
+ au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
+ }
+
+ /*
+ * Program and erase have their own busy handlers.
+ * Status and sequential in need no delay.
+ */
+ switch (command) {
+
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ return;
+
+ case NAND_CMD_RESET:
+ break;
+
+ case NAND_CMD_READ0:
+ case NAND_CMD_READ1:
+ case NAND_CMD_READOOB:
+ /* Check if we're really driving -CE low (just in case) */
+ if (unlikely(!ce_override))
+ break;
+
+ /* Apply a short delay always to ensure that we do wait tWB. */
+ ndelay(100);
+ /* Wait for a chip to become ready... */
+ for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+ udelay(1);
+
+ /* Release -CE and re-enable interrupts. */
+ au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
+ local_irq_restore(flags);
+ return;
+ }
+ /* Apply this short delay always to ensure that we do wait tWB. */
+ ndelay(100);
+
+ while(!this->dev_ready(mtd));
+}
+
+
/*
* Main initialization routine
*/
-int __init au1xxx_nand_init (void)
+static int __init au1xxx_nand_init(void)
{
struct nand_chip *this;
- u16 boot_swapboot = 0; /* default value */
+ u16 boot_swapboot = 0; /* default value */
int retval;
u32 mem_staddr;
u32 nand_phys;
/* Allocate memory for MTD device structure and private data */
- au1550_mtd = kmalloc (sizeof(struct mtd_info) +
- sizeof (struct nand_chip), GFP_KERNEL);
+ au1550_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!au1550_mtd) {
- printk ("Unable to allocate NAND MTD dev structure.\n");
+ printk("Unable to allocate NAND MTD dev structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&au1550_mtd[1]);
+ this = (struct nand_chip *)(&au1550_mtd[1]);
/* Initialize structures */
- memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(au1550_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
au1550_mtd->priv = this;
+ au1550_mtd->owner = THIS_MODULE;
- /* disable interrupts */
- au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
-
- /* disable NAND boot */
- au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
+ /* MEM_STNDCTL: disable ints, disable nand boot */
+ au_writel(0, MEM_STNDCTL);
#ifdef CONFIG_MIPS_PB1550
/* set gpio206 high */
- au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
+ au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR);
- boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
- ((bcsr->status >> 6) & 0x1);
+ boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr->status >> 6) & 0x1);
switch (boot_swapboot) {
- case 0:
- case 2:
- case 8:
- case 0xC:
- case 0xD:
- /* x16 NAND Flash */
- nand_width = 0;
- break;
- case 1:
- case 9:
- case 3:
- case 0xE:
- case 0xF:
- /* x8 NAND Flash */
- nand_width = 1;
- break;
- default:
- printk("Pb1550 NAND: bad boot:swap\n");
- retval = -EINVAL;
- goto outmem;
+ case 0:
+ case 2:
+ case 8:
+ case 0xC:
+ case 0xD:
+ /* x16 NAND Flash */
+ nand_width = 0;
+ break;
+ case 1:
+ case 9:
+ case 3:
+ case 0xE:
+ case 0xF:
+ /* x8 NAND Flash */
+ nand_width = 1;
+ break;
+ default:
+ printk("Pb1550 NAND: bad boot:swap\n");
+ retval = -EINVAL;
+ goto outmem;
}
#endif
@@ -424,21 +560,22 @@ int __init au1xxx_nand_init (void)
/* make controller and MTD agree */
if (NAND_CS == 0)
- nand_width = au_readl(MEM_STCFG0) & (1<<22);
+ nand_width = au_readl(MEM_STCFG0) & (1 << 22);
if (NAND_CS == 1)
- nand_width = au_readl(MEM_STCFG1) & (1<<22);
+ nand_width = au_readl(MEM_STCFG1) & (1 << 22);
if (NAND_CS == 2)
- nand_width = au_readl(MEM_STCFG2) & (1<<22);
+ nand_width = au_readl(MEM_STCFG2) & (1 << 22);
if (NAND_CS == 3)
- nand_width = au_readl(MEM_STCFG3) & (1<<22);
-
+ nand_width = au_readl(MEM_STCFG3) & (1 << 22);
/* Set address of hardware control function */
- this->hwcontrol = au1550_hwcontrol;
this->dev_ready = au1550_device_ready;
+ this->select_chip = au1550_select_chip;
+ this->cmdfunc = au1550_command;
+
/* 30 us command delay time */
this->chip_delay = 30;
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
this->options = NAND_NO_AUTOINCR;
@@ -446,15 +583,14 @@ int __init au1xxx_nand_init (void)
this->options |= NAND_BUSWIDTH_16;
this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
- this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
- this->write_word = au_write_word;
+ au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
this->read_word = au_read_word;
this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
/* Scan to find existence of the device */
- if (nand_scan (au1550_mtd, 1)) {
+ if (nand_scan(au1550_mtd, 1)) {
retval = -ENXIO;
goto outio;
}
@@ -465,10 +601,10 @@ int __init au1xxx_nand_init (void)
return 0;
outio:
- iounmap ((void *)p_nand);
+ iounmap((void *)p_nand);
outmem:
- kfree (au1550_mtd);
+ kfree(au1550_mtd);
return retval;
}
@@ -477,22 +613,21 @@ module_init(au1xxx_nand_init);
/*
* Clean up routine
*/
-#ifdef MODULE
-static void __exit au1550_cleanup (void)
+static void __exit au1550_cleanup(void)
{
- struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];
+ struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1];
/* Release resources, unregister device */
- nand_release (au1550_mtd);
+ nand_release(au1550_mtd);
/* Free the MTD device structure */
- kfree (au1550_mtd);
+ kfree(au1550_mtd);
/* Unmap */
- iounmap ((void *)p_nand);
+ iounmap((void *)p_nand);
}
+
module_exit(au1550_cleanup);
-#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Embedded Edge, LLC");
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index a3c7fea404d0..fe94ae9ae1f2 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -4,7 +4,7 @@
* Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
*
* Derived from drivers/mtd/spia.c
- * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
* $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $
*
@@ -42,12 +42,7 @@
* MTD structure for AUTCPU12 board
*/
static struct mtd_info *autcpu12_mtd = NULL;
-
-static int autcpu12_io_base = CS89712_VIRT_BASE;
-static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
-static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
-static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
-static void __iomem * autcpu12_fio_base;
+static void __iomem *autcpu12_fio_base;
/*
* Define partitions for flash devices
@@ -94,108 +89,131 @@ static struct mtd_partition partition_info128k[] = {
#define NUM_PARTITIONS128K 2
/*
* hardware specific access to control-lines
-*/
-static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
+ *
+ * ALE bit 4 autcpu12_pedr
+ * CLE bit 5 autcpu12_pedr
+ * NCE bit 0 fio_ctrl
+ *
+ */
+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
+ struct nand_chip *chip = mtd->priv;
- switch(cmd){
-
- case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break;
- case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
+ if (ctrl & NAND_CTRL_CHANGE) {
+ void __iomem *addr
+ unsigned char bits;
- case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break;
- case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
+ addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
+ bits = (ctrl & NAND_CLE) << 4;
+ bits |= (ctrl & NAND_ALE) << 2;
+ writeb((readb(addr) & ~0x30) | bits, addr);
- case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
- case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
+ addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
+ writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
}
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
/*
-* read device ready pin
-*/
+ * read device ready pin
+ */
int autcpu12_device_ready(struct mtd_info *mtd)
{
+ void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
- return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
-
+ return readb(addr) & AUTCPU12_SMC_RDY;
}
/*
* Main initialization routine
*/
-int __init autcpu12_init (void)
+static int __init autcpu12_init(void)
{
struct nand_chip *this;
int err = 0;
/* Allocate memory for MTD device structure and private data */
- autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
+ autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
+ GFP_KERNEL);
if (!autcpu12_mtd) {
- printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
+ printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
/* map physical adress */
- autcpu12_fio_base = ioremap(autcpu12_fio_pbase,SZ_1K);
- if(!autcpu12_fio_base){
+ autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
+ if (!autcpu12_fio_base) {
printk("Ioremap autcpu12 SmartMedia Card failed\n");
err = -EIO;
goto out_mtd;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&autcpu12_mtd[1]);
+ this = (struct nand_chip *)(&autcpu12_mtd[1]);
/* Initialize structures */
- memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(autcpu12_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
autcpu12_mtd->priv = this;
+ autcpu12_mtd->owner = THIS_MODULE;
/* Set address of NAND IO lines */
this->IO_ADDR_R = autcpu12_fio_base;
this->IO_ADDR_W = autcpu12_fio_base;
- this->hwcontrol = autcpu12_hwcontrol;
+ this->cmd_ctrl = autcpu12_hwcontrol;
this->dev_ready = autcpu12_device_ready;
/* 20 us command delay time */
this->chip_delay = 20;
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
/* Enable the following for a flash based bad block table */
/*
- this->options = NAND_USE_FLASH_BBT;
- */
+ this->options = NAND_USE_FLASH_BBT;
+ */
this->options = NAND_USE_FLASH_BBT;
/* Scan to find existance of the device */
- if (nand_scan (autcpu12_mtd, 1)) {
+ if (nand_scan(autcpu12_mtd, 1)) {
err = -ENXIO;
goto out_ior;
}
/* Register the partitions */
- switch(autcpu12_mtd->size){
- case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
- case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
- case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
- case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
- default: {
- printk ("Unsupported SmartMedia device\n");
+ switch (autcpu12_mtd->size) {
+ case SZ_16M:
+ add_mtd_partitions(autcpu12_mtd, partition_info16k,
+ NUM_PARTITIONS16K);
+ break;
+ case SZ_32M:
+ add_mtd_partitions(autcpu12_mtd, partition_info32k,
+ NUM_PARTITIONS32K);
+ break;
+ case SZ_64M:
+ add_mtd_partitions(autcpu12_mtd, partition_info64k,
+ NUM_PARTITIONS64K);
+ break;
+ case SZ_128M:
+ add_mtd_partitions(autcpu12_mtd, partition_info128k,
+ NUM_PARTITIONS128K);
+ break;
+ default:
+ printk("Unsupported SmartMedia device\n");
err = -ENXIO;
goto out_ior;
- }
}
goto out;
-out_ior:
- iounmap((void *)autcpu12_fio_base);
-out_mtd:
- kfree (autcpu12_mtd);
-out:
+ out_ior:
+ iounmap(autcpu12_fio_base);
+ out_mtd:
+ kfree(autcpu12_mtd);
+ out:
return err;
}
@@ -204,20 +222,19 @@ module_init(autcpu12_init);
/*
* Clean up routine
*/
-#ifdef MODULE
-static void __exit autcpu12_cleanup (void)
+static void __exit autcpu12_cleanup(void)
{
/* Release resources, unregister device */
- nand_release (autcpu12_mtd);
+ nand_release(autcpu12_mtd);
/* unmap physical adress */
- iounmap((void *)autcpu12_fio_base);
+ iounmap(autcpu12_fio_base);
/* Free the MTD device structure */
- kfree (autcpu12_mtd);
+ kfree(autcpu12_mtd);
}
+
module_exit(autcpu12_cleanup);
-#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
new file mode 100644
index 000000000000..e0a1d386e581
--- /dev/null
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -0,0 +1,353 @@
+/*
+ * drivers/mtd/nand/cs553x_nand.c
+ *
+ * (C) 2005, 2006 Red Hat Inc.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ * Tom Sylla <tom.sylla@amd.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.
+ *
+ * Overview:
+ * This is a device driver for the NAND flash controller found on
+ * the AMD CS5535/CS5536 companion chipsets for the Geode processor.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/msr.h>
+#include <asm/io.h>
+
+#define NR_CS553X_CONTROLLERS 4
+
+#define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilitiies */
+#define CAP_CS5535 0x2df000ULL
+#define CAP_CS5536 0x5df500ULL
+
+/* NAND Timing MSRs */
+#define MSR_NANDF_DATA 0x5140001b /* NAND Flash Data Timing MSR */
+#define MSR_NANDF_CTL 0x5140001c /* NAND Flash Control Timing */
+#define MSR_NANDF_RSVD 0x5140001d /* Reserved */
+
+/* NAND BAR MSRs */
+#define MSR_DIVIL_LBAR_FLSH0 0x51400010 /* Flash Chip Select 0 */
+#define MSR_DIVIL_LBAR_FLSH1 0x51400011 /* Flash Chip Select 1 */
+#define MSR_DIVIL_LBAR_FLSH2 0x51400012 /* Flash Chip Select 2 */
+#define MSR_DIVIL_LBAR_FLSH3 0x51400013 /* Flash Chip Select 3 */
+ /* Each made up of... */
+#define FLSH_LBAR_EN (1ULL<<32)
+#define FLSH_NOR_NAND (1ULL<<33) /* 1 for NAND */
+#define FLSH_MEM_IO (1ULL<<34) /* 1 for MMIO */
+ /* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
+ /* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
+
+/* Pin function selection MSR (IDE vs. flash on the IDE pins) */
+#define MSR_DIVIL_BALL_OPTS 0x51400015
+#define PIN_OPT_IDE (1<<0) /* 0 for flash, 1 for IDE */
+
+/* Registers within the NAND flash controller BAR -- memory mapped */
+#define MM_NAND_DATA 0x00 /* 0 to 0x7ff, in fact */
+#define MM_NAND_CTL 0x800 /* Any even address 0x800-0x80e */
+#define MM_NAND_IO 0x801 /* Any odd address 0x801-0x80f */
+#define MM_NAND_STS 0x810
+#define MM_NAND_ECC_LSB 0x811
+#define MM_NAND_ECC_MSB 0x812
+#define MM_NAND_ECC_COL 0x813
+#define MM_NAND_LAC 0x814
+#define MM_NAND_ECC_CTL 0x815
+
+/* Registers within the NAND flash controller BAR -- I/O mapped */
+#define IO_NAND_DATA 0x00 /* 0 to 3, in fact */
+#define IO_NAND_CTL 0x04
+#define IO_NAND_IO 0x05
+#define IO_NAND_STS 0x06
+#define IO_NAND_ECC_CTL 0x08
+#define IO_NAND_ECC_LSB 0x09
+#define IO_NAND_ECC_MSB 0x0a
+#define IO_NAND_ECC_COL 0x0b
+#define IO_NAND_LAC 0x0c
+
+#define CS_NAND_CTL_DIST_EN (1<<4) /* Enable NAND Distract interrupt */
+#define CS_NAND_CTL_RDY_INT_MASK (1<<3) /* Enable RDY/BUSY# interrupt */
+#define CS_NAND_CTL_ALE (1<<2)
+#define CS_NAND_CTL_CLE (1<<1)
+#define CS_NAND_CTL_CE (1<<0) /* Keep low; 1 to reset */
+
+#define CS_NAND_STS_FLASH_RDY (1<<3)
+#define CS_NAND_CTLR_BUSY (1<<2)
+#define CS_NAND_CMD_COMP (1<<1)
+#define CS_NAND_DIST_ST (1<<0)
+
+#define CS_NAND_ECC_PARITY (1<<2)
+#define CS_NAND_ECC_CLRECC (1<<1)
+#define CS_NAND_ECC_ENECC (1<<0)
+
+static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ while (unlikely(len > 0x800)) {
+ memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+ buf += 0x800;
+ len -= 0x800;
+ }
+ memcpy_fromio(buf, this->IO_ADDR_R, len);
+}
+
+static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+
+ while (unlikely(len > 0x800)) {
+ memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+ buf += 0x800;
+ len -= 0x800;
+ }
+ memcpy_toio(this->IO_ADDR_R, buf, len);
+}
+
+static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *this = mtd->priv;
+ return readb(this->IO_ADDR_R);
+}
+
+static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
+{
+ struct nand_chip *this = mtd->priv;
+ int i = 100000;
+
+ while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+ udelay(1);
+ i--;
+ }
+ writeb(byte, this->IO_ADDR_W + 0x801);
+}
+
+static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ void __iomem *mmio_base = this->IO_ADDR_R;
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
+ writeb(ctl, mmio_base + MM_NAND_CTL);
+ }
+ if (cmd != NAND_CMD_NONE)
+ cs553x_write_byte(mtd, cmd);
+}
+
+static int cs553x_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *this = mtd->priv;
+ void __iomem *mmio_base = this->IO_ADDR_R;
+ unsigned char foo = readb(mmio_base + MM_NAND_STS);
+
+ return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
+}
+
+static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct nand_chip *this = mtd->priv;
+ void __iomem *mmio_base = this->IO_ADDR_R;
+
+ writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
+}
+
+static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+ uint32_t ecc;
+ struct nand_chip *this = mtd->priv;
+ void __iomem *mmio_base = this->IO_ADDR_R;
+
+ ecc = readl(mmio_base + MM_NAND_STS);
+
+ ecc_code[1] = ecc >> 8;
+ ecc_code[0] = ecc >> 16;
+ ecc_code[2] = ecc >> 24;
+ return 0;
+}
+
+static struct mtd_info *cs553x_mtd[4];
+
+static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
+{
+ int err = 0;
+ struct nand_chip *this;
+ struct mtd_info *new_mtd;
+
+ printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
+
+ if (!mmio) {
+ printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
+ return -ENXIO;
+ }
+
+ /* Allocate memory for MTD device structure and private data */
+ new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+ if (!new_mtd) {
+ printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *)(&new_mtd[1]);
+
+ /* Initialize structures */
+ memset(new_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ new_mtd->priv = this;
+ new_mtd->owner = THIS_MODULE;
+
+ /* map physical address */
+ this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
+ if (!this->IO_ADDR_R) {
+ printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
+ err = -EIO;
+ goto out_mtd;
+ }
+
+ this->cmd_ctrl = cs553x_hwcontrol;
+ this->dev_ready = cs553x_device_ready;
+ this->read_byte = cs553x_read_byte;
+ this->read_buf = cs553x_read_buf;
+ this->write_buf = cs553x_write_buf;
+
+ this->chip_delay = 0;
+
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 256;
+ this->ecc.bytes = 3;
+ this->ecc.hwctl = cs_enable_hwecc;
+ this->ecc.calculate = cs_calculate_ecc;
+ this->ecc.correct = nand_correct_data;
+
+ /* Enable the following for a flash based bad block table */
+ this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
+
+ /* Scan to find existance of the device */
+ if (nand_scan(new_mtd, 1)) {
+ err = -ENXIO;
+ goto out_ior;
+ }
+
+ cs553x_mtd[cs] = new_mtd;
+ goto out;
+
+out_ior:
+ iounmap((void *)this->IO_ADDR_R);
+out_mtd:
+ kfree(new_mtd);
+out:
+ return err;
+}
+
+static int is_geode(void)
+{
+ /* These are the CPUs which will have a CS553[56] companion chip */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 == 5 &&
+ boot_cpu_data.x86_model == 10)
+ return 1; /* Geode LX */
+
+ if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
+ boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
+ boot_cpu_data.x86 == 5 &&
+ boot_cpu_data.x86_model == 5)
+ return 1; /* Geode GX (née GX2) */
+
+ return 0;
+}
+
+static int __init cs553x_init(void)
+{
+ int err = -ENXIO;
+ int i;
+ uint64_t val;
+
+ /* If the CPU isn't a Geode GX or LX, abort */
+ if (!is_geode())
+ return -ENXIO;
+
+ /* If it doesn't have the CS553[56], abort */
+ rdmsrl(MSR_DIVIL_GLD_CAP, val);
+ val &= ~0xFFULL;
+ if (val != CAP_CS5535 && val != CAP_CS5536)
+ return -ENXIO;
+
+ /* If it doesn't have the NAND controller enabled, abort */
+ rdmsrl(MSR_DIVIL_BALL_OPTS, val);
+ if (val & 1) {
+ printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
+ return -ENXIO;
+ }
+
+ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+ rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
+
+ if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
+ err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
+ }
+
+ /* Register all devices together here. This means we can easily hack it to
+ do mtdconcat etc. if we want to. */
+ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+ if (cs553x_mtd[i]) {
+ add_mtd_device(cs553x_mtd[i]);
+
+ /* If any devices registered, return success. Else the last error. */
+ err = 0;
+ }
+ }
+
+ return err;
+}
+
+module_init(cs553x_init);
+
+static void __exit cs553x_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+ struct mtd_info *mtd = cs553x_mtd[i];
+ struct nand_chip *this;
+ void __iomem *mmio_base;
+
+ if (!mtd)
+ break;
+
+ this = cs553x_mtd[i]->priv;
+ mmio_base = this->IO_ADDR_R;
+
+ /* Release resources, unregister device */
+ nand_release(cs553x_mtd[i]);
+ cs553x_mtd[i] = NULL;
+
+ /* unmap physical adress */
+ iounmap(mmio_base);
+
+ /* Free the MTD device structure */
+ kfree(mtd);
+ }
+}
+
+module_exit(cs553x_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index ec5e45e4e4ef..6107f532855b 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -58,10 +58,10 @@ static unsigned long __initdata doc_locations[] = {
0xe4000000,
#elif defined(CONFIG_MOMENCO_OCELOT)
0x2f000000,
- 0xff000000,
+ 0xff000000,
#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
- 0xff000000,
-##else
+ 0xff000000,
+#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };
@@ -73,7 +73,7 @@ struct doc_priv {
unsigned long physadr;
u_char ChipID;
u_char CDSNControl;
- int chips_per_floor; /* The number of chips detected on each floor */
+ int chips_per_floor; /* The number of chips detected on each floor */
int curfloor;
int curchip;
int mh0_page;
@@ -84,6 +84,7 @@ struct doc_priv {
/* This is the syndrome computed by the HW ecc generator upon reading an empty
page, one with all 0xff for data and stored ecc code. */
static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
+
/* This is the ecc value computed by the HW ecc generator upon writing an empty
page, one with all 0xff for data. */
static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
@@ -94,28 +95,29 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int bitmask);
static void doc200x_select_chip(struct mtd_info *mtd, int chip);
-static int debug=0;
+static int debug = 0;
module_param(debug, int, 0);
-static int try_dword=1;
+static int try_dword = 1;
module_param(try_dword, int, 0);
-static int no_ecc_failures=0;
+static int no_ecc_failures = 0;
module_param(no_ecc_failures, int, 0);
-static int no_autopart=0;
+static int no_autopart = 0;
module_param(no_autopart, int, 0);
-static int show_firmware_partition=0;
+static int show_firmware_partition = 0;
module_param(show_firmware_partition, int, 0);
#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
-static int inftl_bbt_write=1;
+static int inftl_bbt_write = 1;
#else
-static int inftl_bbt_write=0;
+static int inftl_bbt_write = 0;
#endif
module_param(inftl_bbt_write, int, 0);
@@ -123,7 +125,6 @@ static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDR
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
-
/* Sector size for HW ECC */
#define SECTOR_SIZE 512
/* The sector bytes are packed into NB_DATA 10 bit words */
@@ -147,7 +148,7 @@ static struct rs_control *rs_decoder;
* some comments, improved a minor bit and converted it to make use
* of the generic Reed-Solomon libary. tglx
*/
-static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
+static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
{
int i, j, nerr, errpos[8];
uint8_t parity;
@@ -168,18 +169,18 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
* s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
* where x = alpha^(FCR + i)
*/
- for(j = 1; j < NROOTS; j++) {
- if(ds[j] == 0)
+ for (j = 1; j < NROOTS; j++) {
+ if (ds[j] == 0)
continue;
tmp = rs->index_of[ds[j]];
- for(i = 0; i < NROOTS; i++)
+ for (i = 0; i < NROOTS; i++)
s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
}
/* Calc s[i] = s[i] / alpha^(v + i) */
for (i = 0; i < NROOTS; i++) {
if (syn[i])
- syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
+ syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
}
/* Call the decoder library */
nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
@@ -193,7 +194,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
* but they are given by the design of the de/encoder circuit
* in the DoC ASIC's.
*/
- for(i = 0;i < nerr; i++) {
+ for (i = 0; i < nerr; i++) {
int index, bitpos, pos = 1015 - errpos[i];
uint8_t val;
if (pos >= NB_DATA && pos < 1019)
@@ -205,8 +206,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
can be modified since pos is even */
index = (pos >> 3) ^ 1;
bitpos = pos & 7;
- if ((index >= 0 && index < SECTOR_SIZE) ||
- index == (SECTOR_SIZE + 1)) {
+ if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
val = (uint8_t) (errval[i] >> (2 + bitpos));
parity ^= val;
if (index < SECTOR_SIZE)
@@ -216,9 +216,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
bitpos = (bitpos + 10) & 7;
if (bitpos == 0)
bitpos = 8;
- if ((index >= 0 && index < SECTOR_SIZE) ||
- index == (SECTOR_SIZE + 1)) {
- val = (uint8_t)(errval[i] << (8 - bitpos));
+ if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
+ val = (uint8_t) (errval[i] << (8 - bitpos));
parity ^= val;
if (index < SECTOR_SIZE)
data[index] ^= val;
@@ -250,10 +249,11 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
static int _DoC_WaitReady(struct doc_priv *doc)
{
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
unsigned long timeo = jiffies + (HZ * 10);
- if(debug) printk("_DoC_WaitReady...\n");
+ if (debug)
+ printk("_DoC_WaitReady...\n");
/* Out-of-line routine to wait for chip response */
if (DoC_is_MillenniumPlus(doc)) {
while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
@@ -280,7 +280,7 @@ static int _DoC_WaitReady(struct doc_priv *doc)
static inline int DoC_WaitReady(struct doc_priv *doc)
{
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int ret = 0;
if (DoC_is_MillenniumPlus(doc)) {
@@ -298,7 +298,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
DoC_Delay(doc, 2);
}
- if(debug) printk("DoC_WaitReady OK\n");
+ if (debug)
+ printk("DoC_WaitReady OK\n");
return ret;
}
@@ -306,9 +307,10 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
- if(debug)printk("write_byte %02x\n", datum);
+ if (debug)
+ printk("write_byte %02x\n", datum);
WriteDOC(datum, docptr, CDSNSlowIO);
WriteDOC(datum, docptr, 2k_CDSN_IO);
}
@@ -317,77 +319,78 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
u_char ret;
ReadDOC(docptr, CDSNSlowIO);
DoC_Delay(doc, 2);
ret = ReadDOC(docptr, 2k_CDSN_IO);
- if (debug) printk("read_byte returns %02x\n", ret);
+ if (debug)
+ printk("read_byte returns %02x\n", ret);
return ret;
}
-static void doc2000_writebuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- if (debug)printk("writebuf of %d bytes: ", len);
- for (i=0; i < len; i++) {
+ if (debug)
+ printk("writebuf of %d bytes: ", len);
+ for (i = 0; i < len; i++) {
WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
if (debug && i < 16)
printk("%02x ", buf[i]);
}
- if (debug) printk("\n");
+ if (debug)
+ printk("\n");
}
-static void doc2000_readbuf(struct mtd_info *mtd,
- u_char *buf, int len)
+static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
- int i;
+ void __iomem *docptr = doc->virtadr;
+ int i;
- if (debug)printk("readbuf of %d bytes: ", len);
+ if (debug)
+ printk("readbuf of %d bytes: ", len);
- for (i=0; i < len; i++) {
+ for (i = 0; i < len; i++) {
buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
}
}
-static void doc2000_readbuf_dword(struct mtd_info *mtd,
- u_char *buf, int len)
+static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
- int i;
+ void __iomem *docptr = doc->virtadr;
+ int i;
- if (debug) printk("readbuf_dword of %d bytes: ", len);
+ if (debug)
+ printk("readbuf_dword of %d bytes: ", len);
- if (unlikely((((unsigned long)buf)|len) & 3)) {
- for (i=0; i < len; i++) {
- *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
+ if (unlikely((((unsigned long)buf) | len) & 3)) {
+ for (i = 0; i < len; i++) {
+ *(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
}
} else {
- for (i=0; i < len; i+=4) {
- *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
+ for (i = 0; i < len; i += 4) {
+ *(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
}
}
}
-static int doc2000_verifybuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- for (i=0; i < len; i++)
+ for (i = 0; i < len; i++)
if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))
return -EFAULT;
return 0;
@@ -400,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
uint16_t ret;
doc200x_select_chip(mtd, nr);
- doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
- this->write_byte(mtd, NAND_CMD_READID);
- doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
- doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
- this->write_byte(mtd, 0);
- doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+ doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* We cant' use dev_ready here, but at least we wait for the
* command to complete
@@ -423,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
} ident;
void __iomem *docptr = doc->virtadr;
- doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
- doc2000_write_byte(mtd, NAND_CMD_READID);
- doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
- doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
- doc2000_write_byte(mtd, 0);
- doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+ doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
udelay(50);
@@ -464,7 +464,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
}
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
{
struct doc_priv *doc = this->priv;
@@ -482,7 +482,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
WriteDOC(datum, docptr, CDSNSlowIO);
WriteDOC(datum, docptr, Mil_CDSN_IO);
@@ -493,7 +493,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
//ReadDOC(docptr, CDSNSlowIO);
/* 11.4.5 -- delay twice to allow extended length cycle */
@@ -503,50 +503,47 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
return ReadDOC(docptr, LastDataRead);
}
-static void doc2001_writebuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- for (i=0; i < len; i++)
+ for (i = 0; i < len; i++)
WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
/* Terminate write pipeline */
WriteDOC(0x00, docptr, WritePipeTerm);
}
-static void doc2001_readbuf(struct mtd_info *mtd,
- u_char *buf, int len)
+static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
/* Start read pipeline */
ReadDOC(docptr, ReadPipeInit);
- for (i=0; i < len-1; i++)
+ for (i = 0; i < len - 1; i++)
buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
/* Terminate read pipeline */
buf[i] = ReadDOC(docptr, LastDataRead);
}
-static int doc2001_verifybuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
/* Start read pipeline */
ReadDOC(docptr, ReadPipeInit);
- for (i=0; i < len-1; i++)
+ for (i = 0; i < len - 1; i++)
if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
ReadDOC(docptr, LastDataRead);
return i;
@@ -560,87 +557,90 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
u_char ret;
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ret = ReadDOC(docptr, Mplus_LastDataRead);
- if (debug) printk("read_byte returns %02x\n", ret);
+ ReadDOC(docptr, Mplus_ReadPipeInit);
+ ReadDOC(docptr, Mplus_ReadPipeInit);
+ ret = ReadDOC(docptr, Mplus_LastDataRead);
+ if (debug)
+ printk("read_byte returns %02x\n", ret);
return ret;
}
-static void doc2001plus_writebuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- if (debug)printk("writebuf of %d bytes: ", len);
- for (i=0; i < len; i++) {
+ if (debug)
+ printk("writebuf of %d bytes: ", len);
+ for (i = 0; i < len; i++) {
WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
if (debug && i < 16)
printk("%02x ", buf[i]);
}
- if (debug) printk("\n");
+ if (debug)
+ printk("\n");
}
-static void doc2001plus_readbuf(struct mtd_info *mtd,
- u_char *buf, int len)
+static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- if (debug)printk("readbuf of %d bytes: ", len);
+ if (debug)
+ printk("readbuf of %d bytes: ", len);
/* Start read pipeline */
ReadDOC(docptr, Mplus_ReadPipeInit);
ReadDOC(docptr, Mplus_ReadPipeInit);
- for (i=0; i < len-2; i++) {
+ for (i = 0; i < len - 2; i++) {
buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
if (debug && i < 16)
printk("%02x ", buf[i]);
}
/* Terminate read pipeline */
- buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
+ buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
if (debug && i < 16)
- printk("%02x ", buf[len-2]);
- buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
+ printk("%02x ", buf[len - 2]);
+ buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
if (debug && i < 16)
- printk("%02x ", buf[len-1]);
- if (debug) printk("\n");
+ printk("%02x ", buf[len - 1]);
+ if (debug)
+ printk("\n");
}
-static int doc2001plus_verifybuf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
- if (debug)printk("verifybuf of %d bytes: ", len);
+ if (debug)
+ printk("verifybuf of %d bytes: ", len);
/* Start read pipeline */
ReadDOC(docptr, Mplus_ReadPipeInit);
ReadDOC(docptr, Mplus_ReadPipeInit);
- for (i=0; i < len-2; i++)
+ for (i = 0; i < len - 2; i++)
if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
ReadDOC(docptr, Mplus_LastDataRead);
ReadDOC(docptr, Mplus_LastDataRead);
return i;
}
- if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead))
- return len-2;
- if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead))
- return len-1;
+ if (buf[len - 2] != ReadDOC(docptr, Mplus_LastDataRead))
+ return len - 2;
+ if (buf[len - 1] != ReadDOC(docptr, Mplus_LastDataRead))
+ return len - 1;
return 0;
}
@@ -648,10 +648,11 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int floor = 0;
- if(debug)printk("select chip (%d)\n", chip);
+ if (debug)
+ printk("select chip (%d)\n", chip);
if (chip == -1) {
/* Disable flash internally */
@@ -660,7 +661,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
}
floor = chip / doc->chips_per_floor;
- chip -= (floor * doc->chips_per_floor);
+ chip -= (floor * doc->chips_per_floor);
/* Assert ChipEnable and deassert WriteProtect */
WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
@@ -674,72 +675,61 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int floor = 0;
- if(debug)printk("select chip (%d)\n", chip);
+ if (debug)
+ printk("select chip (%d)\n", chip);
if (chip == -1)
return;
floor = chip / doc->chips_per_floor;
- chip -= (floor * doc->chips_per_floor);
+ chip -= (floor * doc->chips_per_floor);
/* 11.4.4 -- deassert CE before changing chip */
- doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
+ doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect);
- doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
+ doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
doc->curchip = chip;
doc->curfloor = floor;
}
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
+#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
+
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
- switch(cmd) {
- case NAND_CTL_SETNCE:
- doc->CDSNControl |= CDSN_CTRL_CE;
- break;
- case NAND_CTL_CLRNCE:
- doc->CDSNControl &= ~CDSN_CTRL_CE;
- break;
- case NAND_CTL_SETCLE:
- doc->CDSNControl |= CDSN_CTRL_CLE;
- break;
- case NAND_CTL_CLRCLE:
- doc->CDSNControl &= ~CDSN_CTRL_CLE;
- break;
- case NAND_CTL_SETALE:
- doc->CDSNControl |= CDSN_CTRL_ALE;
- break;
- case NAND_CTL_CLRALE:
- doc->CDSNControl &= ~CDSN_CTRL_ALE;
- break;
- case NAND_CTL_SETWP:
- doc->CDSNControl |= CDSN_CTRL_WP;
- break;
- case NAND_CTL_CLRWP:
- doc->CDSNControl &= ~CDSN_CTRL_WP;
- break;
+ if (ctrl & NAND_CTRL_CHANGE) {
+ doc->CDSNControl &= ~CDSN_CTRL_MSK;
+ doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
+ if (debug)
+ printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
+ WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+ /* 11.4.3 -- 4 NOPs after CSDNControl write */
+ DoC_Delay(doc, 4);
+ }
+ if (cmd != NAND_CMD_NONE) {
+ if (DoC_is_2000(doc))
+ doc2000_write_byte(mtd, cmd);
+ else
+ doc2001_write_byte(mtd, cmd);
}
- if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
- WriteDOC(doc->CDSNControl, docptr, CDSNControl);
- /* 11.4.3 -- 4 NOPs after CSDNControl write */
- DoC_Delay(doc, 4);
}
-static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
/*
* Must terminate write pipeline before sending any commands
@@ -756,9 +746,9 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
if (command == NAND_CMD_SEQIN) {
int readcmd;
- if (column >= mtd->oobblock) {
+ if (column >= mtd->writesize) {
/* OOB area */
- column -= mtd->oobblock;
+ column -= mtd->writesize;
readcmd = NAND_CMD_READOOB;
} else if (column < 256) {
/* First 256 bytes --> READ0 */
@@ -782,25 +772,26 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
WriteDOC(column, docptr, Mplus_FlashAddress);
}
if (page_addr != -1) {
- WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress);
- WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
+ WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress);
+ WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
/* One more address cycle for higher density devices */
if (this->chipsize & 0x0c000000) {
- WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
+ WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
printk("high density\n");
}
}
WriteDOC(0, docptr, Mplus_WritePipeTerm);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
/* deassert ALE */
- if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID)
+ if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+ command == NAND_CMD_READOOB || command == NAND_CMD_READID)
WriteDOC(0, docptr, Mplus_FlashControl);
}
/*
* program and erase have their own busy handlers
* status and sequential in needs no delay
- */
+ */
switch (command) {
case NAND_CMD_PAGEPROG:
@@ -817,55 +808,57 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
- while ( !(this->read_byte(mtd) & 0x40));
+ while (!(this->read_byte(mtd) & 0x40)) ;
return;
- /* This applies to read commands */
+ /* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay
- */
+ */
if (!this->dev_ready) {
- udelay (this->chip_delay);
+ udelay(this->chip_delay);
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
- ndelay (100);
+ ndelay(100);
/* wait until command is processed */
- while (!this->dev_ready(mtd));
+ while (!this->dev_ready(mtd)) ;
}
static int doc200x_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
if (DoC_is_MillenniumPlus(doc)) {
/* 11.4.2 -- must NOP four times before checking FR/B# */
DoC_Delay(doc, 4);
if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
- if(debug)
+ if (debug)
printk("not ready\n");
return 0;
}
- if (debug)printk("was ready\n");
+ if (debug)
+ printk("was ready\n");
return 1;
} else {
/* 11.4.2 -- must NOP four times before checking FR/B# */
DoC_Delay(doc, 4);
if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
- if(debug)
+ if (debug)
printk("not ready\n");
return 0;
}
/* 11.4.2 -- Must NOP twice if it's ready */
DoC_Delay(doc, 2);
- if (debug)printk("was ready\n");
+ if (debug)
+ printk("was ready\n");
return 1;
}
}
@@ -881,10 +874,10 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
- switch(mode) {
+ switch (mode) {
case NAND_ECC_READ:
WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
WriteDOC(DOC_ECC_EN, docptr, ECCConf);
@@ -900,10 +893,10 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
- switch(mode) {
+ switch (mode) {
case NAND_ECC_READ:
WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
@@ -916,12 +909,11 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
}
/* This code is only called on write */
-static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- unsigned char *ecc_code)
+static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
int i;
int emptymatch = 1;
@@ -961,7 +953,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
often. It could be optimized away by examining the data in
the writebuf routine, and remembering the result. */
for (i = 0; i < 512; i++) {
- if (dat[i] == 0xff) continue;
+ if (dat[i] == 0xff)
+ continue;
emptymatch = 0;
break;
}
@@ -969,17 +962,20 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
/* If emptymatch still =1, we do have an all-0xff data buffer.
Return all-0xff ecc value instead of the computed one, so
it'll look just like a freshly-erased page. */
- if (emptymatch) memset(ecc_code, 0xff, 6);
+ if (emptymatch)
+ memset(ecc_code, 0xff, 6);
#endif
return 0;
}
-static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
+ void __iomem *docptr = doc->virtadr;
+ uint8_t calc_ecc[6];
volatile u_char dummy;
int emptymatch = 1;
@@ -1012,18 +1008,20 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
all-0xff data and stored ecc block. Check the stored ecc. */
if (emptymatch) {
for (i = 0; i < 6; i++) {
- if (read_ecc[i] == 0xff) continue;
+ if (read_ecc[i] == 0xff)
+ continue;
emptymatch = 0;
break;
}
}
/* If emptymatch still =1, check the data block. */
if (emptymatch) {
- /* Note: this somewhat expensive test should not be triggered
- often. It could be optimized away by examining the data in
- the readbuf routine, and remembering the result. */
+ /* Note: this somewhat expensive test should not be triggered
+ often. It could be optimized away by examining the data in
+ the readbuf routine, and remembering the result. */
for (i = 0; i < 512; i++) {
- if (dat[i] == 0xff) continue;
+ if (dat[i] == 0xff)
+ continue;
emptymatch = 0;
break;
}
@@ -1032,7 +1030,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
erased block, in which case the ECC will not come out right.
We'll suppress the error and tell the caller everything's
OK. Because it is. */
- if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc);
+ if (!emptymatch)
+ ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
}
@@ -1059,11 +1058,10 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
* safer. The only problem with it is that any code that parses oobfree must
* be able to handle out-of-order segments.
*/
-static struct nand_oobinfo doc200x_oobinfo = {
- .useecc = MTD_NANDECC_AUTOPLACE,
- .eccbytes = 6,
- .eccpos = {0, 1, 2, 3, 4, 5},
- .oobfree = { {8, 8}, {6, 2} }
+static struct nand_ecclayout doc200x_oobinfo = {
+ .eccbytes = 6,
+ .eccpos = {0, 1, 2, 3, 4, 5},
+ .oobfree = {{8, 8}, {6, 2}}
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1072,8 +1070,7 @@ static struct nand_oobinfo doc200x_oobinfo = {
either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media
header. The page #s of the found media headers are placed in mh0_page and
mh1_page in the DOC private structure. */
-static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
- const char *id, int findmirror)
+static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@@ -1082,17 +1079,19 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
size_t retlen;
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
- ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
- if (retlen != mtd->oobblock) continue;
+ ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
+ if (retlen != mtd->writesize)
+ continue;
if (ret) {
- printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n",
- offs);
+ printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
}
- if (memcmp(buf, id, 6)) continue;
+ if (memcmp(buf, id, 6))
+ continue;
printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
if (doc->mh0_page == -1) {
doc->mh0_page = offs >> this->page_shift;
- if (!findmirror) return 1;
+ if (!findmirror)
+ return 1;
continue;
}
doc->mh1_page = offs >> this->page_shift;
@@ -1105,8 +1104,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
/* Only one mediaheader was found. We want buf to contain a
mediaheader on return, so we'll have to re-read the one we found. */
offs = doc->mh0_page << this->page_shift;
- ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
- if (retlen != mtd->oobblock) {
+ ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
+ if (retlen != mtd->writesize) {
/* Insanity. Give up. */
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
return 0;
@@ -1114,8 +1113,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
return 1;
}
-static inline int __init nftl_partscan(struct mtd_info *mtd,
- struct mtd_partition *parts)
+static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@@ -1127,13 +1125,14 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
unsigned blocks, maxblocks;
int offs, numheaders;
- buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+ buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0;
}
- if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
- mh = (struct NFTLMediaHeader *) buf;
+ if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
+ goto out;
+ mh = (struct NFTLMediaHeader *)buf;
mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
@@ -1155,8 +1154,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
/* Auto-determine UnitSizeFactor. The constraints are:
- There can be at most 32768 virtual blocks.
- There can be at most (virtual block size - page size)
- virtual blocks (because MediaHeader+BBT must fit in 1).
- */
+ virtual blocks (because MediaHeader+BBT must fit in 1).
+ */
mh->UnitSizeFactor = 0xff;
while (blocks > maxblocks) {
blocks >>= 1;
@@ -1211,14 +1210,13 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
}
ret = numparts;
-out:
+ out:
kfree(buf);
return ret;
}
/* This is a stripped-down copy of the code in inftlmount.c */
-static inline int __init inftl_partscan(struct mtd_info *mtd,
- struct mtd_partition *parts)
+static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
@@ -1235,15 +1233,16 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
if (inftl_bbt_write)
end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
- buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+ buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0;
}
- if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out;
+ if (!find_media_headers(mtd, buf, "BNAND", 0))
+ goto out;
doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
- mh = (struct INFTLMediaHeader *) buf;
+ mh = (struct INFTLMediaHeader *)buf;
mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
@@ -1319,8 +1318,10 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
parts[numparts].offset = ip->firstUnit << vshift;
parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
numparts++;
- if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit;
- if (ip->flags & INFTL_LAST) break;
+ if (ip->lastUnit > lastvunit)
+ lastvunit = ip->lastUnit;
+ if (ip->flags & INFTL_LAST)
+ break;
}
lastvunit++;
if ((lastvunit << vshift) < end) {
@@ -1330,7 +1331,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
numparts++;
}
ret = numparts;
-out:
+ out:
kfree(buf);
return ret;
}
@@ -1342,11 +1343,12 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
struct doc_priv *doc = this->priv;
struct mtd_partition parts[2];
- memset((char *) parts, 0, sizeof(parts));
+ memset((char *)parts, 0, sizeof(parts));
/* On NFTL, we have to find the media headers before we can read the
BBTs, since they're stored in the media header eraseblocks. */
numparts = nftl_partscan(mtd, parts);
- if (!numparts) return -EIO;
+ if (!numparts)
+ return -EIO;
this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
NAND_BBT_VERSION;
@@ -1393,8 +1395,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_td->pages[0] = 2;
this->bbt_md = NULL;
} else {
- this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
- NAND_BBT_VERSION;
+ this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
if (inftl_bbt_write)
this->bbt_td->options |= NAND_BBT_WRITE;
this->bbt_td->offs = 8;
@@ -1404,8 +1405,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_td->reserved_block_code = 0x01;
this->bbt_td->pattern = "MSYS_BBT";
- this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
- NAND_BBT_VERSION;
+ this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
if (inftl_bbt_write)
this->bbt_md->options |= NAND_BBT_WRITE;
this->bbt_md->offs = 8;
@@ -1420,12 +1420,13 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
At least as nand_bbt.c is currently written. */
if ((ret = nand_scan_bbt(mtd, NULL)))
return ret;
- memset((char *) parts, 0, sizeof(parts));
+ memset((char *)parts, 0, sizeof(parts));
numparts = inftl_partscan(mtd, parts);
/* At least for now, require the INFTL Media Header. We could probably
do without it for non-INFTL use, since all it gives us is
autopartitioning, but I want to give it more thought. */
- if (!numparts) return -EIO;
+ if (!numparts)
+ return -EIO;
add_mtd_device(mtd);
#ifdef CONFIG_MTD_PARTITIONS
if (!no_autopart)
@@ -1439,7 +1440,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- this->write_byte = doc2000_write_byte;
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
this->read_buf = doc2000_readbuf;
@@ -1457,7 +1457,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- this->write_byte = doc2001_write_byte;
this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf;
this->read_buf = doc2001_readbuf;
@@ -1489,16 +1488,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- this->write_byte = NULL;
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
this->read_buf = doc2001plus_readbuf;
this->verify_buf = doc2001plus_verifybuf;
this->scan_bbt = inftl_scan_bbt;
- this->hwcontrol = NULL;
+ this->cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
this->cmdfunc = doc2001plus_command;
- this->enable_hwecc = doc2001plus_enable_hwecc;
+ this->ecc.hwctl = doc2001plus_enable_hwecc;
doc->chips_per_floor = 1;
mtd->name = "DiskOnChip Millennium Plus";
@@ -1535,20 +1533,16 @@ static int __init doc_probe(unsigned long physadr)
save_control = ReadDOC(virtadr, DOCControl);
/* Reset the DiskOnChip ASIC */
- WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
- virtadr, DOCControl);
- WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
- virtadr, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
/* Enable the DiskOnChip ASIC */
- WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
- virtadr, DOCControl);
- WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
- virtadr, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
ChipID = ReadDOC(virtadr, ChipID);
- switch(ChipID) {
+ switch (ChipID) {
case DOC_ChipID_Doc2k:
reg = DoC_2k_ECCStatus;
break;
@@ -1564,15 +1558,13 @@ static int __init doc_probe(unsigned long physadr)
ReadDOC(virtadr, Mplus_Power);
/* Reset the Millennium Plus ASIC */
- tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
- DOC_MODE_BDECT;
+ tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
WriteDOC(tmp, virtadr, Mplus_DOCControl);
WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
mdelay(1);
/* Enable the Millennium Plus ASIC */
- tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
- DOC_MODE_BDECT;
+ tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
WriteDOC(tmp, virtadr, Mplus_DOCControl);
WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
mdelay(1);
@@ -1596,7 +1588,7 @@ static int __init doc_probe(unsigned long physadr)
goto notfound;
}
/* Check the TOGGLE bit in the ECC register */
- tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+ tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
if ((tmp == tmpb) || (tmp != tmpc)) {
@@ -1626,11 +1618,11 @@ static int __init doc_probe(unsigned long physadr)
if (ChipID == DOC_ChipID_DocMilPlus16) {
WriteDOC(~newval, virtadr, Mplus_AliasResolution);
oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
- WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
+ WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
} else {
WriteDOC(~newval, virtadr, AliasResolution);
oldval = ReadDOC(doc->virtadr, AliasResolution);
- WriteDOC(newval, virtadr, AliasResolution); // restore it
+ WriteDOC(newval, virtadr, AliasResolution); // restore it
}
newval = ~newval;
if (oldval == newval) {
@@ -1642,10 +1634,8 @@ static int __init doc_probe(unsigned long physadr)
printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
len = sizeof(struct mtd_info) +
- sizeof(struct nand_chip) +
- sizeof(struct doc_priv) +
- (2 * sizeof(struct nand_bbt_descr));
- mtd = kmalloc(len, GFP_KERNEL);
+ sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
+ mtd = kmalloc(len, GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
ret = -ENOMEM;
@@ -1663,17 +1653,19 @@ static int __init doc_probe(unsigned long physadr)
nand->priv = doc;
nand->select_chip = doc200x_select_chip;
- nand->hwcontrol = doc200x_hwcontrol;
+ nand->cmd_ctrl = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready;
nand->waitfunc = doc200x_wait;
nand->block_bad = doc200x_block_bad;
- nand->enable_hwecc = doc200x_enable_hwecc;
- nand->calculate_ecc = doc200x_calculate_ecc;
- nand->correct_data = doc200x_correct_data;
+ nand->ecc.hwctl = doc200x_enable_hwecc;
+ nand->ecc.calculate = doc200x_calculate_ecc;
+ nand->ecc.correct = doc200x_correct_data;
- nand->autooob = &doc200x_oobinfo;
- nand->eccmode = NAND_ECC_HW6_512;
- nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
+ nand->ecc.layout = &doc200x_oobinfo;
+ nand->ecc.mode = NAND_ECC_HW_SYNDROME;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 6;
+ nand->options = NAND_USE_FLASH_BBT;
doc->physadr = physadr;
doc->virtadr = virtadr;
@@ -1707,18 +1699,18 @@ static int __init doc_probe(unsigned long physadr)
doclist = mtd;
return 0;
-notfound:
+ notfound:
/* Put back the contents of the DOCControl register, in case it's not
actually a DiskOnChip. */
WriteDOC(save_control, virtadr, DOCControl);
-fail:
+ fail:
iounmap(virtadr);
return ret;
}
static void release_nanddoc(void)
{
- struct mtd_info *mtd, *nextmtd;
+ struct mtd_info *mtd, *nextmtd;
struct nand_chip *nand;
struct doc_priv *doc;
@@ -1747,8 +1739,8 @@ static int __init init_nanddoc(void)
* generator polinomial degree = 4
*/
rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
- if (!rs_decoder) {
- printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+ if (!rs_decoder) {
+ printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
return -ENOMEM;
}
@@ -1758,7 +1750,7 @@ static int __init init_nanddoc(void)
if (ret < 0)
goto outerr;
} else {
- for (i=0; (doc_locations[i] != 0xffffffff); i++) {
+ for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
doc_probe(doc_locations[i]);
}
}
@@ -1770,7 +1762,7 @@ static int __init init_nanddoc(void)
goto outerr;
}
return 0;
-outerr:
+ outerr:
free_rs(rs_decoder);
return ret;
}
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 9b1fd2f387fa..516c0e5e564c 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -1,7 +1,7 @@
/*
* drivers/mtd/nand/edb7312.c
*
- * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
@@ -25,7 +25,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
-#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
#include <asm/sizes.h>
#include <asm/hardware/clps7111.h>
@@ -54,51 +54,45 @@ static struct mtd_info *ep7312_mtd = NULL;
*/
static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE;
-static void __iomem * ep7312_pxdr = (void __iomem *) EP7312_PXDR;
-static void __iomem * ep7312_pxddr = (void __iomem *) EP7312_PXDDR;
+static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR;
+static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR;
#ifdef CONFIG_MTD_PARTITIONS
/*
* Define static partitions for flash device
*/
static struct mtd_partition partition_info[] = {
- { .name = "EP7312 Nand Flash",
- .offset = 0,
- .size = 8*1024*1024 }
+ {.name = "EP7312 Nand Flash",
+ .offset = 0,
+ .size = 8 * 1024 * 1024}
};
+
#define NUM_PARTITIONS 1
#endif
-
/*
* hardware specific access to control-lines
+ *
+ * NAND_NCE: bit 0 -> bit 7
+ * NAND_CLE: bit 1 -> bit 4
+ * NAND_ALE: bit 2 -> bit 5
*/
-static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- switch(cmd) {
-
- case NAND_CTL_SETCLE:
- clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr);
- break;
- case NAND_CTL_CLRCLE:
- clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
- break;
-
- case NAND_CTL_SETALE:
- clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
- break;
- case NAND_CTL_CLRALE:
- clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
- break;
-
- case NAND_CTL_SETNCE:
- clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
- break;
- case NAND_CTL_CLRNCE:
- clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr);
- break;
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned char bits;
+
+ bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3;
+ bits = (ctrl & NAND_NCE) << 7;
+
+ clps_writeb((clps_readb(ep7312_pxdr) & 0xB0) | 0x10,
+ ep7312_pxdr);
}
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
/*
@@ -108,6 +102,7 @@ static int ep7312_device_ready(struct mtd_info *mtd)
{
return 1;
}
+
#ifdef CONFIG_MTD_PARTITIONS
const char *part_probes[] = { "cmdlinepart", NULL };
#endif
@@ -115,18 +110,16 @@ const char *part_probes[] = { "cmdlinepart", NULL };
/*
* Main initialization routine
*/
-static int __init ep7312_init (void)
+static int __init ep7312_init(void)
{
struct nand_chip *this;
const char *part_type = 0;
int mtd_parts_nb = 0;
struct mtd_partition *mtd_parts = 0;
- void __iomem * ep7312_fio_base;
+ void __iomem *ep7312_fio_base;
/* Allocate memory for MTD device structure and private data */
- ep7312_mtd = kmalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip),
- GFP_KERNEL);
+ ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ep7312_mtd) {
printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
return -ENOMEM;
@@ -134,21 +127,22 @@ static int __init ep7312_init (void)
/* map physical adress */
ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
- if(!ep7312_fio_base) {
+ if (!ep7312_fio_base) {
printk("ioremap EDB7312 NAND flash failed\n");
kfree(ep7312_mtd);
return -EIO;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&ep7312_mtd[1]);
+ this = (struct nand_chip *)(&ep7312_mtd[1]);
/* Initialize structures */
- memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(ep7312_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ep7312_mtd->priv = this;
+ ep7312_mtd->owner = THIS_MODULE;
/*
* Set GPIO Port B control register so that the pins are configured
@@ -159,22 +153,20 @@ static int __init ep7312_init (void)
/* insert callbacks */
this->IO_ADDR_R = ep7312_fio_base;
this->IO_ADDR_W = ep7312_fio_base;
- this->hwcontrol = ep7312_hwcontrol;
+ this->cmd_ctrl = ep7312_hwcontrol;
this->dev_ready = ep7312_device_ready;
/* 15 us command delay time */
this->chip_delay = 15;
/* Scan to find existence of the device */
- if (nand_scan (ep7312_mtd, 1)) {
+ if (nand_scan(ep7312_mtd, 1)) {
iounmap((void *)ep7312_fio_base);
- kfree (ep7312_mtd);
+ kfree(ep7312_mtd);
return -ENXIO;
}
-
#ifdef CONFIG_MTD_PARTITIONS
ep7312_mtd->name = "edb7312-nand";
- mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
- &mtd_parts, 0);
+ mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0);
if (mtd_parts_nb > 0)
part_type = "command line";
else
@@ -193,24 +185,23 @@ static int __init ep7312_init (void)
/* Return happy */
return 0;
}
+
module_init(ep7312_init);
/*
* Clean up routine
*/
-static void __exit ep7312_cleanup (void)
+static void __exit ep7312_cleanup(void)
{
- struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
+ struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1];
/* Release resources, unregister device */
- nand_release (ap7312_mtd);
-
- /* Free internal data buffer */
- kfree (this->data_buf);
+ nand_release(ap7312_mtd);
/* Free the MTD device structure */
- kfree (ep7312_mtd);
+ kfree(ep7312_mtd);
}
+
module_exit(ep7312_cleanup);
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
index f68f7a99a630..2d585d2d090c 100644
--- a/drivers/mtd/nand/h1910.c
+++ b/drivers/mtd/nand/h1910.c
@@ -4,7 +4,7 @@
* Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
*
* Derived from drivers/mtd/nand/edb7312.c
- * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*
* $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $
@@ -26,7 +26,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
-#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
#include <asm/sizes.h>
#include <asm/arch/h1900-gpio.h>
#include <asm/arch/ipaq.h>
@@ -45,47 +45,29 @@ static struct mtd_info *h1910_nand_mtd = NULL;
* Define static partitions for flash device
*/
static struct mtd_partition partition_info[] = {
- { name: "h1910 NAND Flash",
- offset: 0,
- size: 16*1024*1024 }
+ {name:"h1910 NAND Flash",
+ offset:0,
+ size:16 * 1024 * 1024}
};
+
#define NUM_PARTITIONS 1
#endif
-
/*
* hardware specific access to control-lines
+ *
+ * NAND_NCE: bit 0 - don't care
+ * NAND_CLE: bit 1 - address bit 2
+ * NAND_ALE: bit 2 - address bit 3
*/
-static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
+static void h1910_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-
- switch(cmd) {
-
- case NAND_CTL_SETCLE:
- this->IO_ADDR_R |= (1 << 2);
- this->IO_ADDR_W |= (1 << 2);
- break;
- case NAND_CTL_CLRCLE:
- this->IO_ADDR_R &= ~(1 << 2);
- this->IO_ADDR_W &= ~(1 << 2);
- break;
-
- case NAND_CTL_SETALE:
- this->IO_ADDR_R |= (1 << 3);
- this->IO_ADDR_W |= (1 << 3);
- break;
- case NAND_CTL_CLRALE:
- this->IO_ADDR_R &= ~(1 << 3);
- this->IO_ADDR_W &= ~(1 << 3);
- break;
-
- case NAND_CTL_SETNCE:
- break;
- case NAND_CTL_CLRNCE:
- break;
- }
+ struct nand_chip *chip = mtd->priv;
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1));
}
/*
@@ -101,7 +83,7 @@ static int h1910_device_ready(struct mtd_info *mtd)
/*
* Main initialization routine
*/
-static int __init h1910_init (void)
+static int __init h1910_init(void)
{
struct nand_chip *this;
const char *part_type = 0;
@@ -119,24 +101,23 @@ static int __init h1910_init (void)
}
/* Allocate memory for MTD device structure and private data */
- h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip),
- GFP_KERNEL);
+ h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!h1910_nand_mtd) {
printk("Unable to allocate h1910 NAND MTD device structure.\n");
- iounmap ((void *) nandaddr);
+ iounmap((void *)nandaddr);
return -ENOMEM;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&h1910_nand_mtd[1]);
+ this = (struct nand_chip *)(&h1910_nand_mtd[1]);
/* Initialize structures */
- memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(h1910_nand_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
h1910_nand_mtd->priv = this;
+ h1910_nand_mtd->owner = THIS_MODULE;
/*
* Enable VPEN
@@ -146,31 +127,28 @@ static int __init h1910_init (void)
/* insert callbacks */
this->IO_ADDR_R = nandaddr;
this->IO_ADDR_W = nandaddr;
- this->hwcontrol = h1910_hwcontrol;
+ this->cmd_ctrl = h1910_hwcontrol;
this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
/* 15 us command delay time */
this->chip_delay = 50;
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
this->options = NAND_NO_AUTOINCR;
/* Scan to find existence of the device */
- if (nand_scan (h1910_nand_mtd, 1)) {
+ if (nand_scan(h1910_nand_mtd, 1)) {
printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
- kfree (h1910_nand_mtd);
- iounmap ((void *) nandaddr);
+ kfree(h1910_nand_mtd);
+ iounmap((void *)nandaddr);
return -ENXIO;
}
-
#ifdef CONFIG_MTD_CMDLINE_PARTS
- mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts,
- "h1910-nand");
+ mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand");
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";
@@ -183,24 +161,26 @@ static int __init h1910_init (void)
/* Return happy */
return 0;
}
+
module_init(h1910_init);
/*
* Clean up routine
*/
-static void __exit h1910_cleanup (void)
+static void __exit h1910_cleanup(void)
{
- struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
+ struct nand_chip *this = (struct nand_chip *)&h1910_nand_mtd[1];
/* Release resources, unregister device */
- nand_release (h1910_nand_mtd);
+ nand_release(h1910_nand_mtd);
/* Release io resource */
- iounmap ((void *) this->IO_ADDR_W);
+ iounmap((void *)this->IO_ADDR_W);
/* Free the MTD device structure */
- kfree (h1910_nand_mtd);
+ kfree(h1910_nand_mtd);
}
+
module_exit(h1910_cleanup);
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 95e96fa1fceb..27083ed0a017 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -10,67 +10,31 @@
* http://www.linux-mtd.infradead.org/tech/nand.html
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * 2002 Thomas Gleixner (tglx@linutronix.de)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
*
- * 02-08-2004 tglx: support for strange chips, which cannot auto increment
- * pages on read / read_oob
- *
- * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes
- * pointed this out, as he marked an auto increment capable chip
- * as NOAUTOINCR in the board driver.
- * Make reads over block boundaries work too
- *
- * 04-14-2004 tglx: first working version for 2k page size chips
- *
- * 05-19-2004 tglx: Basic support for Renesas AG-AND chips
- *
- * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared
- * among multiple independend devices. Suggestions and initial patch
- * from Ben Dooks <ben-mtd@fluff.org>
- *
- * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
- * Basically, any block not rewritten may lose data when surrounding blocks
- * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
- * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
- * do not lose data, force them to be rewritten when some of the surrounding
- * blocks are erased. Rather than tracking a specific nearby block (which
- * could itself go bad), use a page address 'mask' to select several blocks
- * in the same area, and rewrite the BBT when any of them are erased.
- *
- * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
- * AG-AND chips. If there was a sudden loss of power during an erase operation,
- * a "device recovery" operation must be performed when power is restored
- * to ensure correct operation.
- *
- * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
- * perform extra error status checks on erase and write failures. This required
- * adding a wrapper function for nand_read_ecc.
- *
- * 08-20-2005 vwool: suspend/resume added
- *
- * Credits:
+ * Credits:
* David Woodhouse for adding multichip support
*
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
* rework for 2K page size chips
*
- * TODO:
+ * TODO:
* Enable cached programming for 2k page size chips
* Check, if mtd->ecctype should be set to MTD_ECC_HW
* if we have HW ecc support.
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
- * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool 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
* published by the Free Software Foundation.
*
*/
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -88,75 +52,46 @@
#endif
/* Define default oob placement schemes for large and small page devices */
-static struct nand_oobinfo nand_oob_8 = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout nand_oob_8 = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
- .oobfree = { {3, 2}, {6, 2} }
+ .oobfree = {
+ {.offset = 3,
+ .length = 2},
+ {.offset = 6,
+ .length = 2}}
};
-static struct nand_oobinfo nand_oob_16 = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
- .oobfree = { {8, 8} }
+ .oobfree = {
+ {.offset = 8,
+ . length = 8}}
};
-static struct nand_oobinfo nand_oob_64 = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63},
- .oobfree = { {2, 38} }
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63},
+ .oobfree = {
+ {.offset = 2,
+ .length = 38}}
};
-/* This is used for padding purposes in nand_write_oob */
-static u_char ffchars[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
+static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
+ int new_state);
+
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops);
/*
- * NAND low-level MTD interface functions
+ * For devices which display every fart in the system on a seperate LED. Is
+ * compiled away when LED support is disabled.
*/
-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, 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, 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 kvec *vecs,
- unsigned long count, loff_t to, size_t * retlen);
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
- 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);
-
-/* Some internal functions */
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,
- struct nand_oobinfo *oobsel, int mode);
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
- u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
-#else
-#define nand_verify_pages(...) (0)
-#endif
-
-static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+DEFINE_LED_TRIGGER(nand_led_trigger);
/**
* nand_release_device - [GENERIC] release chip
@@ -164,27 +99,19 @@ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int ne
*
* Deselect, release chip lock and wake up anyone waiting on the device
*/
-static void nand_release_device (struct mtd_info *mtd)
+static void nand_release_device(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
/* De-select the NAND device */
- this->select_chip(mtd, -1);
-
- if (this->controller) {
- /* Release the controller and the chip */
- spin_lock(&this->controller->lock);
- this->controller->active = NULL;
- this->state = FL_READY;
- wake_up(&this->controller->wq);
- spin_unlock(&this->controller->lock);
- } else {
- /* Release the chip */
- spin_lock(&this->chip_lock);
- this->state = FL_READY;
- wake_up(&this->wq);
- spin_unlock(&this->chip_lock);
- }
+ chip->select_chip(mtd, -1);
+
+ /* Release the controller and the chip */
+ spin_lock(&chip->controller->lock);
+ chip->controller->active = NULL;
+ chip->state = FL_READY;
+ wake_up(&chip->controller->wq);
+ spin_unlock(&chip->controller->lock);
}
/**
@@ -193,23 +120,10 @@ static void nand_release_device (struct mtd_info *mtd)
*
* Default read function for 8bit buswith
*/
-static u_char nand_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- return readb(this->IO_ADDR_R);
-}
-
-/**
- * nand_write_byte - [DEFAULT] write one byte to the chip
- * @mtd: MTD device structure
- * @byte: pointer to data byte to write
- *
- * Default write function for 8it buswith
- */
-static void nand_write_byte(struct mtd_info *mtd, u_char byte)
+static uint8_t nand_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- writeb(byte, this->IO_ADDR_W);
+ struct nand_chip *chip = mtd->priv;
+ return readb(chip->IO_ADDR_R);
}
/**
@@ -219,24 +133,10 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte)
* Default read function for 16bit buswith with
* endianess conversion
*/
-static u_char nand_read_byte16(struct mtd_info *mtd)
+static uint8_t nand_read_byte16(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
-}
-
-/**
- * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
- * @mtd: MTD device structure
- * @byte: pointer to data byte to write
- *
- * Default write function for 16bit buswith with
- * endianess conversion
- */
-static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
-{
- struct nand_chip *this = mtd->priv;
- writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+ struct nand_chip *chip = mtd->priv;
+ return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
}
/**
@@ -248,22 +148,8 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
*/
static u16 nand_read_word(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- return readw(this->IO_ADDR_R);
-}
-
-/**
- * nand_write_word - [DEFAULT] write one word to the chip
- * @mtd: MTD device structure
- * @word: data word to write
- *
- * Default write function for 16bit buswith without
- * endianess conversion
- */
-static void nand_write_word(struct mtd_info *mtd, u16 word)
-{
- struct nand_chip *this = mtd->priv;
- writew(word, this->IO_ADDR_W);
+ struct nand_chip *chip = mtd->priv;
+ return readw(chip->IO_ADDR_R);
}
/**
@@ -273,15 +159,15 @@ static void nand_write_word(struct mtd_info *mtd, u16 word)
*
* Default select function for 1 chip devices.
*/
-static void nand_select_chip(struct mtd_info *mtd, int chip)
+static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
- struct nand_chip *this = mtd->priv;
- switch(chip) {
+ struct nand_chip *chip = mtd->priv;
+
+ switch (chipnr) {
case -1:
- this->hwcontrol(mtd, NAND_CTL_CLRNCE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
- this->hwcontrol(mtd, NAND_CTL_SETNCE);
break;
default:
@@ -297,13 +183,13 @@ static void nand_select_chip(struct mtd_info *mtd, int chip)
*
* Default write function for 8bit buswith
*/
-static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- for (i=0; i<len; i++)
- writeb(buf[i], this->IO_ADDR_W);
+ for (i = 0; i < len; i++)
+ writeb(buf[i], chip->IO_ADDR_W);
}
/**
@@ -314,13 +200,13 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
*
* Default read function for 8bit buswith
*/
-static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- for (i=0; i<len; i++)
- buf[i] = readb(this->IO_ADDR_R);
+ for (i = 0; i < len; i++)
+ buf[i] = readb(chip->IO_ADDR_R);
}
/**
@@ -331,15 +217,14 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
*
* Default verify function for 8bit buswith
*/
-static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- for (i=0; i<len; i++)
- if (buf[i] != readb(this->IO_ADDR_R))
+ for (i = 0; i < len; i++)
+ if (buf[i] != readb(chip->IO_ADDR_R))
return -EFAULT;
-
return 0;
}
@@ -351,15 +236,15 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
*
* Default write function for 16bit buswith
*/
-static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++)
- writew(p[i], this->IO_ADDR_W);
+ for (i = 0; i < len; i++)
+ writew(p[i], chip->IO_ADDR_W);
}
@@ -371,15 +256,15 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
*
* Default read function for 16bit buswith
*/
-static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++)
- p[i] = readw(this->IO_ADDR_R);
+ for (i = 0; i < len; i++)
+ p[i] = readw(chip->IO_ADDR_R);
}
/**
@@ -390,15 +275,15 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
*
* Default verify function for 16bit buswith
*/
-static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
u16 *p = (u16 *) buf;
len >>= 1;
- for (i=0; i<len; i++)
- if (p[i] != readw(this->IO_ADDR_R))
+ for (i = 0; i < len; i++)
+ if (p[i] != readw(chip->IO_ADDR_R))
return -EFAULT;
return 0;
@@ -415,38 +300,37 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
{
int page, chipnr, res = 0;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
u16 bad;
if (getchip) {
- page = (int)(ofs >> this->page_shift);
- chipnr = (int)(ofs >> this->chip_shift);
+ page = (int)(ofs >> chip->page_shift);
+ chipnr = (int)(ofs >> chip->chip_shift);
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_READING);
+ nand_get_device(chip, mtd, FL_READING);
/* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ chip->select_chip(mtd, chipnr);
} else
- page = (int) ofs;
+ page = (int)ofs;
- if (this->options & NAND_BUSWIDTH_16) {
- this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
- bad = cpu_to_le16(this->read_word(mtd));
- if (this->badblockpos & 0x1)
+ if (chip->options & NAND_BUSWIDTH_16) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
+ page & chip->pagemask);
+ bad = cpu_to_le16(chip->read_word(mtd));
+ if (chip->badblockpos & 0x1)
bad >>= 8;
if ((bad & 0xFF) != 0xff)
res = 1;
} else {
- this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
- if (this->read_byte(mtd) != 0xff)
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
+ page & chip->pagemask);
+ if (chip->read_byte(mtd) != 0xff)
res = 1;
}
- if (getchip) {
- /* Deselect and wake up anyone waiting on the device */
+ if (getchip)
nand_release_device(mtd);
- }
return res;
}
@@ -461,23 +345,33 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
*/
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *this = mtd->priv;
- u_char buf[2] = {0, 0};
- size_t retlen;
- int block;
+ struct nand_chip *chip = mtd->priv;
+ uint8_t buf[2] = { 0, 0 };
+ int block, ret;
/* Get block number */
- block = ((int) ofs) >> this->bbt_erase_shift;
- if (this->bbt)
- this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+ block = ((int)ofs) >> chip->bbt_erase_shift;
+ if (chip->bbt)
+ chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/* Do we have a flash based bad block table ? */
- if (this->options & NAND_USE_FLASH_BBT)
- return nand_update_bbt (mtd, ofs);
+ if (chip->options & NAND_USE_FLASH_BBT)
+ ret = nand_update_bbt(mtd, ofs);
+ else {
+ /* We write two bytes, so we dont have to mess with 16 bit
+ * access
+ */
+ ofs += mtd->oobsize;
+ chip->ops.len = 2;
+ chip->ops.datbuf = NULL;
+ chip->ops.oobbuf = buf;
+ chip->ops.ooboffs = chip->badblockpos & ~0x01;
- /* We write two bytes, so we dont have to mess with 16 bit access */
- ofs += mtd->oobsize + (this->badblockpos & ~0x01);
- return nand_write_oob (mtd, ofs , 2, &retlen, buf);
+ ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+ }
+ if (!ret)
+ mtd->ecc_stats.badblocks++;
+ return ret;
}
/**
@@ -487,12 +381,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
*
* The function expects, that the device is already selected
*/
-static int nand_check_wp (struct mtd_info *mtd)
+static int nand_check_wp(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
/* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
/**
@@ -505,32 +399,31 @@ static int nand_check_wp (struct mtd_info *mtd)
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+ int allowbbt)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- if (!this->bbt)
- return this->block_bad(mtd, ofs, getchip);
+ if (!chip->bbt)
+ return chip->block_bad(mtd, ofs, getchip);
/* Return info from the table */
- return nand_isbad_bbt (mtd, ofs, allowbbt);
+ return nand_isbad_bbt(mtd, ofs, allowbbt);
}
-DEFINE_LED_TRIGGER(nand_led_trigger);
-
/*
* Wait for the ready pin, after a command
* The timeout is catched later.
*/
static void nand_wait_ready(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- unsigned long timeo = jiffies + 2;
+ struct nand_chip *chip = mtd->priv;
+ unsigned long timeo = jiffies + 2;
led_trigger_event(nand_led_trigger, LED_FULL);
/* wait until command is processed or timeout occures */
do {
- if (this->dev_ready(mtd))
+ if (chip->dev_ready(mtd))
break;
touch_softlockup_watchdog();
} while (time_before(jiffies, timeo));
@@ -547,21 +440,21 @@ static void nand_wait_ready(struct mtd_info *mtd)
* Send command to NAND device. This function is used for small page
* devices (256/512 Bytes per page)
*/
-static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
{
- register struct nand_chip *this = mtd->priv;
+ register struct nand_chip *chip = mtd->priv;
+ int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
- /* Begin command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
/*
* Write out the command to the device.
*/
if (command == NAND_CMD_SEQIN) {
int readcmd;
- if (column >= mtd->oobblock) {
+ if (column >= mtd->writesize) {
/* OOB area */
- column -= mtd->oobblock;
+ column -= mtd->writesize;
readcmd = NAND_CMD_READOOB;
} else if (column < 256) {
/* First 256 bytes --> READ0 */
@@ -570,38 +463,37 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
column -= 256;
readcmd = NAND_CMD_READ1;
}
- this->write_byte(mtd, readcmd);
+ chip->cmd_ctrl(mtd, readcmd, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
}
- this->write_byte(mtd, command);
-
- /* Set ALE and clear CLE to start address cycle */
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+ chip->cmd_ctrl(mtd, command, ctrl);
- if (column != -1 || page_addr != -1) {
- this->hwcontrol(mtd, NAND_CTL_SETALE);
-
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (this->options & NAND_BUSWIDTH_16)
- column >>= 1;
- this->write_byte(mtd, column);
- }
- if (page_addr != -1) {
- this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
- this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
- /* One more address cycle for devices > 32MiB */
- if (this->chipsize > (32 << 20))
- this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
- }
- /* Latch in address */
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
+ /*
+ * Address cycle, when necessary
+ */
+ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16)
+ column >>= 1;
+ chip->cmd_ctrl(mtd, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ }
+ if (page_addr != -1) {
+ chip->cmd_ctrl(mtd, page_addr, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
+ /* One more address cycle for devices > 32MiB */
+ if (chip->chipsize > (32 << 20))
+ chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
}
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* program and erase have their own busy handlers
* status and sequential in needs no delay
- */
+ */
switch (command) {
case NAND_CMD_PAGEPROG:
@@ -612,29 +504,30 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
return;
case NAND_CMD_RESET:
- if (this->dev_ready)
+ if (chip->dev_ready)
break;
- 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) & NAND_STATUS_READY));
+ udelay(chip->chip_delay);
+ chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd,
+ NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
return;
- /* This applies to read commands */
+ /* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
+ */
+ if (!chip->dev_ready) {
+ udelay(chip->chip_delay);
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
- ndelay (100);
+ ndelay(100);
nand_wait_ready(mtd);
}
@@ -646,50 +539,49 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
* @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none
*
- * Send command to NAND device. This is the version for the new large page devices
- * We dont have the seperate regions as we have in the small page devices.
- * We must emulate NAND_CMD_READOOB to keep the code compatible.
+ * Send command to NAND device. This is the version for the new large page
+ * devices We dont have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
*
*/
-static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
{
- register struct nand_chip *this = mtd->priv;
+ register struct nand_chip *chip = mtd->priv;
/* Emulate NAND_CMD_READOOB */
if (command == NAND_CMD_READOOB) {
- column += mtd->oobblock;
+ column += mtd->writesize;
command = NAND_CMD_READ0;
}
-
- /* Begin command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- /* Write out the command to the device. */
- this->write_byte(mtd, (command & 0xff));
- /* End command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+ /* Command latch cycle */
+ chip->cmd_ctrl(mtd, command & 0xff,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
if (column != -1 || page_addr != -1) {
- this->hwcontrol(mtd, NAND_CTL_SETALE);
+ int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
- if (this->options & NAND_BUSWIDTH_16)
+ if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
- this->write_byte(mtd, column & 0xff);
- this->write_byte(mtd, column >> 8);
+ chip->cmd_ctrl(mtd, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
if (page_addr != -1) {
- this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
- this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+ chip->cmd_ctrl(mtd, page_addr, ctrl);
+ chip->cmd_ctrl(mtd, page_addr >> 8,
+ NAND_NCE | NAND_ALE);
/* One more address cycle for devices > 128MiB */
- if (this->chipsize > (128 << 20))
- this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff));
+ if (chip->chipsize > (128 << 20))
+ chip->cmd_ctrl(mtd, page_addr >> 16,
+ NAND_NCE | NAND_ALE);
}
- /* Latch in address */
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
}
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* program and erase have their own busy handlers
@@ -702,55 +594,62 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
+ case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
return;
- /*
- * read error status commands require only a short delay
- */
+ /*
+ * read error status commands require only a short delay
+ */
case NAND_CMD_STATUS_ERROR:
case NAND_CMD_STATUS_ERROR0:
case NAND_CMD_STATUS_ERROR1:
case NAND_CMD_STATUS_ERROR2:
case NAND_CMD_STATUS_ERROR3:
- udelay(this->chip_delay);
+ udelay(chip->chip_delay);
return;
case NAND_CMD_RESET:
- if (this->dev_ready)
+ if (chip->dev_ready)
break;
- 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) & NAND_STATUS_READY));
+ udelay(chip->chip_delay);
+ chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
+ return;
+
+ case NAND_CMD_RNDOUT:
+ /* No ready / busy check necessary */
+ chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
return;
case NAND_CMD_READ0:
- /* Begin command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- /* Write out the start read command */
- this->write_byte(mtd, NAND_CMD_READSTART);
- /* End command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- /* Fall through into ready check */
-
- /* This applies to read commands */
+ chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
+ */
+ if (!chip->dev_ready) {
+ udelay(chip->chip_delay);
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
- ndelay (100);
+ ndelay(100);
nand_wait_ready(mtd);
}
@@ -763,34 +662,28 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
*
* Get the device and lock it for exclusive access
*/
-static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+static int
+nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
{
- struct nand_chip *active;
- spinlock_t *lock;
- wait_queue_head_t *wq;
- DECLARE_WAITQUEUE (wait, current);
-
- lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
- wq = (this->controller) ? &this->controller->wq : &this->wq;
-retry:
- active = this;
+ spinlock_t *lock = &chip->controller->lock;
+ wait_queue_head_t *wq = &chip->controller->wq;
+ DECLARE_WAITQUEUE(wait, current);
+ retry:
spin_lock(lock);
/* Hardware controller shared among independend devices */
- if (this->controller) {
- if (this->controller->active)
- active = this->controller->active;
- else
- this->controller->active = this;
- }
- if (active == this && this->state == FL_READY) {
- this->state = new_state;
+ /* Hardware controller shared among independend devices */
+ if (!chip->controller->active)
+ chip->controller->active = chip;
+
+ if (chip->controller->active == chip && chip->state == FL_READY) {
+ chip->state = new_state;
spin_unlock(lock);
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
spin_unlock(lock);
- return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
+ return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
@@ -804,540 +697,339 @@ retry:
* nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure
* @this: NAND chip structure
- * @state: state to select the max. timeout value
*
* Wait for command done. This applies to erase and program only
* Erase can take up to 400ms and program up to 20ms according to
* general NAND and SmartMedia specs
*
*/
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- unsigned long timeo = jiffies;
- int status;
+ unsigned long timeo = jiffies;
+ int status, state = chip->state;
if (state == FL_ERASING)
- timeo += (HZ * 400) / 1000;
+ timeo += (HZ * 400) / 1000;
else
- timeo += (HZ * 20) / 1000;
+ timeo += (HZ * 20) / 1000;
led_trigger_event(nand_led_trigger, LED_FULL);
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
- ndelay (100);
+ ndelay(100);
- if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
- this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
+ if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
+ chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
else
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
while (time_before(jiffies, timeo)) {
- /* Check, if we were interrupted */
- if (this->state != state)
- return 0;
-
- if (this->dev_ready) {
- if (this->dev_ready(mtd))
+ if (chip->dev_ready) {
+ if (chip->dev_ready(mtd))
break;
} else {
- if (this->read_byte(mtd) & NAND_STATUS_READY)
+ if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
cond_resched();
}
led_trigger_event(nand_led_trigger, LED_OFF);
- status = (int) this->read_byte(mtd);
+ status = (int)chip->read_byte(mtd);
return status;
}
/**
- * nand_write_page - [GENERIC] write one page
- * @mtd: MTD device structure
- * @this: NAND chip structure
- * @page: startpage inside the chip, must be called with (page & this->pagemask)
- * @oob_buf: out of band data buffer
- * @oobsel: out of band selecttion structre
- * @cached: 1 = enable cached programming if supported by chip
- *
- * 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 :)
- *
- * Cached programming is not supported yet.
+ * nand_read_page_raw - [Intern] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
*/
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page,
- u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
+static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
{
- int i, status;
- u_char ecc_code[32];
- int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
- int *oob_config = oobsel->eccpos;
- int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
- int eccbytes = 0;
-
- /* FIXME: Enable cached programming */
- cached = 0;
+ chip->read_buf(mtd, buf, mtd->writesize);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
+}
- /* Send command to begin auto page programming */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+/**
+ * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ */
+static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers.ecccalc;
+ uint8_t *ecc_code = chip->buffers.ecccode;
+ int *eccpos = chip->ecc.layout->eccpos;
- /* Write out complete page of data, take care of eccmode */
- switch (eccmode) {
- /* No ecc, 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;
+ nand_read_page_raw(mtd, chip, buf);
- /* Software ecc 3/256, write all */
- case NAND_ECC_SOFT:
- for (; eccsteps; eccsteps--) {
- this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
- for (i = 0; i < 3; i++, eccidx++)
- oob_buf[oob_config[eccidx]] = ecc_code[i];
- datidx += this->eccsize;
- }
- this->write_buf(mtd, this->data_poi, mtd->oobblock);
- break;
- default:
- eccbytes = this->eccbytes;
- for (; eccsteps; eccsteps--) {
- /* enable hardware ecc logic for write */
- this->enable_hwecc(mtd, NAND_ECC_WRITE);
- this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
- this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
- for (i = 0; i < eccbytes; i++, eccidx++)
- oob_buf[oob_config[eccidx]] = ecc_code[i];
- /* If the hardware ecc provides syndromes then
- * the ecc code must be written immidiately after
- * the data bytes (words) */
- if (this->options & NAND_HWECC_SYNDROME)
- this->write_buf(mtd, ecc_code, eccbytes);
- datidx += this->eccsize;
- }
- break;
- }
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- /* Write out OOB data */
- if (this->options & NAND_HWECC_SYNDROME)
- this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
- else
- this->write_buf(mtd, oob_buf, mtd->oobsize);
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
- /* Send command to actually program the data */
- this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
+ eccsteps = chip->ecc.steps;
+ p = buf;
- if (!cached) {
- /* call wait ready function */
- status = this->waitfunc (mtd, this, FL_WRITING);
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
- /* See if operation failed and additional status checks are available */
- if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
- status = this->errstat(mtd, this, FL_WRITING, status, page);
- }
-
- /* See if device thinks it succeeded */
- if (status & NAND_STATUS_FAIL) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
- return -EIO;
- }
- } else {
- /* FIXME: Implement cached programming ! */
- /* wait until cache is ready*/
- // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat == -1)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
}
return 0;
}
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
/**
- * nand_verify_pages - [GENERIC] verify the chip contents after a write
- * @mtd: MTD device structure
- * @this: NAND chip structure
- * @page: startpage inside the chip, must be called with (page & this->pagemask)
- * @numpages: number of pages to verify
- * @oob_buf: out of band data buffer
- * @oobsel: out of band selecttion structre
- * @chipnr: number of the current chip
- * @oobmode: 1 = full buffer verify, 0 = ecc only
+ * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
*
- * The NAND device assumes that it is always writing to a cleanly erased page.
- * Hence, it performs its internal write verification only on bits that
- * transitioned from 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was not completely erased
- * or the page is becoming unusable due to wear. The read with ECC would catch
- * the error later when the ECC page check fails, but we would rather catch
- * it early in the page write stage. Better to write no data than invalid data.
+ * Not for syndrome calculating ecc controllers which need a special oob layout
*/
-static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
- u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
+static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
{
- int i, j, datidx = 0, oobofs = 0, res = -EIO;
- int eccsteps = this->eccsteps;
- int hweccbytes;
- u_char oobdata[64];
-
- hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
-
- /* Send command to read back the first page */
- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
-
- for(;;) {
- for (j = 0; j < eccsteps; j++) {
- /* Loop through and verify the data */
- if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- goto out;
- }
- datidx += mtd->eccsize;
- /* Have we a hw generator layout ? */
- if (!hweccbytes)
- continue;
- if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- goto out;
- }
- oobofs += hweccbytes;
- }
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers.ecccalc;
+ uint8_t *ecc_code = chip->buffers.ecccode;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- /* check, if we must compare all data or if we just have to
- * compare the ecc bytes
- */
- if (oobmode) {
- if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- goto out;
- }
- } else {
- /* Read always, else autoincrement fails */
- this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
-
- if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
- int ecccnt = oobsel->eccbytes;
-
- for (i = 0; i < ecccnt; i++) {
- int idx = oobsel->eccpos[i];
- if (oobdata[idx] != oob_buf[oobofs + idx] ) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "%s: Failed ECC write "
- "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
- goto out;
- }
- }
- }
- }
- oobofs += mtd->oobsize - hweccbytes * eccsteps;
- page++;
- numpages--;
-
- /* Apply delay or wait for ready/busy pin
- * Do this before the AUTOINCR check, so no problems
- * arise if a chip which does auto increment
- * is marked as NOAUTOINCR by the board driver.
- * Do this also before returning, so the chip is
- * ready for the next command.
- */
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
- nand_wait_ready(mtd);
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
- /* All done, return happy */
- if (!numpages)
- return 0;
+ eccsteps = chip->ecc.steps;
+ p = buf;
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
- /* Check, if the chip supports auto page increment */
- if (!NAND_CANAUTOINCR(this))
- this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat == -1)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
}
- /*
- * Terminate the read command. We come here in case of an error
- * So we must issue a reset command.
- */
-out:
- this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
- return res;
+ return 0;
}
-#endif
/**
- * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
- * @mtd: MTD device structure
- * @from: offset to read from
- * @len: number of bytes to read
- * @retlen: pointer to variable to store the number of read bytes
- * @buf: the databuffer to put data
+ * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
*
- * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
- * and flags = 0xff
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
*/
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
{
- return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
-}
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+
+ if (chip->ecc.prepad) {
+ chip->read_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
+ }
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+ chip->read_buf(mtd, oob, eccbytes);
+ stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+ if (stat == -1)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->read_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
+ }
+
+ /* Calculate remaining oob bytes */
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->read_buf(mtd, oob, i);
+ return 0;
+}
/**
- * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
- * @mtd: MTD device structure
- * @from: offset to read from
- * @len: number of bytes to read
- * @retlen: pointer to variable to store the number of read bytes
- * @buf: the databuffer to put data
- * @oob_buf: filesystem supplied oob data buffer
- * @oobsel: oob selection structure
- *
- * This function simply calls nand_do_read_ecc with flags = 0xff
+ * nand_transfer_oob - [Internal] Transfer oob to client buffer
+ * @chip: nand chip structure
+ * @ops: oob ops structure
*/
-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, struct nand_oobinfo *oobsel)
+static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
+ struct mtd_oob_ops *ops)
{
- /* use userspace supplied oobinfo, if zero */
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
- return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+ size_t len = ops->ooblen;
+
+ switch(ops->mode) {
+
+ case MTD_OOB_PLACE:
+ case MTD_OOB_RAW:
+ memcpy(oob, chip->oob_poi + ops->ooboffs, len);
+ return oob + len;
+
+ case MTD_OOB_AUTO: {
+ struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ uint32_t boffs = 0, roffs = ops->ooboffs;
+ size_t bytes = 0;
+
+ for(; free->length && len; free++, len -= bytes) {
+ /* Read request not from offset 0 ? */
+ if (unlikely(roffs)) {
+ if (roffs >= free->length) {
+ roffs -= free->length;
+ continue;
+ }
+ boffs = free->offset + roffs;
+ bytes = min_t(size_t, len,
+ (free->length - roffs));
+ roffs = 0;
+ } else {
+ bytes = min_t(size_t, len, free->length);
+ boffs = free->offset;
+ }
+ memcpy(oob, chip->oob_poi + boffs, bytes);
+ oob += bytes;
+ }
+ return oob;
+ }
+ default:
+ BUG();
+ }
+ return NULL;
}
-
/**
- * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * nand_do_read_ops - [Internal] Read data with ECC
+ *
* @mtd: MTD device structure
* @from: offset to read from
- * @len: number of bytes to read
- * @retlen: pointer to variable to store the number of read bytes
- * @buf: the databuffer to put data
- * @oob_buf: filesystem supplied oob data buffer (can be NULL)
- * @oobsel: oob selection structure
- * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
- * and how many corrected error bits are acceptable:
- * bits 0..7 - number of tolerable errors
- * bit 8 - 0 == do not get/release chip, 1 == get/release chip
*
- * NAND read with ECC
+ * Internal function. Called with chip held.
*/
-int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf, u_char * oob_buf,
- struct nand_oobinfo *oobsel, int flags)
+static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
+ int chipnr, page, realpage, col, bytes, aligned;
+ struct nand_chip *chip = mtd->priv;
+ struct mtd_ecc_stats stats;
+ int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+ int sndcmd = 1;
+ int ret = 0;
+ uint32_t readlen = ops->len;
+ uint8_t *bufpoi, *oob, *buf;
- int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
- int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
- struct nand_chip *this = mtd->priv;
- u_char *data_poi, *oob_data = oob_buf;
- u_char ecc_calc[32];
- u_char ecc_code[32];
- int eccmode, eccsteps;
- int *oob_config, datidx;
- int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
- int eccbytes;
- int compareecc = 1;
- int oobreadlen;
-
-
- 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 */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
- *retlen = 0;
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- if (flags & NAND_GET_DEVICE)
- nand_get_device (this, mtd, FL_READING);
-
- /* Autoplace of oob data ? Use the default placement scheme */
- if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
- oobsel = this->autooob;
-
- eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
- oob_config = oobsel->eccpos;
-
- /* Select the NAND device */
- chipnr = (int)(from >> this->chip_shift);
- this->select_chip(mtd, chipnr);
-
- /* First we calculate the starting page */
- realpage = (int) (from >> this->page_shift);
- page = realpage & this->pagemask;
-
- /* Get raw starting column */
- col = from & (mtd->oobblock - 1);
-
- end = mtd->oobblock;
- ecc = this->eccsize;
- eccbytes = this->eccbytes;
-
- if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
- compareecc = 0;
-
- oobreadlen = mtd->oobsize;
- if (this->options & NAND_HWECC_SYNDROME)
- oobreadlen -= oobsel->eccbytes;
+ stats = mtd->ecc_stats;
- /* Loop until all data read */
- while (read < len) {
+ chipnr = (int)(from >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
- int aligned = (!col && (len - read) >= end);
- /*
- * If the read is not page aligned, we have to read into data buffer
- * due to ecc, else we read into return buffer direct
- */
- if (aligned)
- data_poi = &buf[read];
- else
- data_poi = this->data_buf;
+ realpage = (int)(from >> chip->page_shift);
+ page = realpage & chip->pagemask;
- /* Check, if we have this page in the buffer
- *
- * FIXME: Make it work when we must provide oob data too,
- * check the usage of data_buf oob field
- */
- if (realpage == this->pagebuf && !oob_buf) {
- /* aligned read ? */
- if (aligned)
- memcpy (data_poi, this->data_buf, end);
- goto readdata;
- }
+ col = (int)(from & (mtd->writesize - 1));
+ chip->oob_poi = chip->buffers.oobrbuf;
- /* Check, if we must send the read command */
- if (sndcmd) {
- this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
- sndcmd = 0;
- }
+ buf = ops->datbuf;
+ oob = ops->oobbuf;
- /* get oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
- oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
- oob_data = &this->data_buf[end];
+ while(1) {
+ bytes = min(mtd->writesize - col, readlen);
+ aligned = (bytes == mtd->writesize);
- eccsteps = this->eccsteps;
+ /* Is the current page in the buffer ? */
+ if (realpage != chip->pagebuf || oob) {
+ bufpoi = aligned ? buf : chip->buffers.databuf;
- switch (eccmode) {
- 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;
+ if (likely(sndcmd)) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+ sndcmd = 0;
}
- this->read_buf(mtd, data_poi, end);
- break;
- }
- case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
- this->read_buf(mtd, data_poi, end);
- for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc)
- this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
- break;
+ /* Now read the page into the buffer */
+ ret = chip->ecc.read_page(mtd, chip, bufpoi);
+ if (ret < 0)
+ break;
- default:
- for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
- this->enable_hwecc(mtd, NAND_ECC_READ);
- this->read_buf(mtd, &data_poi[datidx], ecc);
-
- /* HW ecc with syndrome calculation must read the
- * syndrome from flash immidiately after the data */
- if (!compareecc) {
- /* Some hw ecc generators need to know when the
- * syndrome is read from flash */
- this->enable_hwecc(mtd, NAND_ECC_READSYN);
- this->read_buf(mtd, &oob_data[i], eccbytes);
- /* We calc error correction directly, it checks the hw
- * generator for an error, reads back the syndrome and
- * does the error correction on the fly */
- ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
- if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
- "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
- ecc_failed++;
- }
- } else {
- this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
- }
+ /* Transfer not aligned data */
+ if (!aligned) {
+ chip->pagebuf = realpage;
+ memcpy(buf, chip->buffers.databuf + col, bytes);
}
- break;
- }
-
- /* read oobdata */
- this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
-
- /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
- if (!compareecc)
- goto readoob;
-
- /* Pick the ECC bytes out of the oob data */
- for (j = 0; j < oobsel->eccbytes; j++)
- ecc_code[j] = oob_data[oob_config[j]];
- /* correct data, if neccecary */
- for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
- ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
+ buf += bytes;
- /* Get next chunk of ecc bytes */
- j += eccbytes;
-
- /* Check, if we have a fs supplied oob-buffer,
- * This is the legacy mode. Used by YAFFS1
- * Should go away some day
- */
- if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
- int *p = (int *)(&oob_data[mtd->oobsize]);
- p[i] = ecc_status;
+ if (unlikely(oob)) {
+ /* Raw mode does data:oob:data:oob */
+ if (ops->mode != MTD_OOB_RAW)
+ oob = nand_transfer_oob(chip, oob, ops);
+ else
+ buf = nand_transfer_oob(chip, buf, ops);
}
- if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
- ecc_failed++;
+ if (!(chip->options & NAND_NO_READRDY)) {
+ /*
+ * Apply delay or wait for ready/busy pin. Do
+ * this before the AUTOINCR check, so no
+ * problems arise if a chip which does auto
+ * increment is marked as NOAUTOINCR by the
+ * board driver.
+ */
+ if (!chip->dev_ready)
+ udelay(chip->chip_delay);
+ else
+ nand_wait_ready(mtd);
}
+ } else {
+ memcpy(buf, chip->buffers.databuf + col, bytes);
+ buf += bytes;
}
- readoob:
- /* check, if we have a fs supplied oob-buffer */
- if (oob_buf) {
- /* without autoplace. Legacy mode used by YAFFS1 */
- switch(oobsel->useecc) {
- case MTD_NANDECC_AUTOPLACE:
- case MTD_NANDECC_AUTOPL_USR:
- /* Walk through the autoplace chunks */
- for (i = 0; oobsel->oobfree[i][1]; i++) {
- int from = oobsel->oobfree[i][0];
- int num = oobsel->oobfree[i][1];
- memcpy(&oob_buf[oob], &oob_data[from], num);
- oob += num;
- }
- break;
- case MTD_NANDECC_PLACE:
- /* YAFFS1 legacy mode */
- oob_data += this->eccsteps * sizeof (int);
- default:
- oob_data += mtd->oobsize;
- }
- }
- readdata:
- /* Partial page read, transfer data into fs buffer */
- if (!aligned) {
- for (j = col; j < end && read < len; j++)
- buf[read++] = data_poi[j];
- this->pagebuf = realpage;
- } else
- read += mtd->oobblock;
-
- /* Apply delay or wait for ready/busy pin
- * Do this before the AUTOINCR check, so no problems
- * arise if a chip which does auto increment
- * is marked as NOAUTOINCR by the board driver.
- */
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
- nand_wait_ready(mtd);
+ readlen -= bytes;
- if (read == len)
+ if (!readlen)
break;
/* For subsequent reads align to page boundary. */
@@ -1345,701 +1037,775 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* Increment page address */
realpage++;
- page = realpage & this->pagemask;
+ page = realpage & chip->pagemask;
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
}
+
/* Check, if the chip supports auto page increment
* or if we have hit a block boundary.
- */
- if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
+ */
+ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
sndcmd = 1;
}
- /* Deselect and wake up anyone waiting on the device */
- if (flags & NAND_GET_DEVICE)
- nand_release_device(mtd);
+ ops->retlen = ops->len - (size_t) readlen;
- /*
- * Return success, if no ECC failures, else -EBADMSG
- * fs driver will take care of that, because
- * retlen == desired len and result == -EBADMSG
- */
- *retlen = read;
- return ecc_failed ? -EBADMSG : 0;
+ if (ret)
+ return ret;
+
+ if (mtd->ecc_stats.failed - stats.failed)
+ return -EBADMSG;
+
+ return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}
/**
- * nand_read_oob - [MTD Interface] NAND read out-of-band
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
- * NAND read out-of-band data from the spare area
+ * Get hold of the chip and call nand_do_read
*/
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, uint8_t *buf)
{
- int i, col, page, chipnr;
- struct nand_chip *this = mtd->priv;
- int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+ struct nand_chip *chip = mtd->priv;
+ int ret;
- DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ /* Do not allow reads past end of device */
+ if ((from + len) > mtd->size)
+ return -EINVAL;
+ if (!len)
+ return 0;
- /* Shift to get page */
- page = (int)(from >> this->page_shift);
- chipnr = (int)(from >> this->chip_shift);
+ nand_get_device(chip, mtd, FL_READING);
- /* Mask to get column */
- col = from & (mtd->oobsize - 1);
+ chip->ops.len = len;
+ chip->ops.datbuf = buf;
+ chip->ops.oobbuf = NULL;
- /* Initialize return length value */
- *retlen = 0;
+ ret = nand_do_read_ops(mtd, from, &chip->ops);
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
- *retlen = 0;
- return -EINVAL;
+ nand_release_device(mtd);
+
+ *retlen = chip->ops.retlen;
+ return ret;
+}
+
+/**
+ * nand_read_oob_std - [REPLACABLE] the most common OOB data read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
}
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd , FL_READING);
+/**
+ * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC
+ * with syndromes
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ uint8_t *buf = chip->oob_poi;
+ int length = mtd->oobsize;
+ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+ int eccsize = chip->ecc.size;
+ uint8_t *bufpoi = buf;
+ int i, toread, sndrnd = 0, pos;
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
+ for (i = 0; i < chip->ecc.steps; i++) {
+ if (sndrnd) {
+ pos = eccsize + i * (eccsize + chunk);
+ if (mtd->writesize > 512)
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
+ else
+ chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
+ } else
+ sndrnd = 1;
+ toread = min_t(int, length, chunk);
+ chip->read_buf(mtd, bufpoi, toread);
+ bufpoi += toread;
+ length -= toread;
+ }
+ if (length > 0)
+ chip->read_buf(mtd, bufpoi, length);
- /* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ return 1;
+}
+
+/**
+ * nand_write_oob_std - [REPLACABLE] the most common OOB data write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ int status = 0;
+ const uint8_t *buf = chip->oob_poi;
+ int length = mtd->oobsize;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+ chip->write_buf(mtd, buf, length);
+ /* Send command to program the OOB data */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+ status = chip->waitfunc(mtd, chip);
+
+ return status;
+}
+
+/**
+ * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC
+ * with syndrome - only for large page flash !
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+static int nand_write_oob_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+ int eccsize = chip->ecc.size, length = mtd->oobsize;
+ int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
+ const uint8_t *bufpoi = chip->oob_poi;
- /* Send the read command */
- this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
/*
- * Read the data, if we read more than one page
- * oob data, let the device transfer the data !
+ * data-ecc-data-ecc ... ecc-oob
+ * or
+ * data-pad-ecc-pad-data-pad .... ecc-pad-oob
*/
- i = 0;
- while (i < len) {
- int thislen = mtd->oobsize - col;
- thislen = min_t(int, thislen, len);
- this->read_buf(mtd, &buf[i], thislen);
- i += thislen;
-
- /* Read more ? */
- if (i < len) {
- page++;
- col = 0;
-
- /* Check, if we cross a chip boundary */
- if (!(page & this->pagemask)) {
- chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
- }
-
- /* Apply delay or wait for ready/busy pin
- * Do this before the AUTOINCR check, so no problems
- * arise if a chip which does auto increment
- * is marked as NOAUTOINCR by the board driver.
- */
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
- nand_wait_ready(mtd);
+ if (!chip->ecc.prepad && !chip->ecc.postpad) {
+ pos = steps * (eccsize + chunk);
+ steps = 0;
+ } else
+ pos = eccsize + chunk;
- /* Check, if the chip supports auto page increment
- * or if we have hit a block boundary.
- */
- if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
- /* For subsequent page reads set offset to 0 */
- this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
+ for (i = 0; i < steps; i++) {
+ if (sndcmd) {
+ if (mtd->writesize <= 512) {
+ uint32_t fill = 0xFFFFFFFF;
+
+ len = eccsize;
+ while (len > 0) {
+ int num = min_t(int, len, 4);
+ chip->write_buf(mtd, (uint8_t *)&fill,
+ num);
+ len -= num;
+ }
+ } else {
+ pos = eccsize + i * (eccsize + chunk);
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
}
- }
+ } else
+ sndcmd = 1;
+ len = min_t(int, length, chunk);
+ chip->write_buf(mtd, bufpoi, len);
+ bufpoi += len;
+ length -= len;
}
+ if (length > 0)
+ chip->write_buf(mtd, bufpoi, length);
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
- /* Return happy */
- *retlen = len;
- return 0;
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
}
/**
- * nand_read_raw - [GENERIC] Read raw data including oob into buffer
+ * nand_do_read_oob - [Intern] NAND read out-of-band
* @mtd: MTD device structure
- * @buf: temporary buffer
* @from: offset to read from
- * @len: number of bytes to read
- * @ooblen: number of oob data bytes to read
+ * @ops: oob operations description structure
*
- * Read raw data including oob into buffer
+ * NAND read out-of-band data from the spare area
*/
-int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
+static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
- struct nand_chip *this = mtd->priv;
- int page = (int) (from >> this->page_shift);
- int chip = (int) (from >> this->chip_shift);
- int sndcmd = 1;
- int cnt = 0;
- int pagesize = mtd->oobblock + mtd->oobsize;
- int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+ int page, realpage, chipnr, sndcmd = 1;
+ struct nand_chip *chip = mtd->priv;
+ int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+ int readlen = ops->len;
+ uint8_t *buf = ops->oobbuf;
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
- return -EINVAL;
- }
+ DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
+ (unsigned long long)from, readlen);
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd , FL_READING);
+ chipnr = (int)(from >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
- this->select_chip (mtd, chip);
+ /* Shift to get page */
+ realpage = (int)(from >> chip->page_shift);
+ page = realpage & chip->pagemask;
- /* Add requested oob length */
- len += ooblen;
+ chip->oob_poi = chip->buffers.oobrbuf;
- while (len) {
- if (sndcmd)
- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
- sndcmd = 0;
+ while(1) {
+ sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
+ buf = nand_transfer_oob(chip, buf, ops);
- this->read_buf (mtd, &buf[cnt], pagesize);
+ readlen -= ops->ooblen;
+ if (!readlen)
+ break;
- len -= pagesize;
- cnt += pagesize;
- page++;
+ if (!(chip->options & NAND_NO_READRDY)) {
+ /*
+ * Apply delay or wait for ready/busy pin. Do this
+ * before the AUTOINCR check, so no problems arise if a
+ * chip which does auto increment is marked as
+ * NOAUTOINCR by the board driver.
+ */
+ if (!chip->dev_ready)
+ udelay(chip->chip_delay);
+ else
+ nand_wait_ready(mtd);
+ }
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
- nand_wait_ready(mtd);
+ /* Increment page address */
+ realpage++;
- /* Check, if the chip supports auto page increment */
- if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
+ page = realpage & chip->pagemask;
+ /* Check, if we cross a chip boundary */
+ if (!page) {
+ chipnr++;
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
+ }
+
+ /* Check, if the chip supports auto page increment
+ * or if we have hit a block boundary.
+ */
+ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
sndcmd = 1;
}
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ ops->retlen = ops->len;
return 0;
}
-
/**
- * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
+ * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
* @mtd: MTD device structure
- * @fsbuf: buffer given by fs driver
- * @oobsel: out of band selection structre
- * @autoplace: 1 = place given buffer into the oob bytes
- * @numpages: number of pages to prepare
- *
- * Return:
- * 1. Filesystem buffer available and autoplacement is off,
- * return filesystem buffer
- * 2. No filesystem buffer or autoplace is off, return internal
- * buffer
- * 3. Filesystem buffer is given and autoplace selected
- * put data from fs buffer into internal buffer and
- * retrun internal buffer
- *
- * Note: The internal buffer is filled with 0xff. This must
- * be done only once, when no autoplacement happens
- * Autoplacement sets the buffer dirty flag, which
- * forces the 0xff fill before using the buffer again.
+ * @from: offset to read from
+ * @ops: oob operation description structure
*
-*/
-static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
- int autoplace, int numpages)
+ * NAND read data and/or out-of-band data
+ */
+static int nand_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
- struct nand_chip *this = mtd->priv;
- int i, len, ofs;
-
- /* Zero copy fs supplied buffer */
- if (fsbuf && !autoplace)
- return fsbuf;
-
- /* Check, if the buffer must be filled with ff again */
- if (this->oobdirty) {
- memset (this->oob_buf, 0xff,
- mtd->oobsize << (this->phys_erase_shift - this->page_shift));
- this->oobdirty = 0;
+ int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf) = NULL;
+ struct nand_chip *chip = mtd->priv;
+ int ret = -ENOTSUPP;
+
+ ops->retlen = 0;
+
+ /* Do not allow reads past end of device */
+ if ((from + ops->len) > mtd->size) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt read beyond end of device\n");
+ return -EINVAL;
}
- /* If we have no autoplacement or no fs buffer use the internal one */
- if (!autoplace || !fsbuf)
- return this->oob_buf;
-
- /* Walk through the pages and place the data */
- this->oobdirty = 1;
- ofs = 0;
- while (numpages--) {
- for (i = 0, len = 0; len < mtd->oobavail; i++) {
- int to = ofs + oobsel->oobfree[i][0];
- int num = oobsel->oobfree[i][1];
- memcpy (&this->oob_buf[to], fsbuf, num);
- len += num;
- fsbuf += num;
- }
- ofs += mtd->oobavail;
+ nand_get_device(chip, mtd, FL_READING);
+
+ switch(ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+ break;
+
+ case MTD_OOB_RAW:
+ /* Replace the read_page algorithm temporary */
+ read_page = chip->ecc.read_page;
+ chip->ecc.read_page = nand_read_page_raw;
+ break;
+
+ default:
+ goto out;
}
- return this->oob_buf;
+
+ if (!ops->datbuf)
+ ret = nand_do_read_oob(mtd, from, ops);
+ else
+ ret = nand_do_read_ops(mtd, from, ops);
+
+ if (unlikely(ops->mode == MTD_OOB_RAW))
+ chip->ecc.read_page = read_page;
+ out:
+ nand_release_device(mtd);
+ return ret;
}
-#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
/**
- * nand_write - [MTD Interface] compability function for nand_write_ecc
- * @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
- * @buf: the data to write
- *
- * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
- *
-*/
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
+ * nand_write_page_raw - [Intern] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
{
- return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
}
/**
- * nand_write_ecc - [MTD Interface] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
- * @buf: the data to write
- * @eccbuf: filesystem supplied oob data buffer
- * @oobsel: oob selection structure
- *
- * NAND write with ECC
+ * nand_write_page_swecc - {REPLACABLE] software ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
*/
-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, struct nand_oobinfo *oobsel)
+static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
{
- int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
- int autoplace = 0, numpages, totalpages;
- struct nand_chip *this = mtd->priv;
- u_char *oobbuf, *bufstart;
- int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers.ecccalc;
+ const uint8_t *p = buf;
+ int *eccpos = chip->ecc.layout->eccpos;
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ /* Software ecc calculation */
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- /* Initialize retlen, in case of early exit */
- *retlen = 0;
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
- /* Do not allow write past end of device */
- if ((to + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
- return -EINVAL;
- }
+ nand_write_page_raw(mtd, chip, buf);
+}
- /* 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;
+/**
+ * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers.ecccalc;
+ const uint8_t *p = buf;
+ int *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
}
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_WRITING);
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
- /* Calculate chipnr */
- chipnr = (int)(to >> this->chip_shift);
- /* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
- /* Check, if it is write protected */
- if (nand_check_wp(mtd))
- goto out;
+/**
+ * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ *
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
+ */
+static void nand_write_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ const uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
- /* if oobsel is NULL, use chip defaults */
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- /* Autoplace of oob data ? Use the default placement scheme */
- if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
- oobsel = this->autooob;
- autoplace = 1;
- }
- if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
- autoplace = 1;
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
- /* Setup variables and oob buffer */
- totalpages = len >> this->page_shift;
- page = (int) (to >> this->page_shift);
- /* Invalidate the page cache, if we write to the cached page */
- if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
- this->pagebuf = -1;
-
- /* Set it relative to chip */
- page &= this->pagemask;
- startpage = page;
- /* Calc number of pages we can write in one go */
- numpages = min (ppblock - (startpage & (ppblock - 1)), totalpages);
- oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages);
- bufstart = (u_char *)buf;
-
- /* Loop until all data is written */
- while (written < len) {
-
- this->data_poi = (u_char*) &buf[written];
- /* Write one page. If this is the last page to write
- * or the last page in this block, then use the
- * real pageprogram command, else select cached programming
- * if supported by the chip.
- */
- ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
- if (ret) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
- goto out;
+ if (chip->ecc.prepad) {
+ chip->write_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
}
- /* Next oob page */
- oob += mtd->oobsize;
- /* Update written bytes count */
- written += mtd->oobblock;
- if (written == len)
- goto cmp;
- /* Increment page address */
- page++;
-
- /* Have we hit a block boundary ? Then we have to verify and
- * if verify is ok, we have to setup the oob buffer for
- * the next pages.
- */
- if (!(page & (ppblock - 1))){
- int ofs;
- this->data_poi = bufstart;
- ret = nand_verify_pages (mtd, this, startpage,
- page - startpage,
- oobbuf, oobsel, chipnr, (eccbuf != NULL));
- if (ret) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
- goto out;
- }
- *retlen = written;
-
- ofs = autoplace ? mtd->oobavail : mtd->oobsize;
- if (eccbuf)
- eccbuf += (page - startpage) * ofs;
- totalpages -= page - startpage;
- numpages = min (totalpages, ppblock);
- page &= this->pagemask;
- startpage = page;
- oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel,
- autoplace, numpages);
- oob = 0;
- /* Check, if we cross a chip boundary */
- if (!page) {
- chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
- }
+ chip->ecc.calculate(mtd, p, oob);
+ chip->write_buf(mtd, oob, eccbytes);
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->write_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
}
}
- /* Verify the remaining pages */
-cmp:
- this->data_poi = bufstart;
- ret = nand_verify_pages (mtd, this, startpage, totalpages,
- oobbuf, oobsel, chipnr, (eccbuf != NULL));
- if (!ret)
- *retlen = written;
- else
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
-out:
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
-
- return ret;
+ /* Calculate remaining oob bytes */
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->write_buf(mtd, oob, i);
}
-
/**
- * nand_write_oob - [MTD Interface] NAND write out-of-band
+ * nand_write_page - [INTERNAL] write one page
* @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
+ * @chip: NAND chip descriptor
* @buf: the data to write
- *
- * NAND write out-of-band
+ * @page: page number to write
+ * @cached: cached programming
*/
-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_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached)
{
- int column, page, status, ret = -EIO, chipnr;
- struct nand_chip *this = mtd->priv;
+ int status;
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
- /* Shift to get page */
- page = (int) (to >> this->page_shift);
- chipnr = (int) (to >> this->chip_shift);
+ chip->ecc.write_page(mtd, chip, buf);
- /* Mask to get column */
- column = to & (mtd->oobsize - 1);
+ /*
+ * Cached progamming disabled for now, Not sure if its worth the
+ * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
+ */
+ cached = 0;
- /* Initialize return length value */
- *retlen = 0;
+ if (!cached || !(chip->options & NAND_CACHEPRG)) {
- /* Do not allow write past end of page */
- if ((column + len) > mtd->oobsize) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
- return -EINVAL;
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ /*
+ * See if operation failed and additional status checks are
+ * available
+ */
+ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+ status = chip->errstat(mtd, chip, FL_WRITING, status,
+ page);
+
+ if (status & NAND_STATUS_FAIL)
+ return -EIO;
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
}
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_WRITING);
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ /* Send command to read back the data */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
- /* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ if (chip->verify_buf(mtd, buf, mtd->writesize))
+ return -EIO;
+#endif
+ return 0;
+}
+
+/**
+ * nand_fill_oob - [Internal] Transfer client buffer to oob
+ * @chip: nand chip structure
+ * @oob: oob data buffer
+ * @ops: oob ops structure
+ */
+static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
+ struct mtd_oob_ops *ops)
+{
+ size_t len = ops->ooblen;
+
+ switch(ops->mode) {
+
+ case MTD_OOB_PLACE:
+ case MTD_OOB_RAW:
+ memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+ return oob + len;
+
+ case MTD_OOB_AUTO: {
+ struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ uint32_t boffs = 0, woffs = ops->ooboffs;
+ size_t bytes = 0;
+
+ for(; free->length && len; free++, len -= bytes) {
+ /* Write request not from offset 0 ? */
+ if (unlikely(woffs)) {
+ if (woffs >= free->length) {
+ woffs -= free->length;
+ continue;
+ }
+ boffs = free->offset + woffs;
+ bytes = min_t(size_t, len,
+ (free->length - woffs));
+ woffs = 0;
+ } else {
+ bytes = min_t(size_t, len, free->length);
+ boffs = free->offset;
+ }
+ memcpy(chip->oob_poi + woffs, oob, bytes);
+ oob += bytes;
+ }
+ return oob;
+ }
+ default:
+ BUG();
+ }
+ return NULL;
+}
+
+#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
+
+/**
+ * nand_do_write_ops - [Internal] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operations description structure
+ *
+ * NAND write with ECC
+ */
+static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ int chipnr, realpage, page, blockmask;
+ struct nand_chip *chip = mtd->priv;
+ uint32_t writelen = ops->len;
+ uint8_t *oob = ops->oobbuf;
+ uint8_t *buf = ops->datbuf;
+ int bytes = mtd->writesize;
+ int ret;
- /* 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);
+ ops->retlen = 0;
+
+ /* reject writes, which are not page aligned */
+ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
+ printk(KERN_NOTICE "nand_write: "
+ "Attempt to write not page aligned data\n");
+ return -EINVAL;
+ }
+
+ if (!writelen)
+ return 0;
/* Check, if it is write protected */
if (nand_check_wp(mtd))
- goto out;
+ return -EIO;
- /* Invalidate the page cache, if we write to the cached page */
- if (page == this->pagebuf)
- this->pagebuf = -1;
-
- if (NAND_MUST_PAD(this)) {
- /* Write out desired data */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
- /* prepad 0xff for partial programming */
- this->write_buf(mtd, ffchars, column);
- /* write data */
- this->write_buf(mtd, buf, len);
- /* postpad 0xff for partial programming */
- this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
- } else {
- /* Write out desired data */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
- /* write data */
- this->write_buf(mtd, buf, len);
- }
- /* Send command to program the OOB data */
- this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
+ chipnr = (int)(to >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
- status = this->waitfunc (mtd, this, FL_WRITING);
+ realpage = (int)(to >> chip->page_shift);
+ page = realpage & chip->pagemask;
+ blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
- /* See if device thinks it succeeded */
- if (status & NAND_STATUS_FAIL) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
- ret = -EIO;
- goto out;
- }
- /* Return happy */
- *retlen = len;
+ /* Invalidate the page cache, when we write to the cached page */
+ if (to <= (chip->pagebuf << chip->page_shift) &&
+ (chip->pagebuf << chip->page_shift) < (to + ops->len))
+ chip->pagebuf = -1;
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask);
+ chip->oob_poi = chip->buffers.oobwbuf;
- if (this->verify_buf(mtd, buf, len)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
- ret = -EIO;
- goto out;
+ while(1) {
+ int cached = writelen > bytes && page != blockmask;
+
+ if (unlikely(oob))
+ oob = nand_fill_oob(chip, oob, ops);
+
+ ret = nand_write_page(mtd, chip, buf, page, cached);
+ if (ret)
+ break;
+
+ writelen -= bytes;
+ if (!writelen)
+ break;
+
+ buf += bytes;
+ realpage++;
+
+ page = realpage & chip->pagemask;
+ /* Check, if we cross a chip boundary */
+ if (!page) {
+ chipnr++;
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
+ }
}
-#endif
- ret = 0;
-out:
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ if (unlikely(oob))
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+
+ ops->retlen = ops->len - writelen;
return ret;
}
-
/**
- * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
+ * nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
- * @vecs: the iovectors to write
- * @count: number of vectors
* @to: offset to write to
+ * @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
+ * @buf: the data to write
*
- * NAND write with kvec. This just calls the ecc function
+ * NAND write with ECC
*/
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
- loff_t to, size_t * retlen)
+static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const uint8_t *buf)
{
- return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));
+ struct nand_chip *chip = mtd->priv;
+ int ret;
+
+ /* Do not allow reads past end of device */
+ if ((to + len) > mtd->size)
+ return -EINVAL;
+ if (!len)
+ return 0;
+
+ nand_get_device(chip, mtd, FL_WRITING);
+
+ chip->ops.len = len;
+ chip->ops.datbuf = (uint8_t *)buf;
+ chip->ops.oobbuf = NULL;
+
+ ret = nand_do_write_ops(mtd, to, &chip->ops);
+
+ nand_release_device(mtd);
+
+ *retlen = chip->ops.retlen;
+ return ret;
}
/**
- * nand_writev_ecc - [MTD Interface] write with iovec with ecc
+ * nand_do_write_oob - [MTD Interface] NAND write out-of-band
* @mtd: MTD device structure
- * @vecs: the iovectors to write
- * @count: number of vectors
* @to: offset to write to
- * @retlen: pointer to variable to store the number of written bytes
- * @eccbuf: filesystem supplied oob data buffer
- * @oobsel: oob selection structure
+ * @ops: oob operation description structure
*
- * NAND write with iovec with ecc
+ * NAND write out-of-band
*/
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
- loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
- int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
- int oob, numpages, autoplace = 0, startpage;
- struct nand_chip *this = mtd->priv;
- int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
- u_char *oobbuf, *bufstart;
-
- /* Preset written len for early exit */
- *retlen = 0;
-
- /* Calculate total length of data */
- total_len = 0;
- for (i = 0; i < count; i++)
- total_len += (int) vecs[i].iov_len;
+ int chipnr, page, status;
+ struct nand_chip *chip = mtd->priv;
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
+ DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
+ (unsigned int)to, (int)ops->len);
/* Do not allow write past end of page */
- if ((to + total_len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
+ if ((ops->ooboffs + ops->len) > mtd->oobsize) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
+ "Attempt to write past end of page\n");
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;
- }
+ chipnr = (int)(to >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
- /* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_WRITING);
+ /* Shift to get page */
+ page = (int)(to >> chip->page_shift);
- /* Get the current chip-nr */
- chipnr = (int) (to >> this->chip_shift);
- /* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ /*
+ * 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.
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */
if (nand_check_wp(mtd))
- goto out;
+ return -EROFS;
- /* if oobsel is NULL, use chip defaults */
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
+ /* Invalidate the page cache, if we write to the cached page */
+ if (page == chip->pagebuf)
+ chip->pagebuf = -1;
- /* Autoplace of oob data ? Use the default placement scheme */
- if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
- oobsel = this->autooob;
- autoplace = 1;
- }
- if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
- autoplace = 1;
+ chip->oob_poi = chip->buffers.oobwbuf;
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+ nand_fill_oob(chip, ops->oobbuf, ops);
+ status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
- /* Setup start page */
- page = (int) (to >> this->page_shift);
- /* Invalidate the page cache, if we write to the cached page */
- if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
- this->pagebuf = -1;
+ if (status)
+ return status;
- startpage = page & this->pagemask;
+ ops->retlen = ops->len;
- /* Loop until all kvec' data has been written */
- len = 0;
- while (count) {
- /* If the given tuple is >= pagesize then
- * write it out from the iov
- */
- if ((vecs->iov_len - len) >= mtd->oobblock) {
- /* Calc number of pages we can write
- * out of this iov in one go */
- numpages = (vecs->iov_len - len) >> this->page_shift;
- /* Do not cross block boundaries */
- numpages = min (ppblock - (startpage & (ppblock - 1)), numpages);
- oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
- bufstart = (u_char *)vecs->iov_base;
- bufstart += len;
- this->data_poi = bufstart;
- oob = 0;
- for (i = 1; i <= numpages; i++) {
- /* Write one page. If this is the last page to write
- * then use the real pageprogram command, else select
- * cached programming if supported by the chip.
- */
- ret = nand_write_page (mtd, this, page & this->pagemask,
- &oobbuf[oob], oobsel, i != numpages);
- if (ret)
- goto out;
- this->data_poi += mtd->oobblock;
- len += mtd->oobblock;
- oob += mtd->oobsize;
- page++;
- }
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- } else {
- /* We must use the internal buffer, read data out of each
- * tuple until we have a full page to write
- */
- int cnt = 0;
- while (cnt < mtd->oobblock) {
- if (vecs->iov_base != NULL && vecs->iov_len)
- this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- }
- this->pagebuf = page;
- this->data_poi = this->data_buf;
- bufstart = this->data_poi;
- numpages = 1;
- oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
- ret = nand_write_page (mtd, this, page & this->pagemask,
- oobbuf, oobsel, 0);
- if (ret)
- goto out;
- page++;
- }
+ return 0;
+}
- this->data_poi = bufstart;
- ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
- if (ret)
- goto out;
+/**
+ * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
+ */
+static int nand_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf) = NULL;
+ struct nand_chip *chip = mtd->priv;
+ int ret = -ENOTSUPP;
- written += mtd->oobblock * numpages;
- /* All done ? */
- if (!count)
- break;
+ ops->retlen = 0;
- startpage = page & this->pagemask;
- /* Check, if we cross a chip boundary */
- if (!startpage) {
- chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
- }
+ /* Do not allow writes past end of device */
+ if ((to + ops->len) > mtd->size) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt read beyond end of device\n");
+ return -EINVAL;
}
- ret = 0;
-out:
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
- *retlen = written;
+ nand_get_device(chip, mtd, FL_WRITING);
+
+ switch(ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+ break;
+
+ case MTD_OOB_RAW:
+ /* Replace the write_page algorithm temporary */
+ write_page = chip->ecc.write_page;
+ chip->ecc.write_page = nand_write_page_raw;
+ break;
+
+ default:
+ goto out;
+ }
+
+ if (!ops->datbuf)
+ ret = nand_do_write_oob(mtd, to, ops);
+ else
+ ret = nand_do_write_ops(mtd, to, ops);
+
+ if (unlikely(ops->mode == MTD_OOB_RAW))
+ chip->ecc.write_page = write_page;
+ out:
+ nand_release_device(mtd);
return ret;
}
@@ -2050,12 +1816,12 @@ out:
*
* Standard erase command for NAND chips
*/
-static void single_erase_cmd (struct mtd_info *mtd, int page)
+static void single_erase_cmd(struct mtd_info *mtd, int page)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
/* Send commands to erase a block */
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
- this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
}
/**
@@ -2066,15 +1832,15 @@ static void single_erase_cmd (struct mtd_info *mtd, int page)
* AND multi block erase command function
* Erase 4 consecutive blocks
*/
-static void multi_erase_cmd (struct mtd_info *mtd, int page)
+static void multi_erase_cmd(struct mtd_info *mtd, int page)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
/* Send commands to erase a block */
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
- this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
}
/**
@@ -2084,79 +1850,82 @@ static void multi_erase_cmd (struct mtd_info *mtd, int page)
*
* Erase one ore more blocks
*/
-static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
+static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- return nand_erase_nand (mtd, instr, 0);
+ return nand_erase_nand(mtd, instr, 0);
}
#define BBT_PAGE_MASK 0xffffff3f
/**
- * nand_erase_intern - [NAND Interface] erase block(s)
+ * nand_erase_nand - [Internal] erase block(s)
* @mtd: MTD device structure
* @instr: erase instruction
* @allowbbt: allow erasing the bbt area
*
* Erase one ore more blocks
*/
-int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+ int allowbbt)
{
int page, len, status, pages_per_block, ret, chipnr;
- struct nand_chip *this = mtd->priv;
- int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
- unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
- /* It is used to see if the current page is in the same */
- /* 256 block group and the same bank as the bbt. */
+ struct nand_chip *chip = mtd->priv;
+ int rewrite_bbt[NAND_MAX_CHIPS]={0};
+ unsigned int bbt_masked_page = 0xffffffff;
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
+ DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
+ (unsigned int)instr->addr, (unsigned int)instr->len);
/* Start address must align on block boundary */
- if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
+ if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
return -EINVAL;
}
/* Length must align on block boundary */
- if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
+ if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Length not block aligned\n");
return -EINVAL;
}
/* Do not allow erase past end of device */
if ((instr->len + instr->addr) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Erase past end of device\n");
return -EINVAL;
}
instr->fail_addr = 0xffffffff;
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_ERASING);
+ nand_get_device(chip, mtd, FL_ERASING);
/* Shift to get first page */
- page = (int) (instr->addr >> this->page_shift);
- chipnr = (int) (instr->addr >> this->chip_shift);
+ page = (int)(instr->addr >> chip->page_shift);
+ chipnr = (int)(instr->addr >> chip->chip_shift);
/* Calculate pages in each block */
- pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
+ pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
/* Select the NAND device */
- this->select_chip(mtd, chipnr);
+ chip->select_chip(mtd, chipnr);
- /* Check the WP bit */
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Device is write protected!!!\n");
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
- /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
- if (this->options & BBT_AUTO_REFRESH) {
- bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
- } else {
- bbt_masked_page = 0xffffffff; /* should not match anything */
- }
+ /*
+ * If BBT requires refresh, set the BBT page mask to see if the BBT
+ * should be rewritten. Otherwise the mask is set to 0xffffffff which
+ * can not be matched. This is also done when the bbt is actually
+ * erased to avoid recusrsive updates
+ */
+ if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
+ bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
/* Loop through the pages */
len = instr->len;
@@ -2164,64 +1933,77 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
instr->state = MTD_ERASING;
while (len) {
- /* Check if we have a bad block, we do not erase bad blocks ! */
- if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
- printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
+ /*
+ * heck if we have a bad block, we do not erase bad blocks !
+ */
+ if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ chip->page_shift, 0, allowbbt)) {
+ 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;
}
- /* Invalidate the page cache, if we erase the block which contains
- the current cached page */
- if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
- this->pagebuf = -1;
+ /*
+ * Invalidate the page cache, if we erase the block which
+ * contains the current cached page
+ */
+ if (page <= chip->pagebuf && chip->pagebuf <
+ (page + pages_per_block))
+ chip->pagebuf = -1;
- this->erase_cmd (mtd, page & this->pagemask);
+ chip->erase_cmd(mtd, page & chip->pagemask);
- status = this->waitfunc (mtd, this, FL_ERASING);
+ status = chip->waitfunc(mtd, chip);
- /* See if operation failed and additional status checks are available */
- if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
- status = this->errstat(mtd, this, FL_ERASING, status, page);
- }
+ /*
+ * See if operation failed and additional status checks are
+ * available
+ */
+ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+ status = chip->errstat(mtd, chip, FL_ERASING,
+ status, page);
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
- instr->fail_addr = (page << this->page_shift);
+ instr->fail_addr = (page << chip->page_shift);
goto erase_exit;
}
- /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
- if (this->options & BBT_AUTO_REFRESH) {
- if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
- (page != this->bbt_td->pages[chipnr])) {
- rewrite_bbt[chipnr] = (page << this->page_shift);
- }
- }
+ /*
+ * If BBT requires refresh, set the BBT rewrite flag to the
+ * page being erased
+ */
+ if (bbt_masked_page != 0xffffffff &&
+ (page & BBT_PAGE_MASK) == bbt_masked_page)
+ rewrite_bbt[chipnr] = (page << chip->page_shift);
/* Increment page address and decrement length */
- len -= (1 << this->phys_erase_shift);
+ len -= (1 << chip->phys_erase_shift);
page += pages_per_block;
/* Check, if we cross a chip boundary */
- if (len && !(page & this->pagemask)) {
+ if (len && !(page & chip->pagemask)) {
chipnr++;
- this->select_chip(mtd, -1);
- this->select_chip(mtd, chipnr);
-
- /* if BBT requires refresh and BBT-PERCHIP,
- * set the BBT page mask to see if this BBT should be rewritten */
- if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
- bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
- }
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
+ /*
+ * If BBT requires refresh and BBT-PERCHIP, set the BBT
+ * page mask to see if this BBT should be rewritten
+ */
+ if (bbt_masked_page != 0xffffffff &&
+ (chip->bbt_td->options & NAND_BBT_PERCHIP))
+ bbt_masked_page = chip->bbt_td->pages[chipnr] &
+ BBT_PAGE_MASK;
}
}
instr->state = MTD_ERASE_DONE;
-erase_exit:
+ erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
/* Do call back function */
@@ -2231,16 +2013,21 @@ erase_exit:
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
- /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
- if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
- for (chipnr = 0; chipnr < this->numchips; chipnr++) {
- if (rewrite_bbt[chipnr]) {
- /* update the BBT for chip */
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
- chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
- nand_update_bbt (mtd, rewrite_bbt[chipnr]);
- }
- }
+ /*
+ * If BBT requires refresh and erase was successful, rewrite any
+ * selected bad block tables
+ */
+ if (bbt_masked_page == 0xffffffff || ret)
+ return ret;
+
+ for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
+ if (!rewrite_bbt[chipnr])
+ continue;
+ /* update the BBT for chip */
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
+ "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+ chip->bbt_td->pages[chipnr]);
+ nand_update_bbt(mtd, rewrite_bbt[chipnr]);
}
/* Return more or less happy */
@@ -2253,51 +2040,50 @@ erase_exit:
*
* Sync is actually a wait for chip ready function
*/
-static void nand_sync (struct mtd_info *mtd)
+static void nand_sync(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+ DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_SYNCING);
+ nand_get_device(chip, mtd, FL_SYNCING);
/* Release it and go back */
- nand_release_device (mtd);
+ nand_release_device(mtd);
}
-
/**
- * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
+ * nand_block_isbad - [MTD Interface] Check if block at offset is bad
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
-static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
+static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
/* Check for invalid offset */
- if (ofs > mtd->size)
+ if (offs > mtd->size)
return -EINVAL;
- return nand_block_checkbad (mtd, ofs, 1, 0);
+ return nand_block_checkbad(mtd, offs, 1, 0);
}
/**
- * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
+ * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
-static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
int ret;
- if ((ret = nand_block_isbad(mtd, ofs))) {
- /* If it was bad already, return success and do nothing. */
+ if ((ret = nand_block_isbad(mtd, ofs))) {
+ /* If it was bad already, return success and do nothing. */
if (ret > 0)
return 0;
- return ret;
- }
+ return ret;
+ }
- return this->block_markbad(mtd, ofs);
+ return chip->block_markbad(mtd, ofs);
}
/**
@@ -2306,9 +2092,9 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
*/
static int nand_suspend(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- return nand_get_device (this, mtd, FL_PM_SUSPENDED);
+ return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
}
/**
@@ -2317,373 +2103,385 @@ static int nand_suspend(struct mtd_info *mtd)
*/
static void nand_resume(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
- if (this->state == FL_PM_SUSPENDED)
+ if (chip->state == FL_PM_SUSPENDED)
nand_release_device(mtd);
else
- printk(KERN_ERR "resume() called for the chip which is not "
- "in suspended state\n");
-
+ printk(KERN_ERR "nand_resume() called for a chip which is not "
+ "in suspended state\n");
}
-
-/**
- * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: Number of chips to scan for
- *
- * This fills out all the not initialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values. Buffers are allocated if
- * they are not provided by the board driver
- *
+/*
+ * Set default functions
*/
-int nand_scan (struct mtd_info *mtd, int maxchips)
+static void nand_set_defaults(struct nand_chip *chip, int busw)
{
- int i, nand_maf_id, nand_dev_id, busw, maf_id;
- struct nand_chip *this = mtd->priv;
-
- /* Get buswidth to select the correct functions*/
- busw = this->options & NAND_BUSWIDTH_16;
-
/* check for proper chip_delay setup, set 20us if not */
- if (!this->chip_delay)
- this->chip_delay = 20;
+ if (!chip->chip_delay)
+ chip->chip_delay = 20;
/* check, if a user supplied command function given */
- if (this->cmdfunc == NULL)
- this->cmdfunc = nand_command;
+ if (chip->cmdfunc == NULL)
+ chip->cmdfunc = nand_command;
/* check, if a user supplied wait function given */
- if (this->waitfunc == NULL)
- this->waitfunc = nand_wait;
-
- if (!this->select_chip)
- this->select_chip = nand_select_chip;
- if (!this->write_byte)
- this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
- if (!this->read_byte)
- this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
- if (!this->write_word)
- this->write_word = nand_write_word;
- if (!this->read_word)
- this->read_word = nand_read_word;
- if (!this->block_bad)
- this->block_bad = nand_block_bad;
- if (!this->block_markbad)
- this->block_markbad = nand_default_block_markbad;
- if (!this->write_buf)
- this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
- if (!this->read_buf)
- this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
- if (!this->verify_buf)
- this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
- if (!this->scan_bbt)
- this->scan_bbt = nand_default_bbt;
+ if (chip->waitfunc == NULL)
+ chip->waitfunc = nand_wait;
+
+ if (!chip->select_chip)
+ chip->select_chip = nand_select_chip;
+ if (!chip->read_byte)
+ chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
+ if (!chip->read_word)
+ chip->read_word = nand_read_word;
+ if (!chip->block_bad)
+ chip->block_bad = nand_block_bad;
+ if (!chip->block_markbad)
+ chip->block_markbad = nand_default_block_markbad;
+ if (!chip->write_buf)
+ chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+ if (!chip->read_buf)
+ chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+ if (!chip->verify_buf)
+ chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
+ if (!chip->scan_bbt)
+ chip->scan_bbt = nand_default_bbt;
+
+ if (!chip->controller) {
+ chip->controller = &chip->hwcontrol;
+ spin_lock_init(&chip->controller->lock);
+ init_waitqueue_head(&chip->controller->wq);
+ }
+
+}
+
+/*
+ * Get the flash and manufacturer id and lookup if the type is supported
+ */
+static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ int busw, int *maf_id)
+{
+ struct nand_flash_dev *type = NULL;
+ int i, dev_id, maf_idx;
/* Select the device */
- this->select_chip(mtd, 0);
+ chip->select_chip(mtd, 0);
/* Send the command for reading device ID */
- this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
- nand_maf_id = this->read_byte(mtd);
- nand_dev_id = this->read_byte(mtd);
+ *maf_id = chip->read_byte(mtd);
+ dev_id = chip->read_byte(mtd);
- /* Print and store flash device information */
+ /* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+ if (dev_id == nand_flash_ids[i].id) {
+ type = &nand_flash_ids[i];
+ break;
+ }
+ }
- if (nand_dev_id != nand_flash_ids[i].id)
- continue;
+ if (!type)
+ return ERR_PTR(-ENODEV);
+
+ if (!mtd->name)
+ mtd->name = type->name;
+
+ chip->chipsize = type->chipsize << 20;
+
+ /* Newer devices have all the information in additional id bytes */
+ if (!type->pagesize) {
+ int extid;
+ /* The 3rd id byte contains non relevant data ATM */
+ extid = chip->read_byte(mtd);
+ /* The 4th id byte is the important one */
+ extid = chip->read_byte(mtd);
+ /* Calc pagesize */
+ mtd->writesize = 1024 << (extid & 0x3);
+ extid >>= 2;
+ /* Calc oobsize */
+ mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+ extid >>= 2;
+ /* Calc blocksize. Blocksize is multiples of 64KiB */
+ mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ extid >>= 2;
+ /* Get buswidth information */
+ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
- if (!mtd->name) mtd->name = nand_flash_ids[i].name;
- this->chipsize = nand_flash_ids[i].chipsize << 20;
-
- /* New devices have all the information in additional id bytes */
- if (!nand_flash_ids[i].pagesize) {
- int extid;
- /* The 3rd id byte contains non relevant data ATM */
- extid = this->read_byte(mtd);
- /* The 4th id byte is the important one */
- extid = this->read_byte(mtd);
- /* Calc pagesize */
- mtd->oobblock = 1024 << (extid & 0x3);
- extid >>= 2;
- /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
- extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
- mtd->erasesize = (64 * 1024) << (extid & 0x03);
- extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ } else {
+ /*
+ * Old devices have chip data hardcoded in the device id table
+ */
+ mtd->erasesize = type->erasesize;
+ mtd->writesize = type->pagesize;
+ mtd->oobsize = mtd->writesize / 32;
+ busw = type->options & NAND_BUSWIDTH_16;
+ }
- } else {
- /* Old devices have this data hardcoded in the
- * device id table */
- mtd->erasesize = nand_flash_ids[i].erasesize;
- mtd->oobblock = nand_flash_ids[i].pagesize;
- mtd->oobsize = mtd->oobblock / 32;
- busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
- }
+ /* Try to identify manufacturer */
+ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
+ if (nand_manuf_ids[maf_idx].id == *maf_id)
+ break;
+ }
- /* Try to identify manufacturer */
- for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
- if (nand_manuf_ids[maf_id].id == nand_maf_id)
- break;
- }
+ /*
+ * Check, if buswidth is correct. Hardware drivers should set
+ * chip correct !
+ */
+ if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+ printk(KERN_INFO "NAND device: Manufacturer ID:"
+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
+ dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
+ printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
+ (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
+ busw ? 16 : 8);
+ return ERR_PTR(-EINVAL);
+ }
- /* Check, if buswidth is correct. Hardware drivers should set
- * this correct ! */
- if (busw != (this->options & NAND_BUSWIDTH_16)) {
- 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[maf_id].name , mtd->name);
- printk (KERN_WARNING
- "NAND bus width %d instead %d bit\n",
- (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
- busw ? 16 : 8);
- this->select_chip(mtd, -1);
- return 1;
- }
+ /* Calculate the address shift from the page size */
+ chip->page_shift = ffs(mtd->writesize) - 1;
+ /* Convert chipsize to number of pages per chip -1. */
+ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
- /* Calculate the address shift from the page size */
- this->page_shift = ffs(mtd->oobblock) - 1;
- this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
- this->chip_shift = ffs(this->chipsize) - 1;
-
- /* Set the bad block position */
- this->badblockpos = mtd->oobblock > 512 ?
- NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
-
- /* Get chip options, preserve non chip based options */
- this->options &= ~NAND_CHIPOPTIONS_MSK;
- this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
- /* Set this as a default. Board drivers can override it, if neccecary */
- this->options |= NAND_NO_AUTOINCR;
- /* Check if this is a not a samsung device. Do not clear the options
- * for chips which are not having an extended id.
- */
- if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
- this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+ chip->bbt_erase_shift = chip->phys_erase_shift =
+ ffs(mtd->erasesize) - 1;
+ chip->chip_shift = ffs(chip->chipsize) - 1;
- /* Check for AND chips with 4 page planes */
- if (this->options & NAND_4PAGE_ARRAY)
- this->erase_cmd = multi_erase_cmd;
- else
- this->erase_cmd = single_erase_cmd;
+ /* Set the bad block position */
+ chip->badblockpos = mtd->writesize > 512 ?
+ NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
- /* Do not replace user supplied command function ! */
- if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
- this->cmdfunc = nand_command_lp;
+ /* Get chip options, preserve non chip based options */
+ chip->options &= ~NAND_CHIPOPTIONS_MSK;
+ chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
- 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[maf_id].name , nand_flash_ids[i].name);
- break;
- }
+ /*
+ * Set chip as a default. Board drivers can override it, if necessary
+ */
+ chip->options |= NAND_NO_AUTOINCR;
+
+ /* Check if chip is a not a samsung device. Do not clear the
+ * options for chips which are not having an extended id.
+ */
+ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
+ chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+
+ /* Check for AND chips with 4 page planes */
+ if (chip->options & NAND_4PAGE_ARRAY)
+ chip->erase_cmd = multi_erase_cmd;
+ else
+ chip->erase_cmd = single_erase_cmd;
+
+ /* Do not replace user supplied command function ! */
+ if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+ chip->cmdfunc = nand_command_lp;
+
+ printk(KERN_INFO "NAND device: Manufacturer ID:"
+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
+ nand_manuf_ids[maf_idx].name, type->name);
+
+ return type;
+}
+
+/* module_text_address() isn't exported, and it's mostly a pointless
+ test if this is a module _anyway_ -- they'd have to try _really_ hard
+ to call us from in-kernel code if the core NAND support is modular. */
+#ifdef MODULE
+#define caller_is_module() (1)
+#else
+#define caller_is_module() \
+ module_text_address((unsigned long)__builtin_return_address(0))
+#endif
- if (!nand_flash_ids[i].name) {
- printk (KERN_WARNING "No NAND device found!!!\n");
- this->select_chip(mtd, -1);
- return 1;
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
+ *
+ * This fills out all the uninitialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values.
+ * The mtd->owner field must be set to the module of the caller
+ *
+ */
+int nand_scan(struct mtd_info *mtd, int maxchips)
+{
+ int i, busw, nand_maf_id;
+ struct nand_chip *chip = mtd->priv;
+ struct nand_flash_dev *type;
+
+ /* Many callers got this wrong, so check for it for a while... */
+ if (!mtd->owner && caller_is_module()) {
+ printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
+ BUG();
}
- for (i=1; i < maxchips; i++) {
- this->select_chip(mtd, i);
+ /* Get buswidth to select the correct functions */
+ busw = chip->options & NAND_BUSWIDTH_16;
+ /* Set the default functions */
+ nand_set_defaults(chip, busw);
- /* Send the command for reading device ID */
- this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
+ /* Read the flash type */
+ type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
+
+ if (IS_ERR(type)) {
+ printk(KERN_WARNING "No NAND device found!!!\n");
+ chip->select_chip(mtd, -1);
+ return PTR_ERR(type);
+ }
+ /* Check for a chip array */
+ for (i = 1; i < maxchips; i++) {
+ chip->select_chip(mtd, i);
+ /* Send the command for reading device ID */
+ chip->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))
+ if (nand_maf_id != chip->read_byte(mtd) ||
+ type->id != chip->read_byte(mtd))
break;
}
if (i > 1)
printk(KERN_INFO "%d NAND chips detected\n", i);
- /* Allocate buffers, if neccecary */
- if (!this->oob_buf) {
- size_t len;
- len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
- this->oob_buf = kmalloc (len, GFP_KERNEL);
- if (!this->oob_buf) {
- printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
- return -ENOMEM;
- }
- this->options |= NAND_OOBBUF_ALLOC;
- }
+ /* Store the number of chips and calc total size for mtd */
+ chip->numchips = i;
+ mtd->size = i * chip->chipsize;
- if (!this->data_buf) {
- size_t len;
- len = mtd->oobblock + mtd->oobsize;
- this->data_buf = kmalloc (len, GFP_KERNEL);
- if (!this->data_buf) {
- if (this->options & NAND_OOBBUF_ALLOC)
- kfree (this->oob_buf);
- printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
- return -ENOMEM;
- }
- this->options |= NAND_DATABUF_ALLOC;
- }
+ /* Preset the internal oob write buffer */
+ memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize);
- /* Store the number of chips and calc total size for mtd */
- this->numchips = i;
- mtd->size = i * this->chipsize;
- /* Convert chipsize to number of pages per chip -1. */
- this->pagemask = (this->chipsize >> this->page_shift) - 1;
- /* Preset the internal oob buffer */
- memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
-
- /* If no default placement scheme is given, select an
- * appropriate one */
- if (!this->autooob) {
- /* Select the appropriate default oob placement scheme for
- * placement agnostic filesystems */
+ /*
+ * If no default placement scheme is given, select an appropriate one
+ */
+ if (!chip->ecc.layout) {
switch (mtd->oobsize) {
case 8:
- this->autooob = &nand_oob_8;
+ chip->ecc.layout = &nand_oob_8;
break;
case 16:
- this->autooob = &nand_oob_16;
+ chip->ecc.layout = &nand_oob_16;
break;
case 64:
- this->autooob = &nand_oob_64;
+ chip->ecc.layout = &nand_oob_64;
break;
default:
- printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
+ printk(KERN_WARNING "No oob scheme defined for "
+ "oobsize %d\n", mtd->oobsize);
BUG();
}
}
- /* The number of bytes available for the filesystem to place fs dependend
- * oob data */
- mtd->oobavail = 0;
- for (i = 0; this->autooob->oobfree[i][1]; i++)
- mtd->oobavail += this->autooob->oobfree[i][1];
-
/*
- * check ECC mode, default to software
- * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
- * fallback to software ECC
- */
- this->eccsize = 256; /* set default eccsize */
- this->eccbytes = 3;
-
- switch (this->eccmode) {
- case NAND_ECC_HW12_2048:
- if (mtd->oobblock < 2048) {
- printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
- mtd->oobblock);
- this->eccmode = NAND_ECC_SOFT;
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- } else
- this->eccsize = 2048;
- break;
-
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW6_512:
- case NAND_ECC_HW8_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;
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- } else
- this->eccsize = 512; /* set eccsize to 512 */
- break;
+ * check ECC mode, default to software if 3byte/512byte hardware ECC is
+ * selected and we have 256 byte pagesize fallback to software ECC
+ */
+ switch (chip->ecc.mode) {
+ case NAND_ECC_HW:
+ /* Use standard hwecc read page function ? */
+ if (!chip->ecc.read_page)
+ chip->ecc.read_page = nand_read_page_hwecc;
+ if (!chip->ecc.write_page)
+ chip->ecc.write_page = nand_write_page_hwecc;
+ if (!chip->ecc.read_oob)
+ chip->ecc.read_oob = nand_read_oob_std;
+ if (!chip->ecc.write_oob)
+ chip->ecc.write_oob = nand_write_oob_std;
+
+ case NAND_ECC_HW_SYNDROME:
+ if (!chip->ecc.calculate || !chip->ecc.correct ||
+ !chip->ecc.hwctl) {
+ printk(KERN_WARNING "No ECC functions supplied, "
+ "Hardware ECC not possible\n");
+ BUG();
+ }
+ /* Use standard syndrome read/write page function ? */
+ if (!chip->ecc.read_page)
+ chip->ecc.read_page = nand_read_page_syndrome;
+ if (!chip->ecc.write_page)
+ chip->ecc.write_page = nand_write_page_syndrome;
+ if (!chip->ecc.read_oob)
+ chip->ecc.read_oob = nand_read_oob_syndrome;
+ if (!chip->ecc.write_oob)
+ chip->ecc.write_oob = nand_write_oob_syndrome;
+
+ if (mtd->writesize >= chip->ecc.size)
+ break;
+ printk(KERN_WARNING "%d byte HW ECC not possible on "
+ "%d byte page size, fallback to SW ECC\n",
+ chip->ecc.size, mtd->writesize);
+ chip->ecc.mode = NAND_ECC_SOFT;
- case NAND_ECC_HW3_256:
+ case NAND_ECC_SOFT:
+ chip->ecc.calculate = nand_calculate_ecc;
+ chip->ecc.correct = nand_correct_data;
+ chip->ecc.read_page = nand_read_page_swecc;
+ chip->ecc.write_page = nand_write_page_swecc;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.write_oob = nand_write_oob_std;
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
break;
case NAND_ECC_NONE:
- printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
- this->eccmode = NAND_ECC_NONE;
+ printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
+ "This is not recommended !!\n");
+ chip->ecc.read_page = nand_read_page_raw;
+ chip->ecc.write_page = nand_write_page_raw;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.write_oob = nand_write_oob_std;
+ chip->ecc.size = mtd->writesize;
+ chip->ecc.bytes = 0;
break;
-
- case NAND_ECC_SOFT:
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- break;
-
default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
- }
-
- /* Check hardware ecc function availability and adjust number of ecc bytes per
- * calculation step
- */
- switch (this->eccmode) {
- case NAND_ECC_HW12_2048:
- this->eccbytes += 4;
- case NAND_ECC_HW8_512:
- this->eccbytes += 2;
- case NAND_ECC_HW6_512:
- this->eccbytes += 3;
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW3_256:
- if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
- break;
- printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+ printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
+ chip->ecc.mode);
BUG();
}
- mtd->eccsize = this->eccsize;
-
- /* Set the number of read / write steps for one page to ensure ECC generation */
- switch (this->eccmode) {
- case NAND_ECC_HW12_2048:
- this->eccsteps = mtd->oobblock / 2048;
- break;
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW6_512:
- case NAND_ECC_HW8_512:
- this->eccsteps = mtd->oobblock / 512;
- break;
- case NAND_ECC_HW3_256:
- case NAND_ECC_SOFT:
- this->eccsteps = mtd->oobblock / 256;
- break;
+ /*
+ * The number of bytes available for a client to place data into
+ * the out of band area
+ */
+ chip->ecc.layout->oobavail = 0;
+ for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
+ chip->ecc.layout->oobavail +=
+ chip->ecc.layout->oobfree[i].length;
- case NAND_ECC_NONE:
- this->eccsteps = 1;
- break;
+ /*
+ * Set the number of read / write steps for one page depending on ECC
+ * mode
+ */
+ chip->ecc.steps = mtd->writesize / chip->ecc.size;
+ if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
+ printk(KERN_WARNING "Invalid ecc parameters\n");
+ BUG();
}
+ chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
- /* Initialize state, waitqueue and spinlock */
- this->state = FL_READY;
- init_waitqueue_head (&this->wq);
- spin_lock_init (&this->chip_lock);
+ /* Initialize state */
+ chip->state = FL_READY;
/* De-select the device */
- this->select_chip(mtd, -1);
+ chip->select_chip(mtd, -1);
/* Invalidate the pagebuffer reference */
- this->pagebuf = -1;
+ chip->pagebuf = -1;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+ mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
- mtd->read_ecc = nand_read_ecc;
- mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
- mtd->readv = NULL;
- mtd->writev = nand_writev;
- mtd->writev_ecc = nand_writev_ecc;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
@@ -2692,47 +2490,38 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
- /* and make the autooob the default one */
- memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
-
- mtd->owner = THIS_MODULE;
+ /* propagate ecc.layout to mtd_info */
+ mtd->ecclayout = chip->ecc.layout;
/* Check, if we should skip the bad block table scan */
- if (this->options & NAND_SKIP_BBTSCAN)
+ if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
/* Build bad block table */
- return this->scan_bbt (mtd);
+ return chip->scan_bbt(mtd);
}
/**
* nand_release - [NAND Interface] Free resources held by the NAND device
* @mtd: MTD device structure
*/
-void nand_release (struct mtd_info *mtd)
+void nand_release(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *chip = mtd->priv;
#ifdef CONFIG_MTD_PARTITIONS
/* Deregister partitions */
- del_mtd_partitions (mtd);
+ del_mtd_partitions(mtd);
#endif
/* Deregister the device */
- del_mtd_device (mtd);
+ del_mtd_device(mtd);
/* Free bad block table memory */
- kfree (this->bbt);
- /* Buffer allocated by nand_scan ? */
- if (this->options & NAND_OOBBUF_ALLOC)
- kfree (this->oob_buf);
- /* Buffer allocated by nand_scan ? */
- if (this->options & NAND_DATABUF_ALLOC)
- kfree (this->data_buf);
+ kfree(chip->bbt);
}
-EXPORT_SYMBOL_GPL (nand_scan);
-EXPORT_SYMBOL_GPL (nand_release);
-
+EXPORT_SYMBOL_GPL(nand_scan);
+EXPORT_SYMBOL_GPL(nand_release);
static int __init nand_base_init(void)
{
@@ -2748,6 +2537,6 @@ static void __exit nand_base_exit(void)
module_init(nand_base_init);
module_exit(nand_base_exit);
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION ("Generic NAND flash driver code");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Generic NAND flash driver code");
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index ca286999fe08..a612c4ea8194 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -48,7 +48,7 @@
*
* Following assumptions are made:
* - bbts start at a page boundary, if autolocated on a block boundary
- * - the space neccecary for a bbt in FLASH does not exceed a block boundary
+ * - the space necessary for a bbt in FLASH does not exceed a block boundary
*
*/
@@ -60,7 +60,7 @@
#include <linux/mtd/compatmac.h>
#include <linux/bitops.h>
#include <linux/delay.h>
-
+#include <linux/vmalloc.h>
/**
* check_pattern - [GENERIC] check if a pattern is in the buffer
@@ -75,7 +75,7 @@
* pattern area contain 0xff
*
*/
-static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
int i, end = 0;
uint8_t *p = buf;
@@ -116,7 +116,7 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
* no optional empty check
*
*/
-static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
+static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
{
int i;
uint8_t *p = buf;
@@ -142,8 +142,8 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
* Read the bad block table starting from page.
*
*/
-static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
- int bits, int offs, int reserved_block_code)
+static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
+ int bits, int offs, int reserved_block_code)
{
int res, i, j, act = 0;
struct nand_chip *this = mtd->priv;
@@ -152,17 +152,17 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
uint8_t msk = (uint8_t) ((1 << bits) - 1);
totlen = (num * bits) >> 3;
- from = ((loff_t)page) << this->page_shift;
+ from = ((loff_t) page) << this->page_shift;
while (totlen) {
- len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
- res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
+ len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+ res = mtd->read(mtd, from, len, &retlen, buf);
if (res < 0) {
if (retlen != len) {
- printk (KERN_INFO "nand_bbt: Error reading bad block table\n");
+ printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
return res;
}
- printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
+ printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
}
/* Analyse data */
@@ -172,22 +172,23 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
uint8_t tmp = (dat >> j) & msk;
if (tmp == msk)
continue;
- if (reserved_block_code &&
- (tmp == reserved_block_code)) {
- printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ if (reserved_block_code && (tmp == reserved_block_code)) {
+ printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
+ ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
+ mtd->ecc_stats.bbtblocks++;
continue;
}
/* Leave it for now, if its matured we can move this
* message to MTD_DEBUG_LEVEL0 */
- printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
+ ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
/* Factory marked bad or worn out ? */
if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
else
this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
+ mtd->ecc_stats.badblocks++;
}
}
totlen -= len;
@@ -207,7 +208,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
* Read the bad block table for all chips starting at a given page
* We assume that the bbt bits are in consecutive order.
*/
-static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
{
struct nand_chip *this = mtd->priv;
int res = 0, i;
@@ -231,6 +232,42 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
return 0;
}
+/*
+ * Scan read raw data from flash
+ */
+static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+ size_t len)
+{
+ struct mtd_oob_ops ops;
+
+ ops.mode = MTD_OOB_RAW;
+ ops.ooboffs = 0;
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = buf;
+ ops.datbuf = buf;
+ ops.len = len;
+
+ return mtd->read_oob(mtd, offs, &ops);
+}
+
+/*
+ * Scan write data with oob to flash
+ */
+static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+ uint8_t *buf, uint8_t *oob)
+{
+ struct mtd_oob_ops ops;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = 0;
+ ops.ooblen = mtd->oobsize;
+ ops.datbuf = buf;
+ ops.oobbuf = oob;
+ ops.len = len;
+
+ return mtd->write_oob(mtd, offs, &ops);
+}
+
/**
* read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
* @mtd: MTD device structure
@@ -242,28 +279,85 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
* We assume that the bbt bits are in consecutive order.
*
*/
-static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
- struct nand_bbt_descr *md)
+static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
struct nand_chip *this = mtd->priv;
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
- td->version[0] = buf[mtd->oobblock + td->veroffs];
- printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
+ scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
+ mtd->writesize);
+ td->version[0] = buf[mtd->writesize + td->veroffs];
+ printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
+ td->pages[0], td->version[0]);
}
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
- md->version[0] = buf[mtd->oobblock + md->veroffs];
- printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
+ scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
+ mtd->writesize);
+ md->version[0] = buf[mtd->writesize + md->veroffs];
+ printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
+ md->pages[0], md->version[0]);
}
-
return 1;
}
+/*
+ * Scan a given block full
+ */
+static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+ loff_t offs, uint8_t *buf, size_t readlen,
+ int scanlen, int len)
+{
+ int ret, j;
+
+ ret = scan_read_raw(mtd, buf, offs, readlen);
+ if (ret)
+ return ret;
+
+ for (j = 0; j < len; j++, buf += scanlen) {
+ if (check_pattern(buf, scanlen, mtd->writesize, bd))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Scan a given block partially
+ */
+static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+ loff_t offs, uint8_t *buf, int len)
+{
+ struct mtd_oob_ops ops;
+ int j, ret;
+
+ ops.len = mtd->oobsize;
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = buf;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_PLACE;
+
+ for (j = 0; j < len; j++) {
+ /*
+ * Read the full oob until read_oob is fixed to
+ * handle single byte reads for 16 bit
+ * buswidth
+ */
+ ret = mtd->read_oob(mtd, offs, &ops);
+ if (ret)
+ return ret;
+
+ if (check_short_pattern(buf, bd))
+ return 1;
+
+ offs += mtd->writesize;
+ }
+ return 0;
+}
+
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
* @mtd: MTD device structure
@@ -275,15 +369,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
* Create a bad block table by scanning the device
* for the given good/bad block identify pattern
*/
-static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
- int i, j, numblocks, len, scanlen;
+ int i, numblocks, len, scanlen;
int startblock;
loff_t from;
- size_t readlen, ooblen;
+ size_t readlen;
- printk (KERN_INFO "Scanning device for bad blocks\n");
+ printk(KERN_INFO "Scanning device for bad blocks\n");
if (bd->options & NAND_BBT_SCANALLPAGES)
len = 1 << (this->bbt_erase_shift - this->page_shift);
@@ -296,25 +391,24 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
/* We need only read few bytes from the OOB area */
- scanlen = ooblen = 0;
+ scanlen = 0;
readlen = bd->len;
} else {
/* Full page content should be read */
- scanlen = mtd->oobblock + mtd->oobsize;
- readlen = len * mtd->oobblock;
- ooblen = len * mtd->oobsize;
+ scanlen = mtd->writesize + mtd->oobsize;
+ readlen = len * mtd->writesize;
}
if (chip == -1) {
- /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
- * makes shifting and masking less painful */
+ /* Note that numblocks is 2 * (real numblocks) here, see i+=2
+ * below as it makes shifting and masking less painful */
numblocks = mtd->size >> (this->bbt_erase_shift - 1);
startblock = 0;
from = 0;
} else {
if (chip >= this->numchips) {
- printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
- chip + 1, this->numchips);
+ printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
+ chip + 1, this->numchips);
return -EINVAL;
}
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
@@ -326,36 +420,22 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (i = startblock; i < numblocks;) {
int ret;
- if (bd->options & NAND_BBT_SCANEMPTY)
- if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
- return ret;
-
- for (j = 0; j < len; j++) {
- if (!(bd->options & NAND_BBT_SCANEMPTY)) {
- size_t retlen;
-
- /* Read the full oob until read_oob is fixed to
- * handle single byte reads for 16 bit buswidth */
- ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
- mtd->oobsize, &retlen, buf);
- if (ret)
- return ret;
-
- if (check_short_pattern (buf, bd)) {
- this->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int) from);
- break;
- }
- } else {
- if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
- this->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int) from);
- break;
- }
- }
+ if (bd->options & NAND_BBT_SCANALLPAGES)
+ ret = scan_block_full(mtd, bd, from, buf, readlen,
+ scanlen, len);
+ else
+ ret = scan_block_fast(mtd, bd, from, buf, len);
+
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+ printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+ i >> 1, (unsigned int)from);
+ mtd->ecc_stats.badblocks++;
}
+
i += 2;
from += (1 << this->bbt_erase_shift);
}
@@ -374,22 +454,23 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
* block.
* If the option NAND_BBT_PERCHIP is given, each chip is searched
* for a bbt, which contains the bad block information of this chip.
- * This is neccecary to provide support for certain DOC devices.
+ * This is necessary to provide support for certain DOC devices.
*
* The bbt ident pattern resides in the oob area of the first page
* in a block.
*/
-static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
{
struct nand_chip *this = mtd->priv;
int i, chips;
int bits, startblock, block, dir;
- int scanlen = mtd->oobblock + mtd->oobsize;
+ int scanlen = mtd->writesize + mtd->oobsize;
int bbtblocks;
+ int blocktopage = this->bbt_erase_shift - this->page_shift;
/* Search direction top -> down ? */
if (td->options & NAND_BBT_LASTBLOCK) {
- startblock = (mtd->size >> this->bbt_erase_shift) -1;
+ startblock = (mtd->size >> this->bbt_erase_shift) - 1;
dir = -1;
} else {
startblock = 0;
@@ -415,13 +496,16 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
td->pages[i] = -1;
/* Scan the maximum number of blocks */
for (block = 0; block < td->maxblocks; block++) {
+
int actblock = startblock + dir * block;
+ loff_t offs = actblock << this->bbt_erase_shift;
+
/* Read first page */
- nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
- if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
- td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
+ scan_read_raw(mtd, buf, offs, mtd->writesize);
+ if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
+ td->pages[i] = actblock << blocktopage;
if (td->options & NAND_BBT_VERSION) {
- td->version[i] = buf[mtd->oobblock + td->veroffs];
+ td->version[i] = buf[mtd->writesize + td->veroffs];
}
break;
}
@@ -431,9 +515,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
/* Check, if we found a bbt for each requested chip */
for (i = 0; i < chips; i++) {
if (td->pages[i] == -1)
- printk (KERN_WARNING "Bad block table not found for chip %d\n", i);
+ printk(KERN_WARNING "Bad block table not found for chip %d\n", i);
else
- printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
+ printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i],
+ td->version[i]);
}
return 0;
}
@@ -447,21 +532,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
*
* Search and read the bad block table(s)
*/
-static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
- struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
/* Search the primary table */
- search_bbt (mtd, buf, td);
+ search_bbt(mtd, buf, td);
/* Search the mirror table */
if (md)
- search_bbt (mtd, buf, md);
+ search_bbt(mtd, buf, md);
/* Force result check */
return 1;
}
-
/**
* write_bbt - [GENERIC] (Re)write the bad block table
*
@@ -474,25 +557,31 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
* (Re)write the bad block table
*
*/
-static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
- struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
+static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md,
+ int chipsel)
{
struct nand_chip *this = mtd->priv;
- struct nand_oobinfo oobinfo;
struct erase_info einfo;
int i, j, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
- int nrchips, bbtoffs, pageoffs;
+ int nrchips, bbtoffs, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
size_t retlen, len = 0;
loff_t to;
+ struct mtd_oob_ops ops;
+
+ ops.ooblen = mtd->oobsize;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_PLACE;
if (!rcode)
rcode = 0xff;
/* Write bad block table per chip rather than per device ? */
if (td->options & NAND_BBT_PERCHIP) {
- numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
+ numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
/* Full device write or specific chip ? */
if (chipsel == -1) {
nrchips = this->numchips;
@@ -501,7 +590,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
chip = chipsel;
}
} else {
- numblocks = (int) (mtd->size >> this->bbt_erase_shift);
+ numblocks = (int)(mtd->size >> this->bbt_erase_shift);
nrchips = 1;
}
@@ -530,27 +619,38 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
- switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
+ switch ((this->bbt[block >> 2] >>
+ (2 * (block & 0x03))) & 0x03) {
case 0x01:
case 0x03:
continue;
}
- page = block << (this->bbt_erase_shift - this->page_shift);
+ page = block <<
+ (this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
goto write;
}
- printk (KERN_ERR "No space left to write bad block table\n");
+ printk(KERN_ERR "No space left to write bad block table\n");
return -ENOSPC;
-write:
+ write:
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
+ msk[2] = ~rcode;
switch (bits) {
- case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
- case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
- case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
- case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
+ case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
+ msk[3] = 0x01;
+ break;
+ case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
+ msk[3] = 0x03;
+ break;
+ case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
+ msk[3] = 0x0f;
+ break;
+ case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
+ msk[3] = 0xff;
+ break;
default: return -EINVAL;
}
@@ -558,82 +658,92 @@ write:
to = ((loff_t) page) << this->page_shift;
- memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
- oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-
/* Must we save the block contents ? */
if (td->options & NAND_BBT_SAVECONTENT) {
/* Make it block aligned */
to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
len = 1 << this->bbt_erase_shift;
- res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
+ res = mtd->read(mtd, to, len, &retlen, buf);
if (res < 0) {
if (retlen != len) {
- printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
+ printk(KERN_INFO "nand_bbt: Error "
+ "reading block for writing "
+ "the bad block table\n");
return res;
}
- printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
+ printk(KERN_WARNING "nand_bbt: ECC error "
+ "while reading block for writing "
+ "bad block table\n");
}
+ /* Read oob data */
+ ops.len = (len >> this->page_shift) * mtd->oobsize;
+ ops.oobbuf = &buf[len];
+ res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
+ if (res < 0 || ops.retlen != ops.len)
+ goto outerr;
+
/* Calc the byte offset in the buffer */
pageoffs = page - (int)(to >> this->page_shift);
offs = pageoffs << this->page_shift;
/* Preset the bbt area with 0xff */
- memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
- /* Preset the bbt's oob area with 0xff */
- memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
- ((len >> this->page_shift) - pageoffs) * mtd->oobsize);
- if (td->options & NAND_BBT_VERSION) {
- buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
- }
+ memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
+ ooboffs = len + (pageoffs * mtd->oobsize);
+
} else {
/* Calc length */
len = (size_t) (numblocks >> sft);
/* Make it page aligned ! */
- len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
+ len = (len + (mtd->writesize - 1)) &
+ ~(mtd->writesize - 1);
/* Preset the buffer with 0xff */
- memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
+ memset(buf, 0xff, len +
+ (len >> this->page_shift)* mtd->oobsize);
offs = 0;
+ ooboffs = len;
/* Pattern is located in oob area of first page */
- memcpy (&buf[len + td->offs], td->pattern, td->len);
- if (td->options & NAND_BBT_VERSION) {
- buf[len + td->veroffs] = td->version[chip];
- }
+ memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
}
+ if (td->options & NAND_BBT_VERSION)
+ buf[ooboffs + td->veroffs] = td->version[chip];
+
/* walk through the memory table */
- for (i = 0; i < numblocks; ) {
+ for (i = 0; i < numblocks;) {
uint8_t dat;
dat = this->bbt[bbtoffs + (i >> 2)];
- for (j = 0; j < 4; j++ , i++) {
+ for (j = 0; j < 4; j++, i++) {
int sftcnt = (i << (3 - sft)) & sftmsk;
/* Do not store the reserved bbt blocks ! */
- buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
+ buf[offs + (i >> sft)] &=
+ ~(msk[dat & 0x03] << sftcnt);
dat >>= 2;
}
}
- memset (&einfo, 0, sizeof (einfo));
+ memset(&einfo, 0, sizeof(einfo));
einfo.mtd = mtd;
- einfo.addr = (unsigned long) to;
+ einfo.addr = (unsigned long)to;
einfo.len = 1 << this->bbt_erase_shift;
- res = nand_erase_nand (mtd, &einfo, 1);
- if (res < 0) {
- printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
- return res;
- }
+ res = nand_erase_nand(mtd, &einfo, 1);
+ if (res < 0)
+ goto outerr;
- res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
- if (res < 0) {
- printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
- return res;
- }
- printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
- (unsigned int) to, td->version[chip]);
+ res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
+ if (res < 0)
+ goto outerr;
+
+ printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
+ "0x%02X\n", (unsigned int)to, td->version[chip]);
/* Mark it as used */
td->pages[chip] = page;
}
return 0;
+
+ outerr:
+ printk(KERN_WARNING
+ "nand_bbt: Error while writing bad block table %d\n", res);
+ return res;
}
/**
@@ -644,27 +754,27 @@ write:
* The function creates a memory based bbt by scanning the device
* for manufacturer / software marked good / bad blocks
*/
-static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
bd->options &= ~NAND_BBT_SCANEMPTY;
- return create_bbt (mtd, this->data_buf, bd, -1);
+ return create_bbt(mtd, this->buffers.databuf, bd, -1);
}
/**
- * check_create - [GENERIC] create and write bbt(s) if neccecary
+ * check_create - [GENERIC] create and write bbt(s) if necessary
* @mtd: MTD device structure
* @buf: temporary buffer
* @bd: descriptor for the good/bad block search pattern
*
* The function checks the results of the previous call to read_bbt
- * and creates / updates the bbt(s) if neccecary
- * Creation is neccecary if no bbt was found for the chip/device
- * Update is neccecary if one of the tables is missing or the
+ * and creates / updates the bbt(s) if necessary
+ * Creation is necessary if no bbt was found for the chip/device
+ * Update is necessary if one of the tables is missing or the
* version nr. of one table is less than the other
*/
-static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
{
int i, chips, writeops, chipsel, res;
struct nand_chip *this = mtd->priv;
@@ -732,35 +842,35 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
rd = td;
goto writecheck;
}
-create:
+ create:
/* Create the bad block table by scanning the device ? */
if (!(td->options & NAND_BBT_CREATE))
continue;
/* Create the table in memory by scanning the chip(s) */
- create_bbt (mtd, buf, bd, chipsel);
+ create_bbt(mtd, buf, bd, chipsel);
td->version[i] = 1;
if (md)
md->version[i] = 1;
-writecheck:
+ writecheck:
/* read back first ? */
if (rd)
- read_abs_bbt (mtd, buf, rd, chipsel);
+ read_abs_bbt(mtd, buf, rd, chipsel);
/* If they weren't versioned, read both. */
if (rd2)
- read_abs_bbt (mtd, buf, rd2, chipsel);
+ read_abs_bbt(mtd, buf, rd2, chipsel);
/* Write the bad block table to the device ? */
if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
- res = write_bbt (mtd, buf, td, md, chipsel);
+ res = write_bbt(mtd, buf, td, md, chipsel);
if (res < 0)
return res;
}
/* Write the mirror bad block table to the device ? */
if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
- res = write_bbt (mtd, buf, md, td, chipsel);
+ res = write_bbt(mtd, buf, md, td, chipsel);
if (res < 0)
return res;
}
@@ -777,7 +887,7 @@ writecheck:
* accidental erasures / writes. The regions are identified by
* the mark 0x02.
*/
-static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
+static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
{
struct nand_chip *this = mtd->priv;
int i, j, chips, block, nrblocks, update;
@@ -795,7 +905,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
for (i = 0; i < chips; i++) {
if ((td->options & NAND_BBT_ABSPAGE) ||
!(td->options & NAND_BBT_WRITE)) {
- if (td->pages[i] == -1) continue;
+ if (td->pages[i] == -1)
+ continue;
block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
block <<= 1;
oldval = this->bbt[(block >> 3)];
@@ -815,7 +926,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
oldval = this->bbt[(block >> 3)];
newval = oldval | (0x2 << (block & 0x06));
this->bbt[(block >> 3)] = newval;
- if (oldval != newval) update = 1;
+ if (oldval != newval)
+ update = 1;
block += 2;
}
/* If we want reserved blocks to be recorded to flash, and some
@@ -840,7 +952,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
* by calling the nand_free_bbt function.
*
*/
-int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
int len, res = 0;
@@ -850,21 +962,21 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
len = mtd->size >> (this->bbt_erase_shift + 2);
/* Allocate memory (2bit per block) */
- this->bbt = kmalloc (len, GFP_KERNEL);
+ this->bbt = kmalloc(len, GFP_KERNEL);
if (!this->bbt) {
- printk (KERN_ERR "nand_scan_bbt: Out of memory\n");
+ printk(KERN_ERR "nand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
/* Clear the memory bad block table */
- memset (this->bbt, 0x00, len);
+ memset(this->bbt, 0x00, len);
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
*/
if (!td) {
if ((res = nand_memory_bbt(mtd, bd))) {
- printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
- kfree (this->bbt);
+ printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+ kfree(this->bbt);
this->bbt = NULL;
}
return res;
@@ -873,35 +985,34 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
- buf = kmalloc (len, GFP_KERNEL);
+ buf = vmalloc(len);
if (!buf) {
- printk (KERN_ERR "nand_bbt: Out of memory\n");
- kfree (this->bbt);
+ printk(KERN_ERR "nand_bbt: Out of memory\n");
+ kfree(this->bbt);
this->bbt = NULL;
return -ENOMEM;
}
/* Is the bbt at a given page ? */
if (td->options & NAND_BBT_ABSPAGE) {
- res = read_abs_bbts (mtd, buf, td, md);
+ res = read_abs_bbts(mtd, buf, td, md);
} else {
/* Search the bad block table using a pattern in oob */
- res = search_read_bbts (mtd, buf, td, md);
+ res = search_read_bbts(mtd, buf, td, md);
}
if (res)
- res = check_create (mtd, buf, bd);
+ res = check_create(mtd, buf, bd);
/* Prevent the bbt regions from erasing / writing */
- mark_bbt_region (mtd, td);
+ mark_bbt_region(mtd, td);
if (md)
- mark_bbt_region (mtd, md);
+ mark_bbt_region(mtd, md);
- kfree (buf);
+ vfree(buf);
return res;
}
-
/**
* nand_update_bbt - [NAND Interface] update bad block table(s)
* @mtd: MTD device structure
@@ -909,7 +1020,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
*
* The function updates the bad block table(s)
*/
-int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
+int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
{
struct nand_chip *this = mtd->priv;
int len, res = 0, writeops = 0;
@@ -925,9 +1036,9 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
- buf = kmalloc (len, GFP_KERNEL);
+ buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
- printk (KERN_ERR "nand_update_bbt: Out of memory\n");
+ printk(KERN_ERR "nand_update_bbt: Out of memory\n");
return -ENOMEM;
}
@@ -935,7 +1046,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
/* Do we have a bbt per chip ? */
if (td->options & NAND_BBT_PERCHIP) {
- chip = (int) (offs >> this->chip_shift);
+ chip = (int)(offs >> this->chip_shift);
chipsel = chip;
} else {
chip = 0;
@@ -948,17 +1059,17 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
/* Write the bad block table to the device ? */
if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
- res = write_bbt (mtd, buf, td, md, chipsel);
+ res = write_bbt(mtd, buf, td, md, chipsel);
if (res < 0)
goto out;
}
/* Write the mirror bad block table to the device ? */
if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
- res = write_bbt (mtd, buf, md, td, chipsel);
+ res = write_bbt(mtd, buf, md, td, chipsel);
}
-out:
- kfree (buf);
+ out:
+ kfree(buf);
return res;
}
@@ -981,14 +1092,14 @@ static struct nand_bbt_descr largepage_memorybased = {
};
static struct nand_bbt_descr smallpage_flashbased = {
- .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+ .options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
};
static struct nand_bbt_descr largepage_flashbased = {
- .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+ .options = NAND_BBT_SCAN2NDPAGE,
.offs = 0,
.len = 2,
.pattern = scan_ff_pattern
@@ -1036,7 +1147,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
* support for the device and calls the nand_scan_bbt function
*
*/
-int nand_default_bbt (struct mtd_info *mtd)
+int nand_default_bbt(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
@@ -1046,7 +1157,7 @@ int nand_default_bbt (struct mtd_info *mtd)
* of the good / bad information, so we _must_ store
* this information in a good / bad table during
* startup
- */
+ */
if (this->options & NAND_IS_AND) {
/* Use the default pattern descriptors */
if (!this->bbt_td) {
@@ -1054,10 +1165,9 @@ int nand_default_bbt (struct mtd_info *mtd)
this->bbt_md = &bbt_mirror_descr;
}
this->options |= NAND_USE_FLASH_BBT;
- return nand_scan_bbt (mtd, &agand_flashbased);
+ return nand_scan_bbt(mtd, &agand_flashbased);
}
-
/* Is a flash based bad block table requested ? */
if (this->options & NAND_USE_FLASH_BBT) {
/* Use the default pattern descriptors */
@@ -1066,18 +1176,17 @@ int nand_default_bbt (struct mtd_info *mtd)
this->bbt_md = &bbt_mirror_descr;
}
if (!this->badblock_pattern) {
- this->badblock_pattern = (mtd->oobblock > 512) ?
- &largepage_flashbased : &smallpage_flashbased;
+ this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;
}
} else {
this->bbt_td = NULL;
this->bbt_md = NULL;
if (!this->badblock_pattern) {
- this->badblock_pattern = (mtd->oobblock > 512) ?
- &largepage_memorybased : &smallpage_memorybased;
+ this->badblock_pattern = (mtd->writesize > 512) ?
+ &largepage_memorybased : &smallpage_memorybased;
}
}
- return nand_scan_bbt (mtd, this->badblock_pattern);
+ return nand_scan_bbt(mtd, this->badblock_pattern);
}
/**
@@ -1087,26 +1196,29 @@ int nand_default_bbt (struct mtd_info *mtd)
* @allowbbt: allow access to bad block table region
*
*/
-int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
{
struct nand_chip *this = mtd->priv;
int block;
- uint8_t res;
+ uint8_t res;
/* Get block number * 2 */
- block = (int) (offs >> (this->bbt_erase_shift - 1));
+ block = (int)(offs >> (this->bbt_erase_shift - 1));
res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
- DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int)offs, block >> 1, res);
+ DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+ (unsigned int)offs, block >> 1, res);
switch ((int)res) {
- case 0x00: return 0;
- case 0x01: return 1;
- case 0x02: return allowbbt ? 0 : 1;
+ case 0x00:
+ return 0;
+ case 0x01:
+ return 1;
+ case 0x02:
+ return allowbbt ? 0 : 1;
}
return 1;
}
-EXPORT_SYMBOL (nand_scan_bbt);
-EXPORT_SYMBOL (nand_default_bbt);
+EXPORT_SYMBOL(nand_scan_bbt);
+EXPORT_SYMBOL(nand_default_bbt);
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 40ac909150a3..2a163e4084df 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -7,6 +7,8 @@
* Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
* Toshiba America Electronics Components, Inc.
*
+ * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+ *
* $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
*
* This file is free software; you can redistribute it and/or modify it
@@ -62,90 +64,76 @@ static const u_char nand_ecc_precalc_table[] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
};
-
/**
- * nand_trans_result - [GENERIC] create non-inverted ECC
- * @reg2: line parity reg 2
- * @reg3: line parity reg 3
- * @ecc_code: ecc
- *
- * Creates non-inverted ECC code from line parity
- */
-static void nand_trans_result(u_char reg2, u_char reg3,
- u_char *ecc_code)
-{
- u_char a, b, i, tmp1, tmp2;
-
- /* Initialize variables */
- a = b = 0x80;
- tmp1 = tmp2 = 0;
-
- /* Calculate first ECC byte */
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Calculate second ECC byte */
- b = 0x80;
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Store two of the ECC bytes */
- ecc_code[0] = tmp1;
- ecc_code[1] = tmp2;
-}
-
-/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code
+ * for 256 byte block
* @mtd: MTD block structure
* @dat: raw data
* @ecc_code: buffer for ECC
*/
-int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
{
- u_char idx, reg1, reg2, reg3;
- int j;
+ uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
+ int i;
/* Initialize variables */
reg1 = reg2 = reg3 = 0;
- ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
/* Build up column parity */
- for(j = 0; j < 256; j++) {
-
+ for(i = 0; i < 256; i++) {
/* Get CP0 - CP5 from table */
- idx = nand_ecc_precalc_table[dat[j]];
+ idx = nand_ecc_precalc_table[*dat++];
reg1 ^= (idx & 0x3f);
/* All bit XOR = 1 ? */
if (idx & 0x40) {
- reg3 ^= (u_char) j;
- reg2 ^= ~((u_char) j);
+ reg3 ^= (uint8_t) i;
+ reg2 ^= ~((uint8_t) i);
}
}
/* Create non-inverted ECC code from line parity */
- nand_trans_result(reg2, reg3, ecc_code);
+ tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
+ tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
+ tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
+ tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
+ tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
+ tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
+ tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
+ tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
+
+ tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
+ tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
+ tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
+ tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
+ tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
+ tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
+ tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
+ tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
- ecc_code[0] = ~ecc_code[0];
- ecc_code[1] = ~ecc_code[1];
+#ifdef CONFIG_NAND_ECC_SMC
+ ecc_code[0] = ~tmp2;
+ ecc_code[1] = ~tmp1;
+#else
+ ecc_code[0] = ~tmp1;
+ ecc_code[1] = ~tmp2;
+#endif
ecc_code[2] = ((~reg1) << 2) | 0x03;
+
return 0;
}
+EXPORT_SYMBOL(nand_calculate_ecc);
+
+static inline int countbits(uint32_t byte)
+{
+ int res = 0;
+
+ for (;byte; byte >>= 1)
+ res += byte & 0x01;
+ return res;
+}
/**
* nand_correct_data - [NAND Interface] Detect and correct bit error(s)
@@ -156,93 +144,54 @@ int 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(struct mtd_info *mtd, 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;
+ uint8_t s0, s1, s2;
+
+#ifdef CONFIG_NAND_ECC_SMC
+ s0 = calc_ecc[0] ^ read_ecc[0];
+ s1 = calc_ecc[1] ^ read_ecc[1];
+ s2 = calc_ecc[2] ^ read_ecc[2];
+#else
+ s1 = calc_ecc[0] ^ read_ecc[0];
+ s0 = calc_ecc[1] ^ read_ecc[1];
+ s2 = calc_ecc[2] ^ read_ecc[2];
+#endif
+ if ((s0 | s1 | s2) == 0)
+ return 0;
- /* Do error detection */
- d1 = calc_ecc[0] ^ read_ecc[0];
- d2 = calc_ecc[1] ^ read_ecc[1];
- d3 = calc_ecc[2] ^ read_ecc[2];
+ /* Check for a single bit error */
+ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
+ ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
+ ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
- if ((d1 | d2 | d3) == 0) {
- /* No errors */
- return 0;
- }
- else {
- a = (d1 ^ (d1 >> 1)) & 0x55;
- b = (d2 ^ (d2 >> 1)) & 0x55;
- c = (d3 ^ (d3 >> 1)) & 0x54;
-
- /* Found and will correct single bit error in the data */
- if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
- c = 0x80;
- add = 0;
- a = 0x80;
- for (i=0; i<4; i++) {
- if (d1 & c)
- add |= a;
- c >>= 2;
- a >>= 1;
- }
- c = 0x80;
- for (i=0; i<4; i++) {
- if (d2 & c)
- add |= a;
- c >>= 2;
- a >>= 1;
- }
- bit = 0;
- b = 0x04;
- c = 0x80;
- for (i=0; i<3; i++) {
- if (d3 & c)
- bit |= b;
- c >>= 2;
- b >>= 1;
- }
- b = 0x01;
- a = dat[add];
- a ^= (b << bit);
- dat[add] = a;
- return 1;
- }
- else {
- i = 0;
- while (d1) {
- if (d1 & 0x01)
- ++i;
- d1 >>= 1;
- }
- while (d2) {
- if (d2 & 0x01)
- ++i;
- d2 >>= 1;
- }
- while (d3) {
- if (d3 & 0x01)
- ++i;
- d3 >>= 1;
- }
- if (i == 1) {
- /* ECC Code Error Correction */
- read_ecc[0] = calc_ecc[0];
- read_ecc[1] = calc_ecc[1];
- read_ecc[2] = calc_ecc[2];
- return 2;
- }
- else {
- /* Uncorrectable Error */
- return -1;
- }
- }
+ uint32_t byteoffs, bitnum;
+
+ byteoffs = (s1 << 0) & 0x80;
+ byteoffs |= (s1 << 1) & 0x40;
+ byteoffs |= (s1 << 2) & 0x20;
+ byteoffs |= (s1 << 3) & 0x10;
+
+ byteoffs |= (s0 >> 4) & 0x08;
+ byteoffs |= (s0 >> 3) & 0x04;
+ byteoffs |= (s0 >> 2) & 0x02;
+ byteoffs |= (s0 >> 1) & 0x01;
+
+ bitnum = (s2 >> 5) & 0x04;
+ bitnum |= (s2 >> 4) & 0x02;
+ bitnum |= (s2 >> 3) & 0x01;
+
+ dat[byteoffs] ^= (1 << bitnum);
+
+ return 1;
}
- /* Should never happen */
+ if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
+ return 1;
+
return -1;
}
-
-EXPORT_SYMBOL(nand_calculate_ecc);
EXPORT_SYMBOL(nand_correct_data);
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index dbc7e55a4247..2e2cdf2fc91d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -18,99 +18,110 @@
* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
* options
*
-* Pagesize; 0, 256, 512
-* 0 get this information from the extended chip ID
+* Pagesize; 0, 256, 512
+* 0 get this information from the extended chip ID
+ 256 256 Byte page size
* 512 512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
- {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
- {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
- {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
- {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
-
- {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
- {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
- {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-
- {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
- {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
- {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
- {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
- {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
- {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
- {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
- {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-
- {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
-
- /* These are the new chips with large page size. The pagesize
- * and the erasesize is determined from the extended id bytes
- */
+ {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
+
+ {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+ {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+
+ {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
+
+ /*
+ * These are the new chips with large page size. The pagesize and the
+ * erasesize is determined from the extended id bytes
+ */
+#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
+
/*512 Megabit */
- {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
+ {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
+ {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
+ {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
- {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
+ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
+ {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
+ {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
- {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
+ {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
+ {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
+ {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
- {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
+ {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
+ {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
- {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
+ {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
+ {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
- {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
- {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
- {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-
- /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
- * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
- * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
- * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
- * There are more speed improvements for reads and writes possible, but not implemented now
+ {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
+ {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
+ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
+ {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
+
+ /*
+ * Renesas AND 1 Gigabit. Those chips do not support extended id and
+ * have a strange page/block layout ! The chosen minimum erasesize is
+ * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
+ * planes 1 block = 2 pages, but due to plane arrangement the blocks
+ * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
+ * increase the eraseblock size so we chose a combined one which can be
+ * erased in one go There are more speed improvements for reads and
+ * writes possible, but not implemented now
*/
- {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
+ NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
+ BBT_AUTO_REFRESH
+ },
{NULL,}
};
@@ -125,13 +136,13 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
- {NAND_MFR_HYNIX, "Hynix"},
+ {NAND_MFR_HYNIX, "Hynix"},
{0x0, "Unknown"}
};
-EXPORT_SYMBOL (nand_manuf_ids);
-EXPORT_SYMBOL (nand_flash_ids);
+EXPORT_SYMBOL(nand_manuf_ids);
+EXPORT_SYMBOL(nand_flash_ids);
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION ("Nand device & manufacturer ID's");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Nand device & manufacturer IDs");
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index a0af92cc7efd..ebd64abc8be8 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -369,7 +369,7 @@ init_nandsim(struct mtd_info *mtd)
/* Initialize the NAND flash parameters */
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
ns->geom.totsz = mtd->size;
- ns->geom.pgsz = mtd->oobblock;
+ ns->geom.pgsz = mtd->writesize;
ns->geom.oobsz = mtd->oobsize;
ns->geom.secsz = mtd->erasesize;
ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz;
@@ -1071,68 +1071,6 @@ switch_state(struct nandsim *ns)
}
}
-static void
-ns_hwcontrol(struct mtd_info *mtd, int cmd)
-{
- struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-
- switch (cmd) {
-
- /* set CLE line high */
- case NAND_CTL_SETCLE:
- NS_DBG("ns_hwcontrol: start command latch cycles\n");
- ns->lines.cle = 1;
- break;
-
- /* set CLE line low */
- case NAND_CTL_CLRCLE:
- NS_DBG("ns_hwcontrol: stop command latch cycles\n");
- ns->lines.cle = 0;
- break;
-
- /* set ALE line high */
- case NAND_CTL_SETALE:
- NS_DBG("ns_hwcontrol: start address latch cycles\n");
- ns->lines.ale = 1;
- break;
-
- /* set ALE line low */
- case NAND_CTL_CLRALE:
- NS_DBG("ns_hwcontrol: stop address latch cycles\n");
- ns->lines.ale = 0;
- break;
-
- /* set WP line high */
- case NAND_CTL_SETWP:
- NS_DBG("ns_hwcontrol: enable write protection\n");
- ns->lines.wp = 1;
- break;
-
- /* set WP line low */
- case NAND_CTL_CLRWP:
- NS_DBG("ns_hwcontrol: disable write protection\n");
- ns->lines.wp = 0;
- break;
-
- /* set CE line low */
- case NAND_CTL_SETNCE:
- NS_DBG("ns_hwcontrol: enable chip\n");
- ns->lines.ce = 1;
- break;
-
- /* set CE line high */
- case NAND_CTL_CLRNCE:
- NS_DBG("ns_hwcontrol: disable chip\n");
- ns->lines.ce = 0;
- break;
-
- default:
- NS_ERR("hwcontrol: unknown command\n");
- }
-
- return;
-}
-
static u_char
ns_nand_read_byte(struct mtd_info *mtd)
{
@@ -1359,6 +1297,18 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
return;
}
+static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+{
+ struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+
+ ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
+ ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
+ ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
+
+ if (cmd != NAND_CMD_NONE)
+ ns_nand_write_byte(mtd, cmd);
+}
+
static int
ns_device_ready(struct mtd_info *mtd)
{
@@ -1377,17 +1327,6 @@ ns_nand_read_word(struct mtd_info *mtd)
}
static void
-ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
-{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-
- NS_DBG("write_word\n");
-
- chip->write_byte(mtd, word & 0xFF);
- chip->write_byte(mtd, word >> 8);
-}
-
-static void
ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1514,16 +1453,14 @@ static int __init ns_init_module(void)
/*
* Register simulator's callbacks.
*/
- chip->hwcontrol = ns_hwcontrol;
+ chip->cmd_ctrl = ns_hwcontrol;
chip->read_byte = ns_nand_read_byte;
chip->dev_ready = ns_device_ready;
- chip->write_byte = ns_nand_write_byte;
chip->write_buf = ns_nand_write_buf;
chip->read_buf = ns_nand_read_buf;
chip->verify_buf = ns_nand_verify_buf;
- chip->write_word = ns_nand_write_word;
chip->read_word = ns_nand_read_word;
- chip->eccmode = NAND_ECC_SOFT;
+ chip->ecc.mode = NAND_ECC_SOFT;
chip->options |= NAND_SKIP_BBTSCAN;
/*
@@ -1546,6 +1483,8 @@ static int __init ns_init_module(void)
chip->options |= NAND_BUSWIDTH_16;
}
+ nsmtd->owner = THIS_MODULE;
+
if ((retval = nand_scan(nsmtd, 1)) != 0) {
NS_ERR("can't register NAND Simulator\n");
if (retval > 0)
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
new file mode 100644
index 000000000000..fe8d38514ba6
--- /dev/null
+++ b/drivers/mtd/nand/ndfc.c
@@ -0,0 +1,311 @@
+/*
+ * drivers/mtd/ndfc.c
+ *
+ * Overview:
+ * Platform independend driver for NDFC (NanD Flash Controller)
+ * integrated into EP440 cores
+ *
+ * Author: Thomas Gleixner
+ *
+ * Copyright 2006 IBM
+ *
+ * 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 <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/ndfc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/ibm44x.h>
+
+struct ndfc_nand_mtd {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ struct platform_nand_chip *pl_chip;
+};
+
+static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
+
+struct ndfc_controller {
+ void __iomem *ndfcbase;
+ struct nand_hw_control ndfc_control;
+ atomic_t childs_active;
+};
+
+static struct ndfc_controller ndfc_ctrl;
+
+static void ndfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ uint32_t ccr;
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct nand_chip *nandchip = mtd->priv;
+ struct ndfc_nand_mtd *nandmtd = nandchip->priv;
+ struct platform_nand_chip *pchip = nandmtd->pl_chip;
+
+ ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ if (chip >= 0) {
+ ccr &= ~NDFC_CCR_BS_MASK;
+ ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ } else
+ ccr |= NDFC_CCR_RESET_CE;
+ writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+}
+
+static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
+ else
+ writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
+}
+
+static int ndfc_ready(struct mtd_info *mtd)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+
+ return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+}
+
+static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ uint32_t ccr;
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+
+ ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr |= NDFC_CCR_RESET_ECC;
+ __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ wmb();
+}
+
+static int ndfc_calculate_ecc(struct mtd_info *mtd,
+ const u_char *dat, u_char *ecc_code)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ uint32_t ecc;
+ uint8_t *p = (uint8_t *)&ecc;
+
+ wmb();
+ ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
+ ecc_code[0] = p[1];
+ ecc_code[1] = p[2];
+ ecc_code[2] = p[3];
+
+ return 0;
+}
+
+/*
+ * Speedups for buffer read/write/verify
+ *
+ * NDFC allows 32bit read/write of data. So we can speed up the buffer
+ * functions. No further checking, as nand_base will always read/write
+ * page aligned.
+ */
+static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ uint32_t *p = (uint32_t *) buf;
+
+ for(;len > 0; len -= 4)
+ *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
+}
+
+static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ uint32_t *p = (uint32_t *) buf;
+
+ for(;len > 0; len -= 4)
+ __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
+}
+
+static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ uint32_t *p = (uint32_t *) buf;
+
+ for(;len > 0; len -= 4)
+ if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * Initialize chip structure
+ */
+static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+{
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct nand_chip *chip = &mtd->chip;
+
+ chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+ chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+ chip->cmd_ctrl = ndfc_hwcontrol;
+ chip->dev_ready = ndfc_ready;
+ chip->select_chip = ndfc_select_chip;
+ chip->chip_delay = 50;
+ chip->priv = mtd;
+ chip->options = mtd->pl_chip->options;
+ chip->controller = &ndfc->ndfc_control;
+ chip->read_buf = ndfc_read_buf;
+ chip->write_buf = ndfc_write_buf;
+ chip->verify_buf = ndfc_verify_buf;
+ chip->ecc.correct = nand_correct_data;
+ chip->ecc.hwctl = ndfc_enable_hwecc;
+ chip->ecc.calculate = ndfc_calculate_ecc;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+ chip->ecclayout = mtd->pl_chip->ecclayout;
+ mtd->mtd.priv = chip;
+ mtd->mtd.owner = THIS_MODULE;
+}
+
+static int ndfc_chip_probe(struct platform_device *pdev)
+{
+ struct platform_nand_chip *nc = pdev->dev.platform_data;
+ struct ndfc_chip_settings *settings = nc->priv;
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_nand_mtd *nandmtd;
+
+ if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
+ return -EINVAL;
+
+ /* Set the bank settings */
+ __raw_writel(settings->bank_settings,
+ ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
+
+ nandmtd = &ndfc_mtd[pdev->id];
+ if (nandmtd->pl_chip)
+ return -EBUSY;
+
+ nandmtd->pl_chip = nc;
+ ndfc_chip_init(nandmtd);
+
+ /* Scan for chips */
+ if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
+ nandmtd->pl_chip = NULL;
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ printk("Number of partitions %d\n", nc->nr_partitions);
+ if (nc->nr_partitions) {
+ /* Add the full device, so complete dumps can be made */
+ add_mtd_device(&nandmtd->mtd);
+ add_mtd_partitions(&nandmtd->mtd, nc->partitions,
+ nc->nr_partitions);
+
+ } else
+#else
+ add_mtd_device(&nandmtd->mtd);
+#endif
+
+ atomic_inc(&ndfc->childs_active);
+ return 0;
+}
+
+static int ndfc_chip_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int ndfc_nand_probe(struct platform_device *pdev)
+{
+ struct platform_nand_ctrl *nc = pdev->dev.platform_data;
+ struct ndfc_controller_settings *settings = nc->priv;
+ struct resource *res = pdev->resource;
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
+ unsigned long long phys = settings->ndfc_erpn | res->start;
+
+ ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+ if (!ndfc->ndfcbase) {
+ printk(KERN_ERR "NDFC: ioremap failed\n");
+ return -EIO;
+ }
+
+ __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+
+ platform_set_drvdata(pdev, ndfc);
+
+ printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
+ __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+
+ return 0;
+}
+
+static int ndfc_nand_remove(struct platform_device *pdev)
+{
+ struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+
+ if (atomic_read(&ndfc->childs_active))
+ return -EBUSY;
+
+ if (ndfc) {
+ platform_set_drvdata(pdev, NULL);
+ iounmap(ndfc_ctrl.ndfcbase);
+ ndfc_ctrl.ndfcbase = NULL;
+ }
+ return 0;
+}
+
+/* driver device registration */
+
+static struct platform_driver ndfc_chip_driver = {
+ .probe = ndfc_chip_probe,
+ .remove = ndfc_chip_remove,
+ .driver = {
+ .name = "ndfc-chip",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_driver ndfc_nand_driver = {
+ .probe = ndfc_nand_probe,
+ .remove = ndfc_nand_remove,
+ .driver = {
+ .name = "ndfc-nand",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ndfc_nand_init(void)
+{
+ int ret;
+
+ spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
+ init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
+
+ ret = platform_driver_register(&ndfc_nand_driver);
+ if (!ret)
+ ret = platform_driver_register(&ndfc_chip_driver);
+ return ret;
+}
+
+static void __exit ndfc_nand_exit(void)
+{
+ platform_driver_unregister(&ndfc_chip_driver);
+ platform_driver_unregister(&ndfc_nand_driver);
+}
+
+module_init(ndfc_nand_init);
+module_exit(ndfc_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Platform driver for NDFC");
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c
index 91a95f34a6ee..22fa65c12ab9 100644
--- a/drivers/mtd/nand/ppchameleonevb.c
+++ b/drivers/mtd/nand/ppchameleonevb.c
@@ -58,21 +58,21 @@
/*
* MTD structure for PPChameleonEVB board
*/
-static struct mtd_info *ppchameleon_mtd = NULL;
+static struct mtd_info *ppchameleon_mtd = NULL;
static struct mtd_info *ppchameleonevb_mtd = NULL;
/*
* Module stuff
*/
-static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR;
+static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR;
static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
#ifdef MODULE
module_param(ppchameleon_fio_pbase, ulong, 0);
module_param(ppchameleonevb_fio_pbase, ulong, 0);
#else
-__setup("ppchameleon_fio_pbase=",ppchameleon_fio_pbase);
-__setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase);
+__setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase);
+__setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase);
#endif
#ifdef CONFIG_MTD_PARTITIONS
@@ -80,82 +80,96 @@ __setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase);
* Define static partitions for flash devices
*/
static struct mtd_partition partition_info_hi[] = {
- { name: "PPChameleon HI Nand Flash",
- offset: 0,
- size: 128*1024*1024 }
+ { .name = "PPChameleon HI Nand Flash",
+ offset = 0,
+ .size = 128 * 1024 * 1024
+ }
};
static struct mtd_partition partition_info_me[] = {
- { name: "PPChameleon ME Nand Flash",
- offset: 0,
- size: 32*1024*1024 }
+ { .name = "PPChameleon ME Nand Flash",
+ .offset = 0,
+ .size = 32 * 1024 * 1024
+ }
};
static struct mtd_partition partition_info_evb[] = {
- { name: "PPChameleonEVB Nand Flash",
- offset: 0,
- size: 32*1024*1024 }
+ { .name = "PPChameleonEVB Nand Flash",
+ .offset = 0,
+ .size = 32 * 1024 * 1024
+ }
};
#define NUM_PARTITIONS 1
-extern int parse_cmdline_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
- const char *mtd_id);
+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 ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd)
+static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd,
+ unsigned int ctrl)
{
- switch(cmd) {
-
- case NAND_CTL_SETCLE:
- MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
- break;
- case NAND_CTL_CLRCLE:
- MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
- break;
- case NAND_CTL_SETALE:
- MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
- break;
- case NAND_CTL_CLRALE:
- MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
- break;
- case NAND_CTL_SETNCE:
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+#error Missing headerfiles. No way to fix this. -tglx
+ switch (cmd) {
+ case NAND_CTL_SETCLE:
+ MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
+ break;
+ case NAND_CTL_CLRCLE:
+ MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
+ break;
+ case NAND_CTL_SETALE:
+ MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
+ break;
+ case NAND_CTL_CLRALE:
+ MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
+ break;
+ case NAND_CTL_SETNCE:
MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
- break;
- case NAND_CTL_CLRNCE:
+ break;
+ case NAND_CTL_CLRNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
- break;
+ break;
+ }
}
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
-static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd)
+static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd,
+ unsigned int ctrl)
{
- switch(cmd) {
-
- case NAND_CTL_SETCLE:
- MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
- break;
- case NAND_CTL_CLRCLE:
- MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
- break;
- case NAND_CTL_SETALE:
- MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
- break;
- case NAND_CTL_CLRALE:
- MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
- break;
- case NAND_CTL_SETNCE:
- MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
- break;
- case NAND_CTL_CLRNCE:
- MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
- break;
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+#error Missing headerfiles. No way to fix this. -tglx
+ switch (cmd) {
+ case NAND_CTL_SETCLE:
+ MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ case NAND_CTL_CLRCLE:
+ MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ case NAND_CTL_SETALE:
+ MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ case NAND_CTL_CLRALE:
+ MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ case NAND_CTL_SETNCE:
+ MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ case NAND_CTL_CLRNCE:
+ MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
+ break;
+ }
}
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
#ifdef USE_READY_BUSY_PIN
@@ -164,15 +178,15 @@ static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd)
*/
static int ppchameleon_device_ready(struct mtd_info *minfo)
{
- if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_RB_GPIO_PIN)
+ if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_RB_GPIO_PIN)
return 1;
return 0;
}
static int ppchameleonevb_device_ready(struct mtd_info *minfo)
{
- if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
- return 1;
+ if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
+ return 1;
return 0;
}
#endif
@@ -185,7 +199,7 @@ const char *part_probes_evb[] = { "cmdlinepart", NULL };
/*
* Main initialization routine
*/
-static int __init ppchameleonevb_init (void)
+static int __init ppchameleonevb_init(void)
{
struct nand_chip *this;
const char *part_type = 0;
@@ -194,13 +208,11 @@ static int __init ppchameleonevb_init (void)
void __iomem *ppchameleon_fio_base;
void __iomem *ppchameleonevb_fio_base;
-
/*********************************
* Processor module NAND (if any) *
*********************************/
/* Allocate memory for MTD device structure and private data */
- ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip), GFP_KERNEL);
+ ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleon_mtd) {
printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
return -ENOMEM;
@@ -208,63 +220,65 @@ static int __init ppchameleonevb_init (void)
/* map physical address */
ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M);
- if(!ppchameleon_fio_base) {
+ if (!ppchameleon_fio_base) {
printk("ioremap PPChameleon NAND flash failed\n");
kfree(ppchameleon_mtd);
return -EIO;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&ppchameleon_mtd[1]);
+ this = (struct nand_chip *)(&ppchameleon_mtd[1]);
/* Initialize structures */
- memset((char *) ppchameleon_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(ppchameleon_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ppchameleon_mtd->priv = this;
+ ppchameleon_mtd->owner = THIS_MODULE;
- /* Initialize GPIOs */
+ /* Initialize GPIOs */
/* Pin mapping for NAND chip */
/*
- CE GPIO_01
- CLE GPIO_02
- ALE GPIO_03
- R/B GPIO_04
- */
+ CE GPIO_01
+ CLE GPIO_02
+ ALE GPIO_03
+ R/B GPIO_04
+ */
/* output select */
- out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xC0FFFFFF);
+ out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xC0FFFFFF);
/* three-state select */
- out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xC0FFFFFF);
+ out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xC0FFFFFF);
/* enable output driver */
- out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
+ out_be32((volatile unsigned *)GPIO0_TCR,
+ in_be32((volatile unsigned *)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
#ifdef USE_READY_BUSY_PIN
/* three-state select */
- out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFF3FFFFF);
+ out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFF3FFFFF);
/* high-impedecence */
- out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
+ out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
/* input select */
- out_be32((volatile unsigned*)GPIO0_ISR1H, (in_be32((volatile unsigned*)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
+ out_be32((volatile unsigned *)GPIO0_ISR1H,
+ (in_be32((volatile unsigned *)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
#endif
/* insert callbacks */
this->IO_ADDR_R = ppchameleon_fio_base;
this->IO_ADDR_W = ppchameleon_fio_base;
- this->hwcontrol = ppchameleon_hwcontrol;
+ this->cmd_ctrl = ppchameleon_hwcontrol;
#ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleon_device_ready;
#endif
this->chip_delay = NAND_BIG_DELAY_US;
/* ECC mode */
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
/* Scan to find existence of the device (it could not be mounted) */
- if (nand_scan (ppchameleon_mtd, 1)) {
+ if (nand_scan(ppchameleon_mtd, 1)) {
iounmap((void *)ppchameleon_fio_base);
- kfree (ppchameleon_mtd);
+ kfree(ppchameleon_mtd);
goto nand_evb_init;
}
-
#ifndef USE_READY_BUSY_PIN
/* Adjust delay if necessary */
if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
@@ -275,12 +289,11 @@ static int __init ppchameleonevb_init (void)
ppchameleon_mtd->name = "ppchameleon-nand";
mtd_parts_nb = parse_mtd_partitions(ppchameleon_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) {
if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
mtd_parts = partition_info_me;
else
@@ -293,13 +306,12 @@ static int __init ppchameleonevb_init (void)
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
-nand_evb_init:
+ nand_evb_init:
/****************************
* EVB NAND (always present) *
****************************/
/* Allocate memory for MTD device structure and private data */
- ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip), GFP_KERNEL);
+ ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleonevb_mtd) {
printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
return -ENOMEM;
@@ -307,77 +319,76 @@ nand_evb_init:
/* map physical address */
ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M);
- if(!ppchameleonevb_fio_base) {
+ if (!ppchameleonevb_fio_base) {
printk("ioremap PPChameleonEVB NAND flash failed\n");
kfree(ppchameleonevb_mtd);
return -EIO;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&ppchameleonevb_mtd[1]);
+ this = (struct nand_chip *)(&ppchameleonevb_mtd[1]);
/* Initialize structures */
- memset((char *) ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ppchameleonevb_mtd->priv = this;
- /* Initialize GPIOs */
+ /* Initialize GPIOs */
/* Pin mapping for NAND chip */
/*
- CE GPIO_14
- CLE GPIO_15
- ALE GPIO_16
- R/B GPIO_31
- */
+ CE GPIO_14
+ CLE GPIO_15
+ ALE GPIO_16
+ R/B GPIO_31
+ */
/* output select */
- out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xFFFFFFF0);
- out_be32((volatile unsigned*)GPIO0_OSRL, in_be32((volatile unsigned*)GPIO0_OSRL) & 0x3FFFFFFF);
+ out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xFFFFFFF0);
+ out_be32((volatile unsigned *)GPIO0_OSRL, in_be32((volatile unsigned *)GPIO0_OSRL) & 0x3FFFFFFF);
/* three-state select */
- out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
- out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
+ out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFFFFFFF0);
+ out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0x3FFFFFFF);
/* enable output driver */
- out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
+ out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
#ifdef USE_READY_BUSY_PIN
/* three-state select */
- out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC);
+ out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0xFFFFFFFC);
/* high-impedecence */
- out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
+ out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
/* input select */
- out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
+ out_be32((volatile unsigned *)GPIO0_ISR1L,
+ (in_be32((volatile unsigned *)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
#endif
/* insert callbacks */
this->IO_ADDR_R = ppchameleonevb_fio_base;
this->IO_ADDR_W = ppchameleonevb_fio_base;
- this->hwcontrol = ppchameleonevb_hwcontrol;
+ this->cmd_ctrl = ppchameleonevb_hwcontrol;
#ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleonevb_device_ready;
#endif
this->chip_delay = NAND_SMALL_DELAY_US;
/* ECC mode */
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
/* Scan to find existence of the device */
- if (nand_scan (ppchameleonevb_mtd, 1)) {
+ if (nand_scan(ppchameleonevb_mtd, 1)) {
iounmap((void *)ppchameleonevb_fio_base);
- kfree (ppchameleonevb_mtd);
+ kfree(ppchameleonevb_mtd);
return -ENXIO;
}
-
#ifdef CONFIG_MTD_PARTITIONS
ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &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_evb;
mtd_parts_nb = NUM_PARTITIONS;
part_type = "static";
@@ -390,18 +401,19 @@ nand_evb_init:
/* Return happy */
return 0;
}
+
module_init(ppchameleonevb_init);
/*
* Clean up routine
*/
-static void __exit ppchameleonevb_cleanup (void)
+static void __exit ppchameleonevb_cleanup(void)
{
struct nand_chip *this;
/* Release resources, unregister device(s) */
- nand_release (ppchameleon_mtd);
- nand_release (ppchameleonevb_mtd);
+ nand_release(ppchameleon_mtd);
+ nand_release(ppchameleonevb_mtd);
/* Release iomaps */
this = (struct nand_chip *) &ppchameleon_mtd[1];
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index 4129c03dfd90..f8c49645324d 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -97,12 +97,12 @@ static struct mtd_info *rtc_from4_mtd = NULL;
static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
static const struct mtd_partition partition_info[] = {
- {
- .name = "Renesas flash partition 1",
- .offset = 0,
- .size = MTDPART_SIZ_FULL
- },
+ {
+ .name = "Renesas flash partition 1",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL},
};
+
#define NUM_PARTITIONS 1
/*
@@ -111,8 +111,8 @@ static const struct mtd_partition partition_info[] = {
* NAND_BBT_CREATE and/or NAND_BBT_WRITE
*
*/
-static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
static struct nand_bbt_descr rtc_from4_bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
@@ -134,8 +134,6 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
.pattern = mirror_pattern
};
-
-
#ifdef RTC_FROM4_HWECC
/* the Reed Solomon control structure */
@@ -144,15 +142,14 @@ static struct rs_control *rs_decoder;
/*
* hardware specific Out Of Band information
*/
-static struct nand_oobinfo rtc_from4_nand_oobinfo = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout rtc_from4_nand_oobinfo = {
.eccbytes = 32,
.eccpos = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31},
- .oobfree = { {32, 32} }
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31},
+ .oobfree = {{32, 32}}
};
/* Aargh. I missed the reversed bit order, when I
@@ -162,44 +159,42 @@ static struct nand_oobinfo rtc_from4_nand_oobinfo = {
* of the ecc byte which we get from the FPGA
*/
static uint8_t revbits[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
#endif
-
-
/*
* rtc_from4_hwcontrol - hardware specific access to control-lines
* @mtd: MTD device structure
@@ -212,35 +207,20 @@ static uint8_t revbits[256] = {
* Address lines (A24-A22), so no action is required here.
*
*/
-static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
+static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-
- switch(cmd) {
+ struct nand_chip *chip = (mtd->priv);
- case NAND_CTL_SETCLE:
- this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
- break;
- case NAND_CTL_CLRCLE:
- this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
- break;
-
- case NAND_CTL_SETALE:
- this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
- break;
- case NAND_CTL_CLRALE:
- this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
- break;
+ if (cmd == NAND_CMD_NONE)
+ return;
- case NAND_CTL_SETNCE:
- break;
- case NAND_CTL_CLRNCE:
- break;
-
- }
+ if (ctrl & NAND_CLE)
+ writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE);
+ else
+ writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE);
}
-
/*
* rtc_from4_nand_select_chip - hardware specific chip select
* @mtd: MTD device structure
@@ -252,26 +232,25 @@ static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
*/
static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK);
- switch(chip) {
+ switch (chip) {
- case 0: /* select slot 3 chip */
+ case 0: /* select slot 3 chip */
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3);
- break;
- case 1: /* select slot 4 chip */
+ break;
+ case 1: /* select slot 4 chip */
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4);
- break;
+ break;
- }
+ }
}
-
/*
* rtc_from4_nand_device_ready - hardware specific ready/busy check
* @mtd: MTD device structure
@@ -290,7 +269,6 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
}
-
/*
* deplete - code to perform device recovery in case there was a power loss
* @mtd: MTD device structure
@@ -306,24 +284,23 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
*/
static void deplete(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd->priv;
- /* wait until device is ready */
- while (!this->dev_ready(mtd));
+ /* wait until device is ready */
+ while (!this->dev_ready(mtd)) ;
this->select_chip(mtd, chip);
/* Send the commands for device recovery, phase 1 */
- this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
- this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+ this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
+ this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1);
/* Send the commands for device recovery, phase 2 */
- this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
- this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+ this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
+ this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1);
}
-
#ifdef RTC_FROM4_HWECC
/*
* rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
@@ -335,39 +312,35 @@ static void deplete(struct mtd_info *mtd, int chip)
*/
static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
{
- volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
+ volatile unsigned short *rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
unsigned short status;
switch (mode) {
- case NAND_ECC_READ :
- status = RTC_FROM4_RS_ECC_CTL_CLR
- | RTC_FROM4_RS_ECC_CTL_FD_E;
+ case NAND_ECC_READ:
+ status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_FD_E;
*rs_ecc_ctl = status;
break;
- case NAND_ECC_READSYN :
- status = 0x00;
+ case NAND_ECC_READSYN:
+ status = 0x00;
*rs_ecc_ctl = status;
break;
- case NAND_ECC_WRITE :
- status = RTC_FROM4_RS_ECC_CTL_CLR
- | RTC_FROM4_RS_ECC_CTL_GEN
- | RTC_FROM4_RS_ECC_CTL_FD_E;
+ case NAND_ECC_WRITE:
+ status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_GEN | RTC_FROM4_RS_ECC_CTL_FD_E;
*rs_ecc_ctl = status;
break;
- default:
+ default:
BUG();
break;
}
}
-
/*
* rtc_from4_calculate_ecc - hardware specific code to read ECC code
* @mtd: MTD device structure
@@ -383,7 +356,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
*/
static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
- volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
+ volatile unsigned short *rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
unsigned short value;
int i;
@@ -395,7 +368,6 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
ecc_code[7] |= 0x0f; /* set the last four bits (not used) */
}
-
/*
* rtc_from4_correct_data - hardware specific code to correct data using ECC code
* @mtd: MTD device structure
@@ -414,7 +386,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
unsigned short status;
uint16_t par[6], syn[6];
uint8_t ecc[8];
- volatile unsigned short *rs_ecc;
+ volatile unsigned short *rs_ecc;
status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK));
@@ -424,23 +396,18 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
/* Read the syndrom pattern from the FPGA and correct the bitorder */
rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
- for (i = 0; i < 8; i++) {
- ecc[i] = revbits[(*rs_ecc) & 0xFF];
- rs_ecc++;
- }
+ for (i = 0; i < 8; i++) {
+ ecc[i] = revbits[(*rs_ecc) & 0xFF];
+ rs_ecc++;
+ }
/* convert into 6 10bit syndrome fields */
- par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) |
- (((uint16_t)ecc[1] << 8) & 0x300)];
- par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
- (((uint16_t)ecc[2] << 6) & 0x3c0)];
- par[3] = rs_decoder->index_of[(((uint16_t)ecc[2] >> 4) & 0x00f) |
- (((uint16_t)ecc[3] << 4) & 0x3f0)];
- par[2] = rs_decoder->index_of[(((uint16_t)ecc[3] >> 6) & 0x003) |
- (((uint16_t)ecc[4] << 2) & 0x3fc)];
- par[1] = rs_decoder->index_of[(((uint16_t)ecc[5] >> 0) & 0x0ff) |
- (((uint16_t)ecc[6] << 8) & 0x300)];
- par[0] = (((uint16_t)ecc[6] >> 2) & 0x03f) | (((uint16_t)ecc[7] << 6) & 0x3c0);
+ par[5] = rs_decoder->index_of[(((uint16_t) ecc[0] >> 0) & 0x0ff) | (((uint16_t) ecc[1] << 8) & 0x300)];
+ par[4] = rs_decoder->index_of[(((uint16_t) ecc[1] >> 2) & 0x03f) | (((uint16_t) ecc[2] << 6) & 0x3c0)];
+ par[3] = rs_decoder->index_of[(((uint16_t) ecc[2] >> 4) & 0x00f) | (((uint16_t) ecc[3] << 4) & 0x3f0)];
+ par[2] = rs_decoder->index_of[(((uint16_t) ecc[3] >> 6) & 0x003) | (((uint16_t) ecc[4] << 2) & 0x3fc)];
+ par[1] = rs_decoder->index_of[(((uint16_t) ecc[5] >> 0) & 0x0ff) | (((uint16_t) ecc[6] << 8) & 0x300)];
+ par[0] = (((uint16_t) ecc[6] >> 2) & 0x03f) | (((uint16_t) ecc[7] << 6) & 0x3c0);
/* Convert to computable syndrome */
for (i = 0; i < 6; i++) {
@@ -453,16 +420,14 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
syn[i] = rs_decoder->index_of[syn[i]];
}
- /* Let the library code do its magic.*/
- res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
+ /* Let the library code do its magic. */
+ res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL);
if (res > 0) {
- DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
- "ECC corrected %d errors on read\n", res);
+ DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res);
}
return res;
}
-
/**
* rtc_from4_errstat - perform additional error status checks
* @mtd: MTD device structure
@@ -478,54 +443,66 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
* note: see pages 34..37 of data sheet for details.
*
*/
-static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
+static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
+ int state, int status, int page)
{
- int er_stat=0;
- int rtn, retlen;
- size_t len;
+ int er_stat = 0;
+ int rtn, retlen;
+ size_t len;
uint8_t *buf;
- int i;
-
- this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
-
- if (state == FL_ERASING) {
- for (i=0; i<4; i++) {
- if (status & 1<<(i+1)) {
- this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
- rtn = this->read_byte(mtd);
- this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
- if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
- er_stat |= 1<<(i+1); /* err_ecc_not_avail */
- }
- }
+ int i;
+
+ this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
+
+ if (state == FL_ERASING) {
+
+ for (i = 0; i < 4; i++) {
+ if (!(status & 1 << (i + 1)))
+ continue;
+ this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1),
+ -1, -1);
+ rtn = this->read_byte(mtd);
+ this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
+
+ /* err_ecc_not_avail */
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE))
+ er_stat |= 1 << (i + 1);
}
+
} else if (state == FL_WRITING) {
+
+ unsigned long corrected = mtd->ecc_stats.corrected;
+
/* single bank write logic */
- this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1);
+ this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1);
rtn = this->read_byte(mtd);
- this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+ this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
+
if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
- er_stat |= 1<<1; /* err_ecc_not_avail */
- } else {
- len = mtd->oobblock;
- buf = kmalloc (len, GFP_KERNEL);
- if (!buf) {
- printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
- er_stat = 1; /* if we can't check, assume failed */
- } else {
- /* recovery read */
- /* page read */
- rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
- if (rtn) { /* if read failed or > 1-bit error corrected */
- er_stat |= 1<<1; /* ECC read failed */
- }
- kfree(buf);
- }
+ /* err_ecc_not_avail */
+ er_stat |= 1 << 1;
+ goto out;
+ }
+
+ len = mtd->writesize;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
+ er_stat = 1;
+ goto out;
}
+
+ /* recovery read */
+ rtn = nand_do_read(mtd, page, len, &retlen, buf);
+
+ /* if read failed or > 1-bit error corrected */
+ if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) {
+ er_stat |= 1 << 1;
+ kfree(buf);
}
rtn = status;
- if (er_stat == 0) { /* if ECC is available */
+ if (er_stat == 0) { /* if ECC is available */
rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */
}
@@ -533,33 +510,32 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s
}
#endif
-
/*
* Main initialization routine
*/
-int __init rtc_from4_init (void)
+static int __init rtc_from4_init(void)
{
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
int i;
/* Allocate memory for MTD device structure and private data */
- rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
+ rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!rtc_from4_mtd) {
- printk ("Unable to allocate Renesas NAND MTD device structure.\n");
+ printk("Unable to allocate Renesas NAND MTD device structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&rtc_from4_mtd[1]);
+ this = (struct nand_chip *)(&rtc_from4_mtd[1]);
/* Initialize structures */
- memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(rtc_from4_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
rtc_from4_mtd->priv = this;
+ rtc_from4_mtd->owner = THIS_MODULE;
/* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */
bcr1 = *SH77X9_BCR1 & ~0x0002;
@@ -580,9 +556,9 @@ int __init rtc_from4_init (void)
this->IO_ADDR_R = rtc_from4_fio_base;
this->IO_ADDR_W = rtc_from4_fio_base;
/* Set address of hardware control function */
- this->hwcontrol = rtc_from4_hwcontrol;
+ this->cmd_ctrl = rtc_from4_hwcontrol;
/* Set address of chip select function */
- this->select_chip = rtc_from4_nand_select_chip;
+ this->select_chip = rtc_from4_nand_select_chip;
/* command delay time (in us) */
this->chip_delay = 100;
/* return the status of the Ready/Busy line */
@@ -591,19 +567,20 @@ int __init rtc_from4_init (void)
#ifdef RTC_FROM4_HWECC
printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
- this->eccmode = NAND_ECC_HW8_512;
- this->options |= NAND_HWECC_SYNDROME;
+ this->ecc.mode = NAND_ECC_HW_SYNDROME;
+ this->ecc.size = 512;
+ this->ecc.bytes = 8;
/* return the status of extra status and ECC checks */
this->errstat = rtc_from4_errstat;
/* set the nand_oobinfo to support FPGA H/W error detection */
- this->autooob = &rtc_from4_nand_oobinfo;
- this->enable_hwecc = rtc_from4_enable_hwecc;
- this->calculate_ecc = rtc_from4_calculate_ecc;
- this->correct_data = rtc_from4_correct_data;
+ this->ecc.layout = &rtc_from4_nand_oobinfo;
+ this->ecc.hwctl = rtc_from4_enable_hwecc;
+ this->ecc.calculate = rtc_from4_calculate_ecc;
+ this->ecc.correct = rtc_from4_correct_data;
#else
printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
#endif
/* set the bad block tables to support debugging */
@@ -617,7 +594,7 @@ int __init rtc_from4_init (void)
}
/* Perform 'device recovery' for each chip in case there was a power loss. */
- for (i=0; i < this->numchips; i++) {
+ for (i = 0; i < this->numchips; i++) {
deplete(rtc_from4_mtd, i);
}
@@ -643,7 +620,7 @@ int __init rtc_from4_init (void)
*/
rs_decoder = init_rs(10, 0x409, 0, 1, 6);
if (!rs_decoder) {
- printk (KERN_ERR "Could not create a RS decoder\n");
+ printk(KERN_ERR "Could not create a RS decoder\n");
nand_release(rtc_from4_mtd);
kfree(rtc_from4_mtd);
return -ENOMEM;
@@ -652,20 +629,19 @@ int __init rtc_from4_init (void)
/* Return happy */
return 0;
}
-module_init(rtc_from4_init);
+module_init(rtc_from4_init);
/*
* Clean up routine
*/
-#ifdef MODULE
-static void __exit rtc_from4_cleanup (void)
+static void __exit rtc_from4_cleanup(void)
{
/* Release resource, unregister partitions */
nand_release(rtc_from4_mtd);
/* Free the MTD device structure */
- kfree (rtc_from4_mtd);
+ kfree(rtc_from4_mtd);
#ifdef RTC_FROM4_HWECC
/* Free the reed solomon resources */
@@ -674,10 +650,9 @@ static void __exit rtc_from4_cleanup (void)
}
#endif
}
+
module_exit(rtc_from4_cleanup);
-#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("d.marlin <dmarlin@redhat.com");
MODULE_DESCRIPTION("Board-specific glue layer for AG-AND flash on Renesas FROM_BOARD4");
-
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 5b55599739f3..2c262fe03d8a 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -18,8 +18,9 @@
* 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
* 08-Jul-2005 BJD Fix OOPS when no platform data supplied
* 20-Oct-2005 BJD Fix timing calculation bug
+ * 14-Jan-2006 BJD Allow clock to be stopped when idle
*
- * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $
+ * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd 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
@@ -36,9 +37,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <config/mtd/nand/s3c2410/hwecc.h>
-#include <config/mtd/nand/s3c2410/debug.h>
-
#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
#define DEBUG
#endif
@@ -73,14 +71,20 @@ static int hardware_ecc = 1;
static int hardware_ecc = 0;
#endif
+#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
+static int clock_stop = 1;
+#else
+static const int clock_stop = 0;
+#endif
+
+
/* new oob placement block for use with hardware ecc generation
*/
-static struct nand_oobinfo nand_hw_eccoob = {
- .useecc = MTD_NANDECC_AUTOPLACE,
- .eccbytes = 3,
- .eccpos = {0, 1, 2 },
- .oobfree = { {8, 8} }
+static struct nand_ecclayout nand_hw_eccoob = {
+ .eccbytes = 3,
+ .eccpos = {0, 1, 2},
+ .oobfree = {{8, 8}}
};
/* controller and mtd information */
@@ -135,6 +139,11 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
return dev->dev.platform_data;
}
+static inline int allow_clk_stop(struct s3c2410_nand_info *info)
+{
+ return clock_stop;
+}
+
/* timing calculations */
#define NS_IN_KHZ 1000000
@@ -149,8 +158,7 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
pr_debug("result %d from %ld, %d\n", result, clk, wanted);
if (result > max) {
- printk("%d ns is too big for current clock rate %ld\n",
- wanted, clk);
+ printk("%d ns is too big for current clock rate %ld\n", wanted, clk);
return -1;
}
@@ -164,8 +172,7 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
/* controller setup */
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
- struct platform_device *pdev)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
unsigned long clkrate = clk_get_rate(info->clk);
@@ -177,7 +184,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
clkrate /= 1000; /* turn clock into kHz for ease of use */
if (plat != NULL) {
- tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
+ tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
} else {
@@ -193,19 +200,22 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
}
printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
- tacls, to_ns(tacls, clkrate),
- twrph0, to_ns(twrph0, clkrate),
- twrph1, to_ns(twrph1, clkrate));
+ tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
if (!info->is_s3c2440) {
- cfg = S3C2410_NFCONF_EN;
- cfg |= S3C2410_NFCONF_TACLS(tacls-1);
- cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
- cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
+ cfg = S3C2410_NFCONF_EN;
+ cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
} else {
- cfg = S3C2440_NFCONF_TACLS(tacls-1);
- cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1);
- cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1);
+ cfg = S3C2440_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
+
+ /* enable the controller and de-assert nFCE */
+
+ writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
+ info->regs + S3C2440_NFCONT);
}
pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
@@ -229,7 +239,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
info = nmtd->info;
bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
- reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF);
+ reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
+
+ if (chip != -1 && allow_clk_stop(info))
+ clk_enable(info->clk);
cur = readl(reg);
@@ -243,77 +256,51 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
if (info->platform != NULL) {
if (info->platform->select_chip != NULL)
- (info->platform->select_chip)(nmtd->set, chip);
+ (info->platform->select_chip) (nmtd->set, chip);
}
cur &= ~bit;
}
writel(cur, reg);
+
+ if (chip == -1 && allow_clk_stop(info))
+ clk_disable(info->clk);
}
-/* command and control functions
- *
- * Note, these all use tglx's method of changing the IO_ADDR_W field
- * to make the code simpler, and use the nand layer's code to issue the
- * command and address sequences via the proper IO ports.
+/* s3c2410_nand_hwcontrol
*
+ * Issue command and address cycles to the chip
*/
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
+static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- struct nand_chip *chip = mtd->priv;
-
- switch (cmd) {
- case NAND_CTL_SETNCE:
- case NAND_CTL_CLRNCE:
- printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
- break;
-
- case NAND_CTL_SETCLE:
- chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;
- break;
-
- case NAND_CTL_SETALE:
- chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;
- break;
-
- /* NAND_CTL_CLRCLE: */
- /* NAND_CTL_CLRALE: */
- default:
- chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
- break;
- }
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd, info->regs + S3C2410_NFCMD);
+ else
+ writeb(cmd, info->regs + S3C2410_NFADDR);
}
/* command and control functions */
-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
+static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- struct nand_chip *chip = mtd->priv;
-
- switch (cmd) {
- case NAND_CTL_SETNCE:
- case NAND_CTL_CLRNCE:
- printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
- break;
-
- case NAND_CTL_SETCLE:
- chip->IO_ADDR_W = info->regs + S3C2440_NFCMD;
- break;
-
- case NAND_CTL_SETALE:
- chip->IO_ADDR_W = info->regs + S3C2440_NFADDR;
- break;
-
- /* NAND_CTL_CLRCLE: */
- /* NAND_CTL_CLRALE: */
- default:
- chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
- break;
- }
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd, info->regs + S3C2440_NFCMD);
+ else
+ writeb(cmd, info->regs + S3C2440_NFADDR);
}
/* s3c2410_nand_devready()
@@ -330,22 +317,16 @@ static int s3c2410_nand_devready(struct mtd_info *mtd)
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
}
-
/* ECC handling functions */
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
- u_char *read_ecc, u_char *calc_ecc)
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
{
- pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n",
- mtd, dat, read_ecc, calc_ecc);
+ pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n",
- read_ecc[0], read_ecc[1], read_ecc[2],
- calc_ecc[0], calc_ecc[1], calc_ecc[2]);
+ read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]);
- if (read_ecc[0] == calc_ecc[0] &&
- read_ecc[1] == calc_ecc[1] &&
- read_ecc[2] == calc_ecc[2])
+ if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2])
return 0;
/* we curently have no method for correcting the error */
@@ -378,8 +359,7 @@ static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
}
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -387,15 +367,12 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
- ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
}
-
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
@@ -404,13 +381,11 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd,
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
- ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
}
-
/* over-ride the standard functions for a little more speed. We can
* use read/write block to move the data buffers to/from the controller
*/
@@ -421,8 +396,7 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
readsb(this->IO_ADDR_R, buf, len);
}
-static void s3c2410_nand_write_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
writesb(this->IO_ADDR_W, buf, len);
@@ -459,7 +433,8 @@ static int s3c2410_nand_remove(struct platform_device *pdev)
/* free the common resources */
if (info->clk != NULL && !IS_ERR(info->clk)) {
- clk_disable(info->clk);
+ if (!allow_clk_stop(info))
+ clk_disable(info->clk);
clk_put(info->clk);
}
@@ -488,9 +463,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return add_mtd_device(&mtd->mtd);
if (set->nr_partitions > 0 && set->partitions != NULL) {
- return add_mtd_partitions(&mtd->mtd,
- set->partitions,
- set->nr_partitions);
+ return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions);
}
return add_mtd_device(&mtd->mtd);
@@ -517,7 +490,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
- chip->hwcontrol = s3c2410_nand_hwcontrol;
+ chip->cmd_ctrl = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
@@ -530,26 +503,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
if (info->is_s3c2440) {
chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;
chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
- chip->hwcontrol = s3c2440_nand_hwcontrol;
+ chip->cmd_ctrl = s3c2440_nand_hwcontrol;
}
nmtd->info = info;
nmtd->mtd.priv = chip;
+ nmtd->mtd.owner = THIS_MODULE;
nmtd->set = set;
if (hardware_ecc) {
- chip->correct_data = s3c2410_nand_correct_data;
- chip->enable_hwecc = s3c2410_nand_enable_hwecc;
- chip->calculate_ecc = s3c2410_nand_calculate_ecc;
- chip->eccmode = NAND_ECC_HW3_512;
- chip->autooob = &nand_hw_eccoob;
+ chip->ecc.correct = s3c2410_nand_correct_data;
+ chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 3;
+ chip->ecc.layout = &nand_hw_eccoob;
if (info->is_s3c2440) {
- chip->enable_hwecc = s3c2440_nand_enable_hwecc;
- chip->calculate_ecc = s3c2440_nand_calculate_ecc;
+ chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2440_nand_calculate_ecc;
}
} else {
- chip->eccmode = NAND_ECC_SOFT;
+ chip->ecc.mode = NAND_ECC_SOFT;
}
}
@@ -654,13 +630,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
- pr_debug("initialising set %d (%p, info %p)\n",
- setno, nmtd, info);
+ pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
s3c2410_nand_init_chip(info, nmtd, sets);
- nmtd->scan_res = nand_scan(&nmtd->mtd,
- (sets) ? sets->nr_chips : 1);
+ nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1);
if (nmtd->scan_res == 0) {
s3c2410_nand_add_partition(info, nmtd, sets);
@@ -670,6 +644,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
sets++;
}
+ if (allow_clk_stop(info)) {
+ dev_info(&pdev->dev, "clock idle support enabled\n");
+ clk_disable(info->clk);
+ }
+
pr_debug("initialised ok\n");
return 0;
@@ -681,6 +660,41 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
return err;
}
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+ struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+
+ if (info) {
+ if (!allow_clk_stop(info))
+ clk_disable(info->clk);
+ }
+
+ return 0;
+}
+
+static int s3c24xx_nand_resume(struct platform_device *dev)
+{
+ struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+
+ if (info) {
+ clk_enable(info->clk);
+ s3c2410_nand_inithw(info, dev);
+
+ if (allow_clk_stop(info))
+ clk_disable(info->clk);
+ }
+
+ return 0;
+}
+
+#else
+#define s3c24xx_nand_suspend NULL
+#define s3c24xx_nand_resume NULL
+#endif
+
/* driver device registration */
static int s3c2410_nand_probe(struct platform_device *dev)
@@ -696,6 +710,8 @@ static int s3c2440_nand_probe(struct platform_device *dev)
static struct platform_driver s3c2410_nand_driver = {
.probe = s3c2410_nand_probe,
.remove = s3c2410_nand_remove,
+ .suspend = s3c24xx_nand_suspend,
+ .resume = s3c24xx_nand_resume,
.driver = {
.name = "s3c2410-nand",
.owner = THIS_MODULE,
@@ -705,6 +721,8 @@ static struct platform_driver s3c2410_nand_driver = {
static struct platform_driver s3c2440_nand_driver = {
.probe = s3c2440_nand_probe,
.remove = s3c2410_nand_remove,
+ .suspend = s3c24xx_nand_suspend,
+ .resume = s3c24xx_nand_resume,
.driver = {
.name = "s3c2440-nand",
.owner = THIS_MODULE,
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 1924a4f137c7..21743658d150 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -46,7 +46,6 @@ static int sharpsl_phys_base = 0x0C000000;
#define FLCLE (1 << 1)
#define FLCE0 (1 << 0)
-
/*
* MTD structure for SharpSL
*/
@@ -60,50 +59,44 @@ static struct mtd_info *sharpsl_mtd = NULL;
static int nr_partitions;
static struct mtd_partition sharpsl_nand_default_partition_info[] = {
{
- .name = "System Area",
- .offset = 0,
- .size = 7 * 1024 * 1024,
- },
+ .name = "System Area",
+ .offset = 0,
+ .size = 7 * 1024 * 1024,
+ },
{
- .name = "Root Filesystem",
- .offset = 7 * 1024 * 1024,
- .size = 30 * 1024 * 1024,
- },
+ .name = "Root Filesystem",
+ .offset = 7 * 1024 * 1024,
+ .size = 30 * 1024 * 1024,
+ },
{
- .name = "Home Filesystem",
- .offset = MTDPART_OFS_APPEND ,
- .size = MTDPART_SIZ_FULL ,
- },
+ .name = "Home Filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
};
/*
* hardware specific access to control-lines
+ * ctrl:
+ * NAND_CNE: bit 0 -> bit 0 & 4
+ * NAND_CLE: bit 1 -> bit 1
+ * NAND_ALE: bit 2 -> bit 2
+ *
*/
-static void
-sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
+static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
- switch (cmd) {
- case NAND_CTL_SETCLE:
- writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
- break;
- case NAND_CTL_CLRCLE:
- writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL);
- break;
-
- case NAND_CTL_SETALE:
- writeb(readb(FLASHCTL) | FLALE, FLASHCTL);
- break;
- case NAND_CTL_CLRALE:
- writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
- break;
-
- case NAND_CTL_SETNCE:
- writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
- break;
- case NAND_CTL_CLRNCE:
- writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
- break;
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned char bits = ctrl & 0x07;
+
+ bits |= (ctrl & 0x01) << 4;
+ writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL);
}
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -122,31 +115,26 @@ static struct nand_bbt_descr sharpsl_akita_bbt = {
.pattern = scan_ff_pattern
};
-static struct nand_oobinfo akita_oobinfo = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout akita_oobinfo = {
.eccbytes = 24,
.eccpos = {
- 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
- 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
- 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
- .oobfree = { {0x08, 0x09} }
+ 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
+ 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
+ 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
+ .oobfree = {{0x08, 0x09}}
};
-static int
-sharpsl_nand_dev_ready(struct mtd_info* mtd)
+static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
{
return !((readb(FLASHCTL) & FLRYBY) == 0);
}
-static void
-sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode)
+static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
- writeb(0 ,ECCCLRR);
+ writeb(0, ECCCLRR);
}
-static int
-sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
- u_char* ecc_code)
+static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
{
ecc_code[0] = ~readb(ECCLPUB);
ecc_code[1] = ~readb(ECCLPLB);
@@ -154,47 +142,44 @@ sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
return readb(ECCCNTR) != 0;
}
-
#ifdef CONFIG_MTD_PARTITIONS
const char *part_probes[] = { "cmdlinepart", NULL };
#endif
-
/*
* Main initialization routine
*/
-int __init
-sharpsl_nand_init(void)
+static int __init sharpsl_nand_init(void)
{
struct nand_chip *this;
- struct mtd_partition* sharpsl_partition_info;
+ struct mtd_partition *sharpsl_partition_info;
int err = 0;
/* Allocate memory for MTD device structure and private data */
- sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
- GFP_KERNEL);
+ sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!sharpsl_mtd) {
- printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
+ printk("Unable to allocate SharpSL NAND MTD device structure.\n");
return -ENOMEM;
}
/* map physical adress */
sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
- if(!sharpsl_io_base){
+ if (!sharpsl_io_base) {
printk("ioremap to access Sharp SL NAND chip failed\n");
kfree(sharpsl_mtd);
return -EIO;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&sharpsl_mtd[1]);
+ this = (struct nand_chip *)(&sharpsl_mtd[1]);
/* Initialize structures */
- memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(sharpsl_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
sharpsl_mtd->priv = this;
+ sharpsl_mtd->owner = THIS_MODULE;
/*
* PXA initialize
@@ -205,23 +190,25 @@ sharpsl_nand_init(void)
this->IO_ADDR_R = FLASHIO;
this->IO_ADDR_W = FLASHIO;
/* Set address of hardware control function */
- this->hwcontrol = sharpsl_nand_hwcontrol;
+ this->cmd_ctrl = sharpsl_nand_hwcontrol;
this->dev_ready = sharpsl_nand_dev_ready;
/* 15 us command delay time */
this->chip_delay = 15;
/* set eccmode using hardware ECC */
- this->eccmode = NAND_ECC_HW3_256;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 256;
+ this->ecc.bytes = 3;
this->badblock_pattern = &sharpsl_bbt;
if (machine_is_akita() || machine_is_borzoi()) {
this->badblock_pattern = &sharpsl_akita_bbt;
- this->autooob = &akita_oobinfo;
+ this->ecc.layout = &akita_oobinfo;
}
- this->enable_hwecc = sharpsl_nand_enable_hwecc;
- this->calculate_ecc = sharpsl_nand_calculate_ecc;
- this->correct_data = nand_correct_data;
+ this->ecc.hwctl = sharpsl_nand_enable_hwecc;
+ this->ecc.calculate = sharpsl_nand_calculate_ecc;
+ this->ecc.correct = nand_correct_data;
/* Scan to find existence of the device */
- err=nand_scan(sharpsl_mtd,1);
+ err = nand_scan(sharpsl_mtd, 1);
if (err) {
iounmap(sharpsl_io_base);
kfree(sharpsl_mtd);
@@ -230,24 +217,23 @@ sharpsl_nand_init(void)
/* Register the partitions */
sharpsl_mtd->name = "sharpsl-nand";
- nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
- &sharpsl_partition_info, 0);
+ nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0);
if (nr_partitions <= 0) {
nr_partitions = DEFAULT_NUM_PARTITIONS;
sharpsl_partition_info = sharpsl_nand_default_partition_info;
if (machine_is_poodle()) {
- sharpsl_partition_info[1].size=30 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 22 * 1024 * 1024;
} else if (machine_is_corgi() || machine_is_shepherd()) {
- sharpsl_partition_info[1].size=25 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 25 * 1024 * 1024;
} else if (machine_is_husky()) {
- sharpsl_partition_info[1].size=53 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 53 * 1024 * 1024;
} else if (machine_is_spitz()) {
- sharpsl_partition_info[1].size=5 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 5 * 1024 * 1024;
} else if (machine_is_akita()) {
- sharpsl_partition_info[1].size=58 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 58 * 1024 * 1024;
} else if (machine_is_borzoi()) {
- sharpsl_partition_info[1].size=32 * 1024 * 1024;
+ sharpsl_partition_info[1].size = 32 * 1024 * 1024;
}
}
@@ -261,15 +247,15 @@ sharpsl_nand_init(void)
/* Return happy */
return 0;
}
+
module_init(sharpsl_nand_init);
/*
* Clean up routine
*/
-#ifdef MODULE
static void __exit sharpsl_nand_cleanup(void)
{
- struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1];
+ struct nand_chip *this = (struct nand_chip *)&sharpsl_mtd[1];
/* Release resources, unregister device */
nand_release(sharpsl_mtd);
@@ -279,8 +265,8 @@ static void __exit sharpsl_nand_cleanup(void)
/* Free the MTD device structure */
kfree(sharpsl_mtd);
}
+
module_exit(sharpsl_nand_cleanup);
-#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c
index 9cf1ce718ec1..1f6d429b1583 100644
--- a/drivers/mtd/nand/spia.c
+++ b/drivers/mtd/nand/spia.c
@@ -39,16 +39,16 @@ static struct mtd_info *spia_mtd = NULL;
*/
#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 /*
- * IO offset to Port E data direction
- * register so we can control the IO
- * lines.
- */
+#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 /*
+ * IO offset to Port E data direction
+ * register so we can control the IO
+ * lines.
+ */
/*
* Module stuff
@@ -69,79 +69,84 @@ module_param(spia_peddr, int, 0);
*/
static const struct mtd_partition partition_info[] = {
{
- .name = "SPIA flash partition 1",
- .offset = 0,
- .size = 2*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
- }
+ .name = "SPIA flash partition 2",
+ .offset = 2 * 1024 * 1024,
+ .size = 6 * 1024 * 1024}
};
-#define NUM_PARTITIONS 2
+#define NUM_PARTITIONS 2
/*
* hardware specific access to control-lines
-*/
-static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
-
- switch(cmd){
+ *
+ * ctrl:
+ * NAND_CNE: bit 0 -> bit 2
+ * NAND_CLE: bit 1 -> bit 0
+ * NAND_ALE: bit 2 -> bit 1
+ */
+static void spia_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+ struct nand_chip *chip = mtd->priv;
- case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break;
- case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break;
+ if (ctrl & NAND_CTRL_CHANGE) {
+ void __iomem *addr = spia_io_base + spia_pedr;
+ unsigned char bits;
- case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x02; break;
- case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break;
+ bits = (ctrl & NAND_CNE) << 2;
+ bits |= (ctrl & NAND_CLE | NAND_ALE) >> 1;
+ writeb((readb(addr) & ~0x7) | bits, addr);
+ }
- case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break;
- case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break;
- }
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
/*
* Main initialization routine
*/
-int __init spia_init (void)
+static int __init spia_init(void)
{
struct nand_chip *this;
/* Allocate memory for MTD device structure and private data */
- spia_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
+ spia_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!spia_mtd) {
- printk ("Unable to allocate SPIA NAND MTD device structure.\n");
+ printk("Unable to allocate SPIA NAND MTD device structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&spia_mtd[1]);
+ this = (struct nand_chip *)(&spia_mtd[1]);
/* Initialize structures */
- memset((char *) spia_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(spia_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
spia_mtd->priv = this;
+ spia_mtd->owner = THIS_MODULE;
/*
* Set GPIO Port E control register so that the pins are configured
* to be outputs for controlling the NAND flash.
*/
- (*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
+ (*(volatile unsigned char *)(spia_io_base + spia_peddr)) = 0x07;
/* Set address of NAND IO lines */
- this->IO_ADDR_R = (void __iomem *) spia_fio_base;
- this->IO_ADDR_W = (void __iomem *) spia_fio_base;
+ this->IO_ADDR_R = (void __iomem *)spia_fio_base;
+ this->IO_ADDR_W = (void __iomem *)spia_fio_base;
/* Set address of hardware control function */
- this->hwcontrol = spia_hwcontrol;
+ this->cmd_ctrl = spia_hwcontrol;
/* 15 us command delay time */
this->chip_delay = 15;
/* Scan to find existence of the device */
- if (nand_scan (spia_mtd, 1)) {
- kfree (spia_mtd);
+ if (nand_scan(spia_mtd, 1)) {
+ kfree(spia_mtd);
return -ENXIO;
}
@@ -151,22 +156,22 @@ int __init spia_init (void)
/* Return happy */
return 0;
}
+
module_init(spia_init);
/*
* Clean up routine
*/
-#ifdef MODULE
-static void __exit spia_cleanup (void)
+static void __exit spia_cleanup(void)
{
/* Release resources, unregister device */
- nand_release (spia_mtd);
+ nand_release(spia_mtd);
/* Free the MTD device structure */
- kfree (spia_mtd);
+ kfree(spia_mtd);
}
+
module_exit(spia_cleanup);
-#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com");
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c
index 7609c43cb3ec..f9e2d4a0ab8c 100644
--- a/drivers/mtd/nand/toto.c
+++ b/drivers/mtd/nand/toto.c
@@ -32,6 +32,8 @@
#include <asm/arch-omap1510/hardware.h>
#include <asm/arch/gpio.h>
+#define CONFIG_NAND_WORKAROUND 1
+
/*
* MTD structure for TOTO board
*/
@@ -39,25 +41,6 @@ static struct mtd_info *toto_mtd = NULL;
static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
-#define CONFIG_NAND_WORKAROUND 1
-
-#define NAND_NCE 0x4000
-#define NAND_CLE 0x1000
-#define NAND_ALE 0x0002
-#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE)
-
-#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0)
-#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE)
-#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */
-#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2)
-#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0)
-#else
-#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0)
-#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE)
-#endif
-#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
-#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
-
/*
* Define partitions for flash devices
*/
@@ -91,91 +74,110 @@ static struct mtd_partition partition_info32M[] = {
#define NUM_PARTITIONS32M 3
#define NUM_PARTITIONS64M 4
+
/*
* hardware specific access to control-lines
-*/
-
-static void toto_hwcontrol(struct mtd_info *mtd, int cmd)
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 -> bit 14 (0x4000)
+ * NAND_CLE: bit 1 -> bit 12 (0x1000)
+ * NAND_ALE: bit 2 -> bit 1 (0x0002)
+ */
+static void toto_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned long bits;
- udelay(1); /* hopefully enough time for tc make proceding write to clear */
- switch(cmd){
+ /* hopefully enough time for tc make proceding write to clear */
+ udelay(1);
- case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
- case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
+ bits = (~ctrl & NAND_NCE) << 14;
+ bits |= (ctrl & NAND_CLE) << 12;
+ bits |= (ctrl & NAND_ALE) >> 1;
- case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
- case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
+#warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx
+ gpiosetout(0x5002, bits);
- case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
- case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
+#ifdef CONFIG_NAND_WORKAROUND
+ /* "some" dev boards busted, blue wired to rts2 :( */
+ rts2setout(2, (ctrl & NAND_CLE) << 1);
+#endif
+ /* allow time to ensure gpio state to over take memory write */
+ udelay(1);
}
- udelay(1); /* allow time to ensure gpio state to over take memory write */
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
}
/*
* Main initialization routine
*/
-int __init toto_init (void)
+static int __init toto_init(void)
{
struct nand_chip *this;
int err = 0;
/* Allocate memory for MTD device structure and private data */
- toto_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
+ toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!toto_mtd) {
- printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
+ printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
/* Get pointer to private data */
- this = (struct nand_chip *) (&toto_mtd[1]);
+ this = (struct nand_chip *)(&toto_mtd[1]);
/* Initialize structures */
- memset((char *) toto_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
+ memset(toto_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
toto_mtd->priv = this;
+ toto_mtd->owner = THIS_MODULE;
/* Set address of NAND IO lines */
this->IO_ADDR_R = toto_io_base;
this->IO_ADDR_W = toto_io_base;
- this->hwcontrol = toto_hwcontrol;
+ this->cmd_ctrl = toto_hwcontrol;
this->dev_ready = NULL;
/* 25 us command delay time */
this->chip_delay = 30;
- this->eccmode = NAND_ECC_SOFT;
+ this->ecc.mode = NAND_ECC_SOFT;
- /* Scan to find existance of the device */
- if (nand_scan (toto_mtd, 1)) {
+ /* Scan to find existance of the device */
+ if (nand_scan(toto_mtd, 1)) {
err = -ENXIO;
goto out_mtd;
}
/* Register the partitions */
- switch(toto_mtd->size){
- case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
- case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
- default: {
- printk (KERN_WARNING "Unsupported Nand device\n");
+ switch (toto_mtd->size) {
+ case SZ_64M:
+ add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M);
+ break;
+ case SZ_32M:
+ add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M);
+ break;
+ default:{
+ printk(KERN_WARNING "Unsupported Nand device\n");
err = -ENXIO;
goto out_buf;
}
}
- gpioreserve(NAND_MASK); /* claim our gpios */
- archflashwp(0,0); /* open up flash for writing */
+ gpioreserve(NAND_MASK); /* claim our gpios */
+ archflashwp(0, 0); /* open up flash for writing */
goto out;
-out_buf:
- kfree (this->data_buf);
-out_mtd:
- kfree (toto_mtd);
-out:
+ out_mtd:
+ kfree(toto_mtd);
+ out:
return err;
}
@@ -184,20 +186,21 @@ module_init(toto_init);
/*
* Clean up routine
*/
-static void __exit toto_cleanup (void)
+static void __exit toto_cleanup(void)
{
/* Release resources, unregister device */
- nand_release (toto_mtd);
+ nand_release(toto_mtd);
/* Free the MTD device structure */
- kfree (toto_mtd);
+ kfree(toto_mtd);
/* stop flash writes */
- archflashwp(0,1);
+ archflashwp(0, 1);
/* release gpios to system */
- gpiorelease(NAND_MASK);
+ gpiorelease(NAND_MASK);
}
+
module_exit(toto_cleanup);
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c
new file mode 100644
index 000000000000..a0b4b1edcb0d
--- /dev/null
+++ b/drivers/mtd/nand/ts7250.c
@@ -0,0 +1,206 @@
+/*
+ * drivers/mtd/nand/ts7250.c
+ *
+ * Copyright (C) 2004 Technologic Systems (support@embeddedARM.com)
+ *
+ * Derived from drivers/mtd/nand/edb7312.c
+ * Copyright (C) 2004 Marius Gröger (mag@sysgo.de)
+ *
+ * Derived from drivers/mtd/nand/autcpu12.c
+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: ts7250.c,v 1.4 2004/12/30 22:02:07 joff 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
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This is a device driver for the NAND flash device found on the
+ * TS-7250 board which utilizes a Samsung 32 Mbyte part.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/sizes.h>
+#include <asm/mach-types.h>
+
+/*
+ * MTD structure for TS7250 board
+ */
+static struct mtd_info *ts7250_mtd = NULL;
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+#define NUM_PARTITIONS 3
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info32[] = {
+ {
+ .name = "TS-BOOTROM",
+ .offset = 0x00000000,
+ .size = 0x00004000,
+ }, {
+ .name = "Linux",
+ .offset = 0x00004000,
+ .size = 0x01d00000,
+ }, {
+ .name = "RedBoot",
+ .offset = 0x01d04000,
+ .size = 0x002fc000,
+ },
+};
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info128[] = {
+ {
+ .name = "TS-BOOTROM",
+ .offset = 0x00000000,
+ .size = 0x00004000,
+ }, {
+ .name = "Linux",
+ .offset = 0x00004000,
+ .size = 0x07d00000,
+ }, {
+ .name = "RedBoot",
+ .offset = 0x07d04000,
+ .size = 0x002fc000,
+ },
+};
+#endif
+
+
+/*
+ * hardware specific access to control-lines
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 -> bit 2
+ * NAND_CLE: bit 1 -> bit 1
+ * NAND_ALE: bit 2 -> bit 0
+ */
+static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
+ unsigned char bits;
+
+ bits = (ctrl & NAND_CNE) << 2;
+ bits |= ctrl & NAND_CLE;
+ bits |= (ctrl & NAND_ALE) >> 2;
+
+ __raw_writeb((__raw_readb(addr) & ~0x7) | bits, addr);
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
+}
+
+/*
+ * read device ready pin
+ */
+static int ts7250_device_ready(struct mtd_info *mtd)
+{
+ return __raw_readb(TS72XX_NAND_BUSY_VIRT_BASE) & 0x20;
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init ts7250_init(void)
+{
+ struct nand_chip *this;
+ const char *part_type = 0;
+ int mtd_parts_nb = 0;
+ struct mtd_partition *mtd_parts = 0;
+
+ if (!machine_is_ts72xx() || board_is_ts7200())
+ return -ENXIO;
+
+ /* Allocate memory for MTD device structure and private data */
+ ts7250_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+ if (!ts7250_mtd) {
+ printk("Unable to allocate TS7250 NAND MTD device structure.\n");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *)(&ts7250_mtd[1]);
+
+ /* Initialize structures */
+ memset(ts7250_mtd, 0, sizeof(struct mtd_info));
+ memset(this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ ts7250_mtd->priv = this;
+ ts7250_mtd->owner = THIS_MODULE;
+
+ /* insert callbacks */
+ this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE;
+ this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE;
+ this->cmd_ctrl = ts7250_hwcontrol;
+ this->dev_ready = ts7250_device_ready;
+ this->chip_delay = 15;
+ this->ecc.mode = NAND_ECC_SOFT;
+
+ printk("Searching for NAND flash...\n");
+ /* Scan to find existence of the device */
+ if (nand_scan(ts7250_mtd, 1)) {
+ kfree(ts7250_mtd);
+ return -ENXIO;
+ }
+#ifdef CONFIG_MTD_PARTITIONS
+ ts7250_mtd->name = "ts7250-nand";
+ mtd_parts_nb = parse_mtd_partitions(ts7250_mtd, part_probes, &mtd_parts, 0);
+ if (mtd_parts_nb > 0)
+ part_type = "command line";
+ else
+ mtd_parts_nb = 0;
+#endif
+ if (mtd_parts_nb == 0) {
+ mtd_parts = partition_info32;
+ if (ts7250_mtd->size >= (128 * 0x100000))
+ mtd_parts = partition_info128;
+ mtd_parts_nb = NUM_PARTITIONS;
+ part_type = "static";
+ }
+
+ /* Register the partitions */
+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+ add_mtd_partitions(ts7250_mtd, mtd_parts, mtd_parts_nb);
+
+ /* Return happy */
+ return 0;
+}
+
+module_init(ts7250_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit ts7250_cleanup(void)
+{
+ /* Unregister the device */
+ del_mtd_device(ts7250_mtd);
+
+ /* Free the MTD device structure */
+ kfree(ts7250_mtd);
+}
+
+module_exit(ts7250_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jesse Off <joff@embeddedARM.com>");
+MODULE_DESCRIPTION("MTD map driver for Technologic Systems TS-7250 board");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index d7cd5fa16ba4..dc7573501d8c 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -70,8 +70,6 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
nftl->mbd.devnum = -1;
nftl->mbd.blksize = 512;
nftl->mbd.tr = tr;
- memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
- nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (NFTL_mount(nftl) < 0) {
printk(KERN_WARNING "NFTL: could not mount device\n");
@@ -136,6 +134,69 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
kfree(nftl);
}
+/*
+ * Read oob data from flash
+ */
+int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write oob data to flash
+ */
+int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write data and oob to flash
+ */
+static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf, uint8_t *oob)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs;
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = oob;
+ ops.datbuf = buf;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
#ifdef CONFIG_NFTL_RW
/* Actual NFTL access routines */
@@ -185,6 +246,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
{
+ struct mtd_info *mtd = nftl->mbd.mtd;
u16 BlockMap[MAX_SECTORS_PER_UNIT];
unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
@@ -194,7 +256,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
unsigned int targetEUN;
struct nftl_oob oob;
int inplace = 1;
- size_t retlen;
+ size_t retlen;
memset(BlockMap, 0xff, sizeof(BlockMap));
memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
@@ -210,21 +272,21 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
/* Scan to find the Erase Unit which holds the actual data for each
512-byte block within the Chain.
*/
- silly = MAX_LOOPS;
+ silly = MAX_LOOPS;
targetEUN = BLOCK_NIL;
while (thisEUN <= nftl->lastEUN ) {
- unsigned int status, foldmark;
+ unsigned int status, foldmark;
targetEUN = thisEUN;
for (block = 0; block < nftl->EraseSize / 512; block ++) {
- MTD_READOOB(nftl->mbd.mtd,
- (thisEUN * nftl->EraseSize) + (block * 512),
- 16 , &retlen, (char *)&oob);
+ nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
+ (block * 512), 16 , &retlen,
+ (char *)&oob);
if (block == 2) {
- foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
- if (foldmark == FOLD_MARK_IN_PROGRESS) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "Write Inhibited on EUN %d\n", thisEUN);
+ foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
+ if (foldmark == FOLD_MARK_IN_PROGRESS) {
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "Write Inhibited on EUN %d\n", thisEUN);
inplace = 0;
} else {
/* There's no other reason not to do inplace,
@@ -233,7 +295,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
inplace = 1;
}
}
- status = oob.b.Status | oob.b.Status1;
+ status = oob.b.Status | oob.b.Status1;
BlockLastState[block] = status;
switch(status) {
@@ -328,15 +390,15 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
return BLOCK_NIL;
}
} else {
- /* We put a fold mark in the chain we are folding only if
- we fold in place to help the mount check code. If we do
- not fold in place, it is possible to find the valid
- 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->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
- 8, &retlen, (char *)&oob.u);
- }
+ /* We put a fold mark in the chain we are folding only if we
+ fold in place to help the mount check code. If we do not fold in
+ place, it is possible to find the valid 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;
+ nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
+ 8, &retlen, (char *)&oob.u);
+ }
/* OK. We now know the location of every block in the Virtual Unit Chain,
and the Erase Unit into which we are supposed to be copying.
@@ -353,33 +415,33 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
continue;
}
- /* copy only in non free block (free blocks can only
+ /* copy only in non free block (free blocks can only
happen in case of media errors or deleted blocks) */
- if (BlockMap[block] == BLOCK_NIL)
- continue;
-
- ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
- 512, &retlen, movebuf);
- if (ret < 0) {
- ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
- + (block * 512), 512, &retlen,
- movebuf);
- if (ret != -EIO)
- printk("Error went away on retry.\n");
- }
+ if (BlockMap[block] == BLOCK_NIL)
+ continue;
+
+ ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+ 512, &retlen, movebuf);
+ if (ret < 0 && ret != -EUCLEAN) {
+ ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
+ + (block * 512), 512, &retlen,
+ movebuf);
+ if (ret != -EIO)
+ printk("Error went away on retry.\n");
+ }
memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
- MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
- 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
+
+ nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
+ (block * 512), 512, &retlen, movebuf, (char *)&oob);
}
- /* add the header so that it is now a valid chain */
- oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
- = cpu_to_le16(thisVUC);
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+ /* add the header so that it is now a valid chain */
+ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
+ oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
- MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
- 8, &retlen, (char *)&oob.u);
+ nftl_write_oob(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. */
@@ -396,18 +458,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
unsigned int EUNtmp;
- EUNtmp = nftl->ReplUnitTable[thisEUN];
+ EUNtmp = nftl->ReplUnitTable[thisEUN];
- if (NFTL_formatblock(nftl, thisEUN) < 0) {
+ if (NFTL_formatblock(nftl, thisEUN) < 0) {
/* could not erase : mark block as reserved
*/
nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
- } else {
+ } else {
/* correctly erased : mark it as free */
nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
nftl->numfreeEUNs++;
- }
- thisEUN = EUNtmp;
+ }
+ thisEUN = EUNtmp;
}
/* Make this the new start of chain for thisVUC */
@@ -473,6 +535,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
{
u16 lastEUN;
u16 thisVUC = block / (nftl->EraseSize / 512);
+ struct mtd_info *mtd = nftl->mbd.mtd;
unsigned int writeEUN;
unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
size_t retlen;
@@ -489,21 +552,22 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
*/
lastEUN = BLOCK_NIL;
writeEUN = nftl->EUNtable[thisVUC];
- silly = MAX_LOOPS;
+ silly = MAX_LOOPS;
while (writeEUN <= nftl->lastEUN) {
struct nftl_bci bci;
size_t retlen;
- unsigned int status;
+ unsigned int status;
lastEUN = writeEUN;
- MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci);
+ nftl_read_oob(mtd,
+ (writeEUN * nftl->EraseSize) + blockofs,
+ 8, &retlen, (char *)&bci);
DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
block , writeEUN, le16_to_cpu(bci.Status));
- status = bci.Status | bci.Status1;
+ status = bci.Status | bci.Status1;
switch(status) {
case SECTOR_FREE:
return writeEUN;
@@ -574,10 +638,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
/* We've found a free block. Insert it into the chain. */
if (lastEUN != BLOCK_NIL) {
- thisVUC |= 0x8000; /* It's a replacement block */
+ thisVUC |= 0x8000; /* It's a replacement block */
} else {
- /* The first block in a new chain */
- nftl->EUNtable[thisVUC] = writeEUN;
+ /* The first block in a new chain */
+ nftl->EUNtable[thisVUC] = writeEUN;
}
/* set up the actual EUN we're writing into */
@@ -585,29 +649,29 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
/* ... and on the flash itself */
- MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
+ nftl_read_oob(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->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
- &retlen, (char *)&oob.u);
+ nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
+ &retlen, (char *)&oob.u);
- /* we link the new block to the chain only after the
+ /* we link the new block to the chain only after the
block is ready. It avoids the case where the chain
could point to a free block */
- if (lastEUN != BLOCK_NIL) {
+ if (lastEUN != BLOCK_NIL) {
/* Both in our cache... */
nftl->ReplUnitTable[lastEUN] = writeEUN;
/* ... and on the flash itself */
- MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
+ nftl_read_oob(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->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
- 8, &retlen, (char *)&oob.u);
+ nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
+ 8, &retlen, (char *)&oob.u);
}
return writeEUN;
@@ -639,10 +703,9 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
- MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
- /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
+ nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
+ 512, &retlen, (char *)buffer, (char *)&oob);
return 0;
}
#endif /* CONFIG_NFTL_RW */
@@ -651,20 +714,22 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
char *buffer)
{
struct NFTLrecord *nftl = (void *)mbd;
+ struct mtd_info *mtd = nftl->mbd.mtd;
u16 lastgoodEUN;
u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
- unsigned int status;
+ unsigned int status;
int silly = MAX_LOOPS;
- size_t retlen;
- struct nftl_bci bci;
+ size_t retlen;
+ struct nftl_bci bci;
lastgoodEUN = BLOCK_NIL;
- if (thisEUN != BLOCK_NIL) {
+ if (thisEUN != BLOCK_NIL) {
while (thisEUN < nftl->nb_blocks) {
- if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,
- 8, &retlen, (char *)&bci) < 0)
+ if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
+ blockofs, 8, &retlen,
+ (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
status = bci.Status | bci.Status1;
@@ -694,7 +759,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
}
thisEUN = nftl->ReplUnitTable[thisEUN];
}
- }
+ }
the_end:
if (lastgoodEUN == BLOCK_NIL) {
@@ -703,7 +768,9 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
} else {
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
size_t retlen;
- if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
+ int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
+
+ if (res < 0 && res != -EUCLEAN)
return -EIO;
}
return 0;
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 3b104ebb219a..067262ee8df0 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -33,6 +33,11 @@
char nftlmountrev[]="$Revision: 1.41 $";
+extern int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+extern int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+
/* 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
* the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
@@ -45,6 +50,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
size_t retlen;
u8 buf[SECTORSIZE];
struct NFTLMediaHeader *mh = &nftl->MediaHdr;
+ struct mtd_info *mtd = nftl->mbd.mtd;
unsigned int i;
/* Assume logical EraseSize == physical erasesize for starting the scan.
@@ -65,7 +71,8 @@ static int find_boot_record(struct NFTLrecord *nftl)
/* Check for ANAND header first. Then can whinge if it's found but later
checks fail */
- ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf);
+ ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
+ &retlen, buf);
/* We ignore ret in case the ECC of the MediaHeader is invalid
(which is apparently acceptable) */
if (retlen != SECTORSIZE) {
@@ -90,8 +97,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* To be safer with BIOS, also use erase mark as discriminant */
- if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
- 8, &retlen, (char *)&h1) < 0)) {
+ if ((ret = nftl_read_oob(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->mbd.mtd->index, ret);
continue;
@@ -109,8 +117,8 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* Finally reread to check ECC */
- if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
- &retlen, buf, (char *)&oob, NULL) < 0)) {
+ if ((ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
+ &retlen, buf) < 0)) {
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue;
@@ -228,9 +236,9 @@ device is already correct.
The new DiskOnChip driver already scanned the bad block table. Just query it.
if ((i & (SECTORSIZE - 1)) == 0) {
/* read one sector for every SECTORSIZE of blocks */
- if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
- i + SECTORSIZE, SECTORSIZE, &retlen, buf,
- (char *)&oob, NULL)) < 0) {
+ if ((ret = mtd->read(nftl->mbd.mtd, block * nftl->EraseSize +
+ i + SECTORSIZE, SECTORSIZE, &retlen,
+ buf)) < 0) {
printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
ret);
kfree(nftl->ReplUnitTable);
@@ -268,18 +276,22 @@ static int memcmpb(void *a, int c, int n)
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
int check_oob)
{
- int i;
- size_t retlen;
u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
+ struct mtd_info *mtd = nftl->mbd.mtd;
+ size_t retlen;
+ int i;
for (i = 0; i < len; i += SECTORSIZE) {
- if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
+ if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
- if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
+ if(nftl_read_oob(mtd, address, mtd->oobsize,
+ &retlen, &buf[SECTORSIZE]) < 0)
+ return -1;
+ if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
@@ -301,10 +313,11 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
unsigned int nb_erases, erase_mark;
struct nftl_uci1 uci;
struct erase_info *instr = &nftl->instr;
+ struct mtd_info *mtd = nftl->mbd.mtd;
/* Read the Unit Control Information #1 for Wear-Leveling */
- if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
+ if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+ 8, &retlen, (char *)&uci) < 0)
goto default_uci1;
erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
@@ -321,7 +334,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
instr->mtd = nftl->mbd.mtd;
instr->addr = block * nftl->EraseSize;
instr->len = nftl->EraseSize;
- MTD_ERASE(nftl->mbd.mtd, instr);
+ mtd->erase(mtd, instr);
if (instr->state == MTD_ERASE_FAILED) {
printk("Error while formatting block %d\n", block);
@@ -343,8 +356,8 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
goto fail;
uci.WearInfo = le32_to_cpu(nb_erases);
- if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&uci) < 0)
+ if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
+ 8, 8, &retlen, (char *)&uci) < 0)
goto fail;
return 0;
fail:
@@ -365,6 +378,7 @@ fail:
* case. */
static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
{
+ struct mtd_info *mtd = nftl->mbd.mtd;
unsigned int block, i, status;
struct nftl_bci bci;
int sectors_per_block;
@@ -374,8 +388,9 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
block = first_block;
for (;;) {
for (i = 0; i < sectors_per_block; i++) {
- if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci) < 0)
+ if (nftl_read_oob(mtd,
+ block * nftl->EraseSize + i * SECTORSIZE,
+ 8, &retlen, (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
status = bci.Status | bci.Status1;
@@ -394,9 +409,10 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
/* sector not free actually : mark it as SECTOR_IGNORE */
bci.Status = SECTOR_IGNORE;
bci.Status1 = SECTOR_IGNORE;
- MTD_WRITEOOB(nftl->mbd.mtd,
- block * nftl->EraseSize + i * SECTORSIZE,
- 8, &retlen, (char *)&bci);
+ nftl_write_oob(mtd, block *
+ nftl->EraseSize +
+ i * SECTORSIZE, 8,
+ &retlen, (char *)&bci);
}
break;
default:
@@ -481,13 +497,14 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
* 1. */
static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
{
+ struct mtd_info *mtd = nftl->mbd.mtd;
struct nftl_uci1 h1;
unsigned int erase_mark;
size_t retlen;
/* check erase mark. */
- if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
+ if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
+ &retlen, (char *)&h1) < 0)
return -1;
erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
@@ -501,8 +518,9 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
h1.EraseMark = cpu_to_le16(ERASE_MARK);
h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
h1.WearInfo = cpu_to_le32(0);
- if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0)
+ if (nftl_write_oob(mtd,
+ block * nftl->EraseSize + SECTORSIZE + 8, 8,
+ &retlen, (char *)&h1) < 0)
return -1;
} else {
#if 0
@@ -513,8 +531,8 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
SECTORSIZE, 0) != 0)
return -1;
- if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i,
- 16, &retlen, buf) < 0)
+ if (nftl_read_oob(mtd, block * nftl->EraseSize + i,
+ 16, &retlen, buf) < 0)
return -1;
if (i == SECTORSIZE) {
/* skip erase mark */
@@ -540,11 +558,12 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
*/
static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
{
+ struct mtd_info *mtd = nftl->mbd.mtd;
struct nftl_uci2 uci;
size_t retlen;
- if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
- 8, &retlen, (char *)&uci) < 0)
+ if (nftl_read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
+ 8, &retlen, (char *)&uci) < 0)
return 0;
return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
@@ -558,6 +577,7 @@ int NFTL_mount(struct NFTLrecord *s)
int chain_length, do_format_chain;
struct nftl_uci0 h0;
struct nftl_uci1 h1;
+ struct mtd_info *mtd = s->mbd.mtd;
size_t retlen;
/* search for NFTL MediaHeader and Spare NFTL Media Header */
@@ -582,10 +602,13 @@ int NFTL_mount(struct NFTLrecord *s)
for (;;) {
/* read the block header. If error, we format the chain */
- if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
- &retlen, (char *)&h0) < 0 ||
- MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
- &retlen, (char *)&h1) < 0) {
+ if (nftl_read_oob(mtd,
+ block * s->EraseSize + 8, 8,
+ &retlen, (char *)&h0) < 0 ||
+ nftl_read_oob(mtd,
+ block * s->EraseSize +
+ SECTORSIZE + 8, 8,
+ &retlen, (char *)&h1) < 0) {
s->ReplUnitTable[block] = BLOCK_NIL;
do_format_chain = 1;
break;
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 126ff6bf63d5..5930a03736d7 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -29,6 +29,20 @@ config MTD_ONENAND_GENERIC
help
Support for OneNAND flash via platform device driver.
+config MTD_ONENAND_OTP
+ bool "OneNAND OTP Support"
+ depends on MTD_ONENAND
+ help
+ One Block of the NAND Flash Array memory is reserved as
+ a One-Time Programmable Block memory area.
+ Also, 1st Block of NAND Flash Array can be used as OTP.
+
+ The OTP block can be read, programmed and locked using the same
+ operations as any other NAND Flash Array memory block.
+ OTP block cannot be erased.
+
+ OTP block is fully-guaranteed to be a valid block.
+
config MTD_ONENAND_SYNC_READ
bool "OneNAND Sync. Burst Read Support"
depends on ARCH_OMAP
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index a53a73fc2a5a..84ec40d25438 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -23,8 +23,7 @@
/**
* onenand_oob_64 - oob info for large (2KB) page
*/
-static struct nand_oobinfo onenand_oob_64 = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout onenand_oob_64 = {
.eccbytes = 20,
.eccpos = {
8, 9, 10, 11, 12,
@@ -34,14 +33,14 @@ static struct nand_oobinfo onenand_oob_64 = {
},
.oobfree = {
{2, 3}, {14, 2}, {18, 3}, {30, 2},
- {24, 3}, {46, 2}, {40, 3}, {62, 2} }
+ {34, 3}, {46, 2}, {50, 3}, {62, 2}
+ }
};
/**
* onenand_oob_32 - oob info for middle (1KB) page
*/
-static struct nand_oobinfo onenand_oob_32 = {
- .useecc = MTD_NANDECC_AUTOPLACE,
+static struct nand_ecclayout onenand_oob_32 = {
.eccbytes = 10,
.eccpos = {
8, 9, 10, 11, 12,
@@ -190,7 +189,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
{
struct onenand_chip *this = mtd->priv;
- int value, readcmd = 0;
+ int value, readcmd = 0, block_cmd = 0;
int block, page;
/* Now we use page size operation */
int sectors = 4, count = 4;
@@ -206,6 +205,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case ONENAND_CMD_ERASE:
case ONENAND_CMD_BUFFERRAM:
+ case ONENAND_CMD_OTP_ACCESS:
+ block_cmd = 1;
block = (int) (addr >> this->erase_shift);
page = -1;
break;
@@ -233,6 +234,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
/* Write 'DFS, FBA' of Flash */
value = onenand_block_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+
+ if (block_cmd) {
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+ }
}
if (page != -1) {
@@ -301,6 +308,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
if (state != FL_READING)
cond_resched();
+ touch_softlockup_watchdog();
}
/* To get correct interrupt status in timeout case */
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
@@ -344,7 +352,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
if (ONENAND_CURRENT_BUFFERRAM(this)) {
if (area == ONENAND_DATARAM)
- return mtd->oobblock;
+ return mtd->writesize;
if (area == ONENAND_SPARERAM)
return mtd->oobsize;
}
@@ -372,6 +380,17 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area,
bufferram += onenand_bufferram_offset(mtd, area);
+ if (ONENAND_CHECK_BYTE_ACCESS(count)) {
+ unsigned short word;
+
+ /* Align with word(16-bit) size */
+ count--;
+
+ /* Read word and save byte */
+ word = this->read_word(bufferram + offset + count);
+ buffer[count] = (word & 0xff);
+ }
+
memcpy(buffer, bufferram + offset, count);
return 0;
@@ -399,6 +418,17 @@ static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
+ if (ONENAND_CHECK_BYTE_ACCESS(count)) {
+ unsigned short word;
+
+ /* Align with word(16-bit) size */
+ count--;
+
+ /* Read word and save byte */
+ word = this->read_word(bufferram + offset + count);
+ buffer[count] = (word & 0xff);
+ }
+
memcpy(buffer, bufferram + offset, count);
this->mmcontrol(mtd, 0);
@@ -426,6 +456,22 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
bufferram += onenand_bufferram_offset(mtd, area);
+ if (ONENAND_CHECK_BYTE_ACCESS(count)) {
+ unsigned short word;
+ int byte_offset;
+
+ /* Align with word(16-bit) size */
+ count--;
+
+ /* Calculate byte access offset */
+ byte_offset = offset + count;
+
+ /* Read word and save byte */
+ word = this->read_word(bufferram + byte_offset);
+ word = (word & ~0xff) | buffer[count];
+ this->write_word(word, bufferram + byte_offset);
+ }
+
memcpy(bufferram + offset, buffer, count);
return 0;
@@ -549,31 +595,28 @@ static void onenand_release_device(struct mtd_info *mtd)
}
/**
- * onenand_read_ecc - [MTD Interface] Read data with ECC
+ * onenand_read - [MTD Interface] Read data from flash
* @param mtd MTD device structure
* @param from offset to read from
* @param len number of bytes to read
* @param retlen pointer to variable to store the number of read bytes
* @param buf the databuffer to put data
- * @param oob_buf filesystem supplied oob data buffer
- * @param oobsel oob selection structure
*
- * OneNAND read with ECC
- */
-static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf,
- u_char *oob_buf, struct nand_oobinfo *oobsel)
+ * Read with ecc
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
int read = 0, column;
int thislen;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n");
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n");
*retlen = 0;
return -EINVAL;
}
@@ -584,14 +627,14 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
/* TODO handling oob */
while (read < len) {
- thislen = min_t(int, mtd->oobblock, len - read);
+ thislen = min_t(int, mtd->writesize, len - read);
- column = from & (mtd->oobblock - 1);
- if (column + thislen > mtd->oobblock)
- thislen = mtd->oobblock - column;
+ column = from & (mtd->writesize - 1);
+ if (column + thislen > mtd->writesize)
+ thislen = mtd->writesize - column;
if (!onenand_check_bufferram(mtd, from)) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
ret = this->wait(mtd, FL_READING);
/* First copy data and check return value for ECC handling */
@@ -606,7 +649,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
break;
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret);
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
goto out;
}
@@ -628,23 +671,7 @@ out:
}
/**
- * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
- * @param mtd MTD device structure
- * @param from offset to read from
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put data
- *
- * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
-*/
-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-/**
- * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
* @param mtd MTD device structure
* @param from offset to read from
* @param len number of bytes to read
@@ -653,8 +680,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
*
* OneNAND read out-of-band data from the spare area
*/
-static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column;
@@ -704,7 +731,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
/* Read more? */
if (read < len) {
/* Page size */
- from += mtd->oobblock;
+ from += mtd->writesize;
column = 0;
}
}
@@ -717,8 +744,53 @@ out:
return ret;
}
+/**
+ * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
+ */
+static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
+
+ return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len,
+ &ops->retlen, ops->oobbuf);
+}
+
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
/**
+ * onenand_verify_oob - [GENERIC] verify the oob contents after a write
+ * @param mtd MTD device structure
+ * @param buf the databuffer to verify
+ * @param to offset to read from
+ * @param len number of bytes to read and compare
+ *
+ */
+static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len)
+{
+ struct onenand_chip *this = mtd->priv;
+ char *readp = this->page_buf;
+ int column = to & (mtd->oobsize - 1);
+ int status, i;
+
+ this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+ onenand_update_bufferram(mtd, to, 0);
+ status = this->wait(mtd, FL_READING);
+ if (status)
+ return status;
+
+ this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len);
+
+ for(i = 0; i < len; i++)
+ if (buf[i] != 0xFF && buf[i] != readp[i])
+ return -EBADMSG;
+
+ return 0;
+}
+
+/**
* onenand_verify_page - [GENERIC] verify the chip contents after a write
* @param mtd MTD device structure
* @param buf the databuffer to verify
@@ -731,7 +803,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
void __iomem *dataram0, *dataram1;
int ret = 0;
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
ret = this->wait(mtd, FL_READING);
if (ret)
@@ -741,53 +813,51 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
/* Check, if the two dataram areas are same */
dataram0 = this->base + ONENAND_DATARAM;
- dataram1 = dataram0 + mtd->oobblock;
+ dataram1 = dataram0 + mtd->writesize;
- if (memcmp(dataram0, dataram1, mtd->oobblock))
+ if (memcmp(dataram0, dataram1, mtd->writesize))
return -EBADMSG;
return 0;
}
#else
#define onenand_verify_page(...) (0)
+#define onenand_verify_oob(...) (0)
#endif
-#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0)
+#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
/**
- * onenand_write_ecc - [MTD Interface] OneNAND write with ECC
+ * onenand_write - [MTD Interface] write buffer to FLASH
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of written bytes
* @param buf the data to write
- * @param eccbuf filesystem supplied oob data buffer
- * @param oobsel oob selection structure
*
- * OneNAND write with ECC
+ * Write with ECC
*/
-static int onenand_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)
+static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
{
struct onenand_chip *this = mtd->priv;
int written = 0;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
*retlen = 0;
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n");
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n");
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n");
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n");
return -EINVAL;
}
@@ -796,20 +866,20 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->oobblock, len - written);
+ int thislen = min_t(int, mtd->writesize, len - written);
- this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
- this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);
+ this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
onenand_update_bufferram(mtd, to, 1);
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret);
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
goto out;
}
@@ -818,7 +888,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
/* Only check verify write turn on */
ret = onenand_verify_page(mtd, (u_char *) buf, to);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret);
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
goto out;
}
@@ -839,24 +909,7 @@ out:
}
/**
- * onenand_write - [MTD Interface] compability function for onenand_write_ecc
- * @param mtd MTD device structure
- * @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
- *
- * This function simply calls onenand_write_ecc
- * with oob buffer and oobsel = NULL
- */
-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
-}
-
-/**
- * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
+ * onenand_do_write_oob - [Internal] OneNAND write out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
@@ -865,11 +918,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
*
* OneNAND write out-of-band
*/
-static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
{
struct onenand_chip *this = mtd->priv;
- int column, status;
+ int column, ret = 0;
int written = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
@@ -894,16 +947,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
- this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
- this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+ /* We send data to spare ram with oobsize
+ * to prevent byte access */
+ memset(this->page_buf, 0xff, mtd->oobsize);
+ memcpy(this->page_buf + column, buf, thislen);
+ this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
- status = this->wait(mtd, FL_WRITING);
- if (status)
+ ret = this->wait(mtd, FL_WRITING);
+ if (ret) {
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret);
+ goto out;
+ }
+
+ ret = onenand_verify_oob(mtd, buf, to, thislen);
+ if (ret) {
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret);
goto out;
+ }
written += thislen;
@@ -920,145 +984,22 @@ out:
*retlen = written;
- return 0;
+ return ret;
}
/**
- * onenand_writev_ecc - [MTD Interface] write with iovec with ecc
- * @param mtd MTD device structure
- * @param vecs the iovectors to write
- * @param count number of vectors
- * @param to offset to write to
- * @param retlen pointer to variable to store the number of written bytes
- * @param eccbuf filesystem supplied oob data buffer
- * @param oobsel oob selection structure
- *
- * OneNAND write with iovec with ecc
+ * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
*/
-static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen,
- u_char *eccbuf, struct nand_oobinfo *oobsel)
+static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
- struct onenand_chip *this = mtd->priv;
- unsigned char *pbuf;
- size_t total_len, len;
- int i, written = 0;
- int ret = 0;
-
- /* Preset written len for early exit */
- *retlen = 0;
-
- /* Calculate total length of data */
- total_len = 0;
- for (i = 0; i < count; i++)
- total_len += vecs[i].iov_len;
-
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
-
- /* Do not allow write past end of the device */
- if (unlikely((to + total_len) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n");
- return -EINVAL;
- }
-
- /* Reject writes, which are not page aligned */
- if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n");
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_WRITING);
-
- /* TODO handling oob */
-
- /* Loop until all keve's data has been written */
- len = 0;
- while (count) {
- pbuf = this->page_buf;
- /*
- * If the given tuple is >= pagesize then
- * write it out from the iov
- */
- if ((vecs->iov_len - len) >= mtd->oobblock) {
- pbuf = vecs->iov_base + len;
-
- len += mtd->oobblock;
-
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- } else {
- int cnt = 0, thislen;
- while (cnt < mtd->oobblock) {
- thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len);
- memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen);
- cnt += thislen;
- len += thislen;
-
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- }
- }
-
- this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);
+ BUG_ON(ops->mode != MTD_OOB_PLACE);
- this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock);
- this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
-
- this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);
-
- onenand_update_bufferram(mtd, to, 1);
-
- ret = this->wait(mtd, FL_WRITING);
- if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret);
- goto out;
- }
-
-
- /* Only check verify write turn on */
- ret = onenand_verify_page(mtd, (u_char *) pbuf, to);
- if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret);
- goto out;
- }
-
- written += mtd->oobblock;
-
- to += mtd->oobblock;
- }
-
-out:
- /* Deselect and wakt up anyone waiting on the device */
- onenand_release_device(mtd);
-
- *retlen = written;
-
- return 0;
-}
-
-/**
- * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc
- * @param mtd MTD device structure
- * @param vecs the iovectors to write
- * @param count number of vectors
- * @param to offset to write to
- * @param retlen pointer to variable to store the number of written bytes
- *
- * OneNAND write with kvec. This just calls the ecc function
- */
-static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
-{
- return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
+ return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len,
+ &ops->retlen, ops->oobbuf);
}
/**
@@ -1227,7 +1168,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit access */
ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
- return mtd->write_oob(mtd, ofs , 2, &retlen, buf);
+ return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf);
}
/**
@@ -1324,6 +1265,304 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
return 0;
}
+#ifdef CONFIG_MTD_ONENAND_OTP
+
+/* Interal OTP operation */
+typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
+ size_t *retlen, u_char *buf);
+
+/**
+ * do_otp_read - [DEFAULT] Read OTP block area
+ * @param mtd MTD device structure
+ * @param from The offset to read
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of readbytes
+ * @param buf the databuffer to put/get data
+ *
+ * Read OTP block area.
+ */
+static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret;
+
+ /* Enter OTP access mode */
+ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
+ this->wait(mtd, FL_OTPING);
+
+ ret = mtd->read(mtd, from, len, retlen, buf);
+
+ /* Exit OTP access mode */
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ this->wait(mtd, FL_RESETING);
+
+ return ret;
+}
+
+/**
+ * do_otp_write - [DEFAULT] Write OTP block area
+ * @param mtd MTD device structure
+ * @param from The offset to write
+ * @param len number of bytes to write
+ * @param retlen pointer to variable to store the number of write bytes
+ * @param buf the databuffer to put/get data
+ *
+ * Write OTP block area.
+ */
+static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned char *pbuf = buf;
+ int ret;
+
+ /* Force buffer page aligned */
+ if (len < mtd->writesize) {
+ memcpy(this->page_buf, buf, len);
+ memset(this->page_buf + len, 0xff, mtd->writesize - len);
+ pbuf = this->page_buf;
+ len = mtd->writesize;
+ }
+
+ /* Enter OTP access mode */
+ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
+ this->wait(mtd, FL_OTPING);
+
+ ret = mtd->write(mtd, from, len, retlen, pbuf);
+
+ /* Exit OTP access mode */
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ this->wait(mtd, FL_RESETING);
+
+ return ret;
+}
+
+/**
+ * do_otp_lock - [DEFAULT] Lock OTP block area
+ * @param mtd MTD device structure
+ * @param from The offset to lock
+ * @param len number of bytes to lock
+ * @param retlen pointer to variable to store the number of lock bytes
+ * @param buf the databuffer to put/get data
+ *
+ * Lock OTP block area.
+ */
+static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret;
+
+ /* Enter OTP access mode */
+ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
+ this->wait(mtd, FL_OTPING);
+
+ ret = onenand_do_write_oob(mtd, from, len, retlen, buf);
+
+ /* Exit OTP access mode */
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ this->wait(mtd, FL_RESETING);
+
+ return ret;
+}
+
+/**
+ * onenand_otp_walk - [DEFAULT] Handle OTP operation
+ * @param mtd MTD device structure
+ * @param from The offset to read/write
+ * @param len number of bytes to read/write
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put/get data
+ * @param action do given action
+ * @param mode specify user and factory
+ *
+ * Handle OTP operation.
+ */
+static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf,
+ otp_op_t action, int mode)
+{
+ struct onenand_chip *this = mtd->priv;
+ int otp_pages;
+ int density;
+ int ret = 0;
+
+ *retlen = 0;
+
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ if (density < ONENAND_DEVICE_DENSITY_512Mb)
+ otp_pages = 20;
+ else
+ otp_pages = 10;
+
+ if (mode == MTD_OTP_FACTORY) {
+ from += mtd->writesize * otp_pages;
+ otp_pages = 64 - otp_pages;
+ }
+
+ /* Check User/Factory boundary */
+ if (((mtd->writesize * otp_pages) - (from + len)) < 0)
+ return 0;
+
+ while (len > 0 && otp_pages > 0) {
+ if (!action) { /* OTP Info functions */
+ struct otp_info *otpinfo;
+
+ len -= sizeof(struct otp_info);
+ if (len <= 0)
+ return -ENOSPC;
+
+ otpinfo = (struct otp_info *) buf;
+ otpinfo->start = from;
+ otpinfo->length = mtd->writesize;
+ otpinfo->locked = 0;
+
+ from += mtd->writesize;
+ buf += sizeof(struct otp_info);
+ *retlen += sizeof(struct otp_info);
+ } else {
+ size_t tmp_retlen;
+ int size = len;
+
+ ret = action(mtd, from, len, &tmp_retlen, buf);
+
+ buf += size;
+ len -= size;
+ *retlen += size;
+
+ if (ret < 0)
+ return ret;
+ }
+ otp_pages--;
+ }
+
+ return 0;
+}
+
+/**
+ * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
+ * @param mtd MTD device structure
+ * @param buf the databuffer to put/get data
+ * @param len number of bytes to read
+ *
+ * Read factory OTP info.
+ */
+static int onenand_get_fact_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);
+
+ return ret ? : retlen;
+}
+
+/**
+ * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
+ * @param mtd MTD device structure
+ * @param from The offset to read
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put/get data
+ *
+ * Read factory OTP area.
+ */
+static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
+}
+
+/**
+ * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
+ * @param mtd MTD device structure
+ * @param buf the databuffer to put/get data
+ * @param len number of bytes to read
+ *
+ * Read user OTP info.
+ */
+static int onenand_get_user_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);
+
+ return ret ? : retlen;
+}
+
+/**
+ * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
+ * @param mtd MTD device structure
+ * @param from The offset to read
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put/get data
+ *
+ * Read user OTP area.
+ */
+static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
+}
+
+/**
+ * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
+ * @param mtd MTD device structure
+ * @param from The offset to write
+ * @param len number of bytes to write
+ * @param retlen pointer to variable to store the number of write bytes
+ * @param buf the databuffer to put/get data
+ *
+ * Write user OTP area.
+ */
+static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
+}
+
+/**
+ * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
+ * @param mtd MTD device structure
+ * @param from The offset to lock
+ * @param len number of bytes to unlock
+ *
+ * Write lock mark on spare area in page 0 in OTP block
+ */
+static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len)
+{
+ unsigned char oob_buf[64];
+ size_t retlen;
+ int ret;
+
+ memset(oob_buf, 0xff, mtd->oobsize);
+ /*
+ * Note: OTP lock operation
+ * OTP block : 0xXXFC
+ * 1st block : 0xXXF3 (If chip support)
+ * Both : 0xXXF0 (If chip support)
+ */
+ oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC;
+
+ /*
+ * Write lock mark to 8th word of sector0 of page0 of the spare0.
+ * We write 16 bytes spare area instead of 2 bytes.
+ */
+ from = 0;
+ len = 16;
+
+ ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER);
+
+ return ret ? : retlen;
+}
+#endif /* CONFIG_MTD_ONENAND_OTP */
+
/**
* onenand_print_device_info - Print device ID
* @param device device ID
@@ -1423,15 +1662,15 @@ static int onenand_probe(struct mtd_info *mtd)
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
- mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
- mtd->oobsize = mtd->oobblock >> 5;
+ mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+ mtd->oobsize = mtd->writesize >> 5;
/* Pagers per block is always 64 in OneNAND */
- mtd->erasesize = mtd->oobblock << 6;
+ mtd->erasesize = mtd->writesize << 6;
this->erase_shift = ffs(mtd->erasesize) - 1;
- this->page_shift = ffs(mtd->oobblock) - 1;
+ this->page_shift = ffs(mtd->writesize) - 1;
this->ppb_shift = (this->erase_shift - this->page_shift);
- this->page_mask = (mtd->erasesize / mtd->oobblock) - 1;
+ this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
/* REVIST: Multichip handling */
@@ -1475,7 +1714,6 @@ static void onenand_resume(struct mtd_info *mtd)
"in suspended state\n");
}
-
/**
* onenand_scan - [OneNAND Interface] Scan for the OneNAND device
* @param mtd MTD device structure
@@ -1522,7 +1760,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
/* Allocate buffers, if necessary */
if (!this->page_buf) {
size_t len;
- len = mtd->oobblock + mtd->oobsize;
+ len = mtd->writesize + mtd->oobsize;
this->page_buf = kmalloc(len, GFP_KERNEL);
if (!this->page_buf) {
printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
@@ -1537,40 +1775,42 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
switch (mtd->oobsize) {
case 64:
- this->autooob = &onenand_oob_64;
+ this->ecclayout = &onenand_oob_64;
break;
case 32:
- this->autooob = &onenand_oob_32;
+ this->ecclayout = &onenand_oob_32;
break;
default:
printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
mtd->oobsize);
/* To prevent kernel oops */
- this->autooob = &onenand_oob_32;
+ this->ecclayout = &onenand_oob_32;
break;
}
- memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
+ mtd->ecclayout = this->ecclayout;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+ mtd->flags = MTD_CAP_NANDFLASH;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = onenand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = onenand_read;
mtd->write = onenand_write;
- mtd->read_ecc = onenand_read_ecc;
- mtd->write_ecc = onenand_write_ecc;
mtd->read_oob = onenand_read_oob;
mtd->write_oob = onenand_write_oob;
- mtd->readv = NULL;
- mtd->readv_ecc = NULL;
- mtd->writev = onenand_writev;
- mtd->writev_ecc = onenand_writev_ecc;
+#ifdef CONFIG_MTD_ONENAND_OTP
+ mtd->get_fact_prot_info = onenand_get_fact_prot_info;
+ mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;
+ mtd->get_user_prot_info = onenand_get_user_prot_info;
+ mtd->read_user_prot_reg = onenand_read_user_prot_reg;
+ mtd->write_user_prot_reg = onenand_write_user_prot_reg;
+ mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
+#endif
mtd->sync = onenand_sync;
mtd->lock = NULL;
mtd->unlock = onenand_unlock;
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 4510d3361eaa..1b00dac3d7d6 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,6 +17,9 @@
#include <linux/mtd/onenand.h>
#include <linux/mtd/compatmac.h>
+extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf);
+
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
* @param buf the buffer to search
@@ -87,13 +90,13 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
/* No need to read pages fully,
* just read required OOB bytes */
- ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
- readlen, &retlen, &buf[0]);
+ ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
+ readlen, &retlen, &buf[0]);
if (ret)
return ret;
- if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+ if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index c077d2ec9cdd..5b58523e4d4e 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -1,5 +1,5 @@
/*
- * $Id: redboot.c,v 1.19 2005/12/01 10:03:51 dwmw2 Exp $
+ * $Id: redboot.c,v 1.21 2006/03/30 18:34:37 bjd Exp $
*
* Parse RedBoot-style Flash Image System (FIS) tables and
* produce a Linux partition array to match.
@@ -15,14 +15,14 @@
struct fis_image_desc {
unsigned char name[16]; // Null terminated name
- unsigned long flash_base; // Address within FLASH of image
- unsigned long mem_base; // Address in memory where it executes
- unsigned long size; // Length of image
- unsigned long entry_point; // Execution entry point
- unsigned long data_length; // Length of actual data
- unsigned char _pad[256-(16+7*sizeof(unsigned long))];
- unsigned long desc_cksum; // Checksum over image descriptor
- unsigned long file_cksum; // Checksum over image data
+ uint32_t flash_base; // Address within FLASH of image
+ uint32_t mem_base; // Address in memory where it executes
+ uint32_t size; // Length of image
+ uint32_t entry_point; // Execution entry point
+ uint32_t data_length; // Length of actual data
+ unsigned char _pad[256-(16+7*sizeof(uint32_t))];
+ uint32_t desc_cksum; // Checksum over image descriptor
+ uint32_t file_cksum; // Checksum over image data
};
struct fis_list {
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index a3e00a4635a5..fa4362fb4dd8 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2005 Sean Young <sean@mess.org>
*
- * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $
+ * $Id: rfd_ftl.c,v 1.8 2006/01/15 12:51:44 sean Exp $
*
* This type of flash translation layer (FTL) is used by the Embedded BIOS
* by General Software. It is known as the Resident Flash Disk (RFD), see:
@@ -61,6 +61,7 @@ struct block {
BLOCK_OK,
BLOCK_ERASING,
BLOCK_ERASED,
+ BLOCK_UNUSED,
BLOCK_FAILED
} state;
int free_sectors;
@@ -99,10 +100,8 @@ static int build_block_map(struct partition *part, int block_no)
block->offset = part->block_size * block_no;
if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) {
- block->state = BLOCK_ERASED; /* assumption */
- block->free_sectors = part->data_sectors_per_block;
- part->reserved_block = block_no;
- return 1;
+ block->state = BLOCK_UNUSED;
+ return -ENOENT;
}
block->state = BLOCK_OK;
@@ -124,7 +123,7 @@ static int build_block_map(struct partition *part, int block_no)
entry = 0;
if (entry >= part->sector_count) {
- printk(KERN_NOTICE PREFIX
+ printk(KERN_WARNING PREFIX
"'%s': unit #%d: entry %d corrupt, "
"sector %d out of range\n",
part->mbd.mtd->name, block_no, i, entry);
@@ -132,7 +131,7 @@ static int build_block_map(struct partition *part, int block_no)
}
if (part->sector_map[entry] != -1) {
- printk(KERN_NOTICE PREFIX
+ printk(KERN_WARNING PREFIX
"'%s': more than one entry for sector %d\n",
part->mbd.mtd->name, entry);
part->errors = 1;
@@ -167,7 +166,7 @@ static int scan_header(struct partition *part)
/* each erase block has three bytes header, followed by the map */
part->header_sectors_per_block =
((HEADER_MAP_OFFSET + sectors_per_block) *
- sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+ sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
part->data_sectors_per_block = sectors_per_block -
part->header_sectors_per_block;
@@ -226,7 +225,7 @@ static int scan_header(struct partition *part)
}
if (part->reserved_block == -1) {
- printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n",
+ printk(KERN_WARNING PREFIX "'%s': no empty erase unit found\n",
part->mbd.mtd->name);
part->errors = 1;
@@ -315,7 +314,7 @@ static void erase_callback(struct erase_info *erase)
rc = -EIO;
if (rc) {
- printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
+ printk(KERN_ERR PREFIX "'%s': unable to write RFD "
"header at 0x%lx\n",
part->mbd.mtd->name,
part->blocks[i].offset);
@@ -348,7 +347,7 @@ static int erase_block(struct partition *part, int block)
rc = part->mbd.mtd->erase(part->mbd.mtd, erase);
if (rc) {
- printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' "
+ printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' "
"failed\n", erase->addr, erase->len,
part->mbd.mtd->name);
kfree(erase);
@@ -383,7 +382,7 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
rc = -EIO;
if (rc) {
- printk(KERN_NOTICE PREFIX "error reading '%s' at "
+ printk(KERN_ERR PREFIX "error reading '%s' at "
"0x%lx\n", part->mbd.mtd->name,
part->blocks[block_no].offset);
@@ -423,7 +422,7 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
rc = -EIO;
if (rc) {
- printk(KERN_NOTICE PREFIX "'%s': Unable to "
+ printk(KERN_ERR PREFIX "'%s': Unable to "
"read sector for relocation\n",
part->mbd.mtd->name);
@@ -520,7 +519,7 @@ static int reclaim_block(struct partition *part, u_long *old_sector)
* because if we fill that one up first it'll have the most chance of having
* the least live sectors at reclaim.
*/
-static int find_free_block(const struct partition *part)
+static int find_free_block(struct partition *part)
{
int block, stop;
@@ -533,6 +532,9 @@ static int find_free_block(const struct partition *part)
block != part->reserved_block)
return block;
+ if (part->blocks[block].state == BLOCK_UNUSED)
+ erase_block(part, block);
+
if (++block >= part->total_blocks)
block = 0;
@@ -541,7 +543,7 @@ static int find_free_block(const struct partition *part)
return -1;
}
-static int find_writeable_block(struct partition *part, u_long *old_sector)
+static int find_writable_block(struct partition *part, u_long *old_sector)
{
int rc, block;
size_t retlen;
@@ -570,7 +572,7 @@ static int find_writeable_block(struct partition *part, u_long *old_sector)
rc = -EIO;
if (rc) {
- printk(KERN_NOTICE PREFIX "'%s': unable to read header at "
+ printk(KERN_ERR PREFIX "'%s': unable to read header at "
"0x%lx\n", part->mbd.mtd->name,
part->blocks[block].offset);
goto err;
@@ -602,7 +604,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
rc = -EIO;
if (rc) {
- printk(KERN_WARNING PREFIX "error writing '%s' at "
+ printk(KERN_ERR PREFIX "error writing '%s' at "
"0x%lx\n", part->mbd.mtd->name, addr);
if (rc)
goto err;
@@ -652,7 +654,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
if (part->current_block == -1 ||
!part->blocks[part->current_block].free_sectors) {
- rc = find_writeable_block(part, old_addr);
+ rc = find_writable_block(part, old_addr);
if (rc)
goto err;
}
@@ -675,7 +677,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
rc = -EIO;
if (rc) {
- printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
+ printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
part->mbd.mtd->name, addr);
if (rc)
goto err;
@@ -695,7 +697,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
rc = -EIO;
if (rc) {
- printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
+ printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
part->mbd.mtd->name, addr);
if (rc)
goto err;
@@ -776,7 +778,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
part->block_size = block_size;
else {
if (!mtd->erasesize) {
- printk(KERN_NOTICE PREFIX "please provide block_size");
+ printk(KERN_WARNING PREFIX "please provide block_size");
return;
}
else
@@ -791,8 +793,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (!(mtd->flags & MTD_WRITEABLE))
part->mbd.readonly = 1;
else if (part->errors) {
- printk(KERN_NOTICE PREFIX "'%s': errors found, "
- "setting read-only", mtd->name);
+ printk(KERN_WARNING PREFIX "'%s': errors found, "
+ "setting read-only\n", mtd->name);
part->mbd.readonly = 1;
}
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index f6d51ce34b00..bb44509fd404 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -909,7 +909,7 @@ MODULE_PARM_DESC(irq, "EtherLink IRQ number");
* here also causes the module to be unloaded
*/
-int init_module(void)
+int __init init_module(void)
{
dev_3c501 = el1_probe(-1);
if (IS_ERR(dev_3c501))
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index dcc98afa65d7..cb5ef75450dc 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -688,7 +688,7 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
+int __init
init_module(void)
{
struct net_device *dev;
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 111601ca4ca3..19c0b856c488 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1633,7 +1633,7 @@ MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-int init_module(void)
+int __init init_module(void)
{
int this_dev, found = 0;
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 4db82893909c..6039049259ed 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -932,7 +932,7 @@ module_param(irq, int, 0);
MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
MODULE_PARM_DESC(irq, "(ignored)");
-int init_module(void)
+int __init init_module(void)
{
if (io == 0)
printk("3c507: You should not use auto-probing with insmod!\n");
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index b40885d41680..4bf8510655c5 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1277,7 +1277,7 @@ MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
MODULE_LICENSE("GPL");
-int init_module(void)
+int __init init_module(void)
{
int this_dev,found = 0;
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 6db3301e7965..1b1cb0026072 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1646,7 +1646,7 @@ static struct net_device *this_device;
* insmod multiple modules for now but it's a hack.
*/
-int init_module(void)
+int __init init_module(void)
{
this_device = mc32_probe(-1);
if (IS_ERR(this_device))
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 066e22b01a94..46d8c01437e9 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -19,11 +19,11 @@
See the file COPYING in this distribution for more information.
Contributors:
-
+
Wake-on-LAN support - Felipe Damasio <felipewd@terra.com.br>
PCI suspend/resume - Felipe Damasio <felipewd@terra.com.br>
LinkChg interrupt - Felipe Damasio <felipewd@terra.com.br>
-
+
TODO:
* Test Tx checksumming thoroughly
* Implement dev->tx_timeout
@@ -461,7 +461,7 @@ static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
static inline void cp_set_rxbufsize (struct cp_private *cp)
{
unsigned int mtu = cp->dev->mtu;
-
+
if (mtu > ETH_DATA_LEN)
/* MTU + ethernet header + FCS + optional VLAN tag */
cp->rx_buf_sz = mtu + ETH_HLEN + 8;
@@ -510,7 +510,7 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
static inline unsigned int cp_rx_csum_ok (u32 status)
{
unsigned int protocol = (status >> 16) & 0x3;
-
+
if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
return 1;
else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
@@ -1061,7 +1061,7 @@ static void cp_init_hw (struct cp_private *cp)
cpw8(Config3, PARMEnable);
cp->wol_enabled = 0;
- cpw8(Config5, cpr8(Config5) & PMEStatus);
+ cpw8(Config5, cpr8(Config5) & PMEStatus);
cpw32_f(HiTxRingAddr, 0);
cpw32_f(HiTxRingAddr + 4, 0);
@@ -1351,7 +1351,7 @@ static void netdev_get_wol (struct cp_private *cp,
WAKE_MCAST | WAKE_UCAST;
/* We don't need to go on if WOL is disabled */
if (!cp->wol_enabled) return;
-
+
options = cpr8 (Config3);
if (options & LinkUp) wol->wolopts |= WAKE_PHY;
if (options & MagicPacket) wol->wolopts |= WAKE_MAGIC;
@@ -1919,7 +1919,7 @@ static int cp_resume (struct pci_dev *pdev)
mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
spin_unlock_irqrestore (&cp->lock, flags);
-
+
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index feae7832fc84..abd6261465f1 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -165,7 +165,7 @@ static int multicast_filter_limit = 32;
static int debug = -1;
/*
- * Receive ring size
+ * Receive ring size
* Warning: 64K ring has hardware issues and may lock up.
*/
#if defined(CONFIG_SH_DREAMCAST)
@@ -257,7 +257,7 @@ static struct pci_device_id rtl8139_pci_tbl[] = {
{0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#ifdef CONFIG_SH_SECUREEDGE5410
/* Bogus 8139 silicon reports 8129 without external PROM :-( */
@@ -1824,7 +1824,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
int tmp_work;
#endif
- if (netif_msg_rx_err (tp))
+ if (netif_msg_rx_err (tp))
printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
dev->name, rx_status);
tp->stats.rx_errors++;
@@ -1944,7 +1944,7 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
- while (netif_running(dev) && received < budget
+ while (netif_running(dev) && received < budget
&& (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
u32 ring_offset = cur_rx % RX_BUF_LEN;
u32 rx_status;
@@ -2031,7 +2031,7 @@ no_early_rx:
netif_receive_skb (skb);
} else {
- if (net_ratelimit())
+ if (net_ratelimit())
printk (KERN_WARNING
"%s: Memory squeeze, dropping packet.\n",
dev->name);
@@ -2158,13 +2158,13 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
status = RTL_R16 (IntrStatus);
/* shared irq? */
- if (unlikely((status & rtl8139_intr_mask) == 0))
+ if (unlikely((status & rtl8139_intr_mask) == 0))
goto out;
handled = 1;
/* h/w no longer present (hotplug?) or major error, bail */
- if (unlikely(status == 0xFFFF))
+ if (unlikely(status == 0xFFFF))
goto out;
/* close possible race's with dev_close */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bdaaad8f2123..0c6b45a11d15 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -447,6 +447,7 @@ config MIPS_GT96100ETH
config MIPS_AU1X00_ENET
bool "MIPS AU1000 Ethernet support"
depends on NET_ETHERNET && SOC_AU1X00
+ select PHYLIB
select CRC32
help
If you have an Alchemy Semi AU1X00 based system
@@ -865,6 +866,22 @@ config DM9000
<file:Documentation/networking/net-modules.txt>. The module will be
called dm9000.
+config SMC911X
+ tristate "SMSC LAN911[5678] support"
+ select CRC32
+ select MII
+ depends on NET_ETHERNET && ARCH_PXA
+ help
+ This is a driver for SMSC's LAN911x series of Ethernet chipsets
+ including the new LAN9115, LAN9116, LAN9117, and LAN9118.
+ Say Y if you want it compiled into the kernel,
+ and read the Ethernet-HOWTO, available from
+ <http://www.linuxdoc.org/docs.html#howto>.
+
+ This driver is also available as a module. The module will be
+ called smc911x. If you want to compile it as a module, say M
+ here and read <file:Documentation/modules.txt>
+
config NET_VENDOR_RACAL
bool "Racal-Interlan (Micom) NI cards"
depends on NET_ETHERNET && ISA
@@ -2163,6 +2180,8 @@ config TIGON3
config BNX2
tristate "Broadcom NetXtremeII support"
depends on PCI
+ select CRC32
+ select ZLIB_INFLATE
help
This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
@@ -2311,6 +2330,23 @@ config S2IO_NAPI
If in doubt, say N.
+config MYRI10GE
+ tristate "Myricom Myri-10G Ethernet support"
+ depends on PCI
+ select FW_LOADER
+ select CRC32
+ ---help---
+ This driver supports Myricom Myri-10G Dual Protocol interface in
+ Ethernet mode. If the eeprom on your board is not recent enough,
+ you will need a newer firmware image.
+ You may get this image or more information, at:
+
+ <http://www.myri.com/Myri-10G/>
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called myri10ge.
+
endmenu
source "drivers/net/tokenring/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90468aea077..1eced3287507 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -192,7 +192,9 @@ obj-$(CONFIG_R8169) += r8169.o
obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
obj-$(CONFIG_IBMVETH) += ibmveth.o
obj-$(CONFIG_S2IO) += s2io.o
+obj-$(CONFIG_MYRI10GE) += myri10ge/
obj-$(CONFIG_SMC91X) += smc91x.o
+obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 1363083b4d83..038d5fcb15e6 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -2,13 +2,16 @@
*
* Alchemy Au1x00 ethernet driver
*
- * Copyright 2001,2002,2003 MontaVista Software Inc.
+ * Copyright 2001-2003, 2006 MontaVista Software Inc.
* Copyright 2002 TimeSys Corp.
* Added ethtool/mii-tool support,
* Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
* Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
* or riemer@riemer-nt.de: fixed the link beat detection with
* ioctls (SIOCGMIIPHY)
+ * Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org>
+ * converted to use linux-2.6.x's PHY framework
+ *
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
@@ -52,6 +55,8 @@
#include <linux/mii.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/phy.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -67,7 +72,7 @@ static int au1000_debug = 5;
static int au1000_debug = 3;
#endif
-#define DRV_NAME "au1000eth"
+#define DRV_NAME "au1000_eth"
#define DRV_VERSION "1.5"
#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
@@ -79,7 +84,7 @@ MODULE_LICENSE("GPL");
// prototypes
static void hard_stop(struct net_device *);
static void enable_rx_tx(struct net_device *dev);
-static struct net_device * au1000_probe(u32 ioaddr, int irq, int port_num);
+static struct net_device * au1000_probe(int port_num);
static int au1000_init(struct net_device *);
static int au1000_open(struct net_device *);
static int au1000_close(struct net_device *);
@@ -87,17 +92,15 @@ static int au1000_tx(struct sk_buff *, struct net_device *);
static int au1000_rx(struct net_device *);
static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);
static void au1000_tx_timeout(struct net_device *);
-static int au1000_set_config(struct net_device *dev, struct ifmap *map);
static void set_rx_mode(struct net_device *);
static struct net_device_stats *au1000_get_stats(struct net_device *);
-static void au1000_timer(unsigned long);
static int au1000_ioctl(struct net_device *, struct ifreq *, int);
static int mdio_read(struct net_device *, int, int);
static void mdio_write(struct net_device *, int, int, u16);
-static void dump_mii(struct net_device *dev, int phy_id);
+static void au1000_adjust_link(struct net_device *);
+static void enable_mac(struct net_device *, int);
// externs
-extern void ack_rise_edge_irq(unsigned int);
extern int get_ethernet_addr(char *ethernet_addr);
extern void str2eaddr(unsigned char *ea, unsigned char *str);
extern char * __init prom_getcmdline(void);
@@ -125,705 +128,83 @@ static unsigned char au1000_mac_addr[6] __devinitdata = {
0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00
};
-#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
-#define RUN_AT(x) (jiffies + (x))
-
-// For reading/writing 32-bit words from/to DMA memory
-#define cpu_to_dma32 cpu_to_be32
-#define dma32_to_cpu be32_to_cpu
-
struct au1000_private *au_macs[NUM_ETH_INTERFACES];
-/* FIXME
- * All of the PHY code really should be detached from the MAC
- * code.
+/*
+ * board-specific configurations
+ *
+ * PHY detection algorithm
+ *
+ * If AU1XXX_PHY_STATIC_CONFIG is undefined, the PHY setup is
+ * autodetected:
+ *
+ * mii_probe() first searches the current MAC's MII bus for a PHY,
+ * selecting the first (or last, if AU1XXX_PHY_SEARCH_HIGHEST_ADDR is
+ * defined) PHY address not already claimed by another netdev.
+ *
+ * If nothing was found that way when searching for the 2nd ethernet
+ * controller's PHY and AU1XXX_PHY1_SEARCH_ON_MAC0 is defined, then
+ * the first MII bus is searched as well for an unclaimed PHY; this is
+ * needed in case of a dual-PHY accessible only through the MAC0's MII
+ * bus.
+ *
+ * Finally, if no PHY is found, then the corresponding ethernet
+ * controller is not registered to the network subsystem.
*/
-/* Default advertise */
-#define GENMII_DEFAULT_ADVERTISE \
- ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
- ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
- ADVERTISED_Autoneg
-
-#define GENMII_DEFAULT_FEATURES \
- SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg
-
-int bcm_5201_init(struct net_device *dev, int phy_addr)
-{
- s16 data;
-
- /* Stop auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
- /* Set advertisement to 10/100 and Half/Full duplex
- * (full capabilities) */
- data = mdio_read(dev, phy_addr, MII_ANADV);
- data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
- mdio_write(dev, phy_addr, MII_ANADV, data);
-
- /* Restart auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
- mdio_write(dev, phy_addr, MII_CONTROL, data);
-
- if (au1000_debug > 4)
- dump_mii(dev, phy_addr);
- return 0;
-}
-
-int bcm_5201_reset(struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int
-bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- if (!dev) {
- printk(KERN_ERR "bcm_5201_status error: NULL dev\n");
- return -1;
- }
- aup = (struct au1000_private *) dev->priv;
-
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
- if (mii_data & MII_AUX_100) {
- if (mii_data & MII_AUX_FDX) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
-
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-int lsi_80227_init(struct net_device *dev, int phy_addr)
-{
- if (au1000_debug > 4)
- printk("lsi_80227_init\n");
-
- /* restart auto-negotiation */
- mdio_write(dev, phy_addr, MII_CONTROL,
- MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); // | MII_CNTL_FDX);
- mdelay(1);
-
- /* set up LEDs to correct display */
-#ifdef CONFIG_MIPS_MTX1
- mdio_write(dev, phy_addr, 17, 0xff80);
-#else
- mdio_write(dev, phy_addr, 17, 0xffc0);
-#endif
-
- if (au1000_debug > 4)
- dump_mii(dev, phy_addr);
- return 0;
-}
-
-int lsi_80227_reset(struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
- if (au1000_debug > 4) {
- printk("lsi_80227_reset\n");
- dump_mii(dev, phy_addr);
- }
-
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int
-lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- if (!dev) {
- printk(KERN_ERR "lsi_80227_status error: NULL dev\n");
- return -1;
- }
- aup = (struct au1000_private *) dev->priv;
-
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_PHY_STAT);
- if (mii_data & MII_LSI_PHY_STAT_SPD) {
- if (mii_data & MII_LSI_PHY_STAT_FDX) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
-
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-int am79c901_init(struct net_device *dev, int phy_addr)
-{
- printk("am79c901_init\n");
- return 0;
-}
-
-int am79c901_reset(struct net_device *dev, int phy_addr)
-{
- printk("am79c901_reset\n");
- return 0;
-}
-
-int
-am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- return 0;
-}
-
-int am79c874_init(struct net_device *dev, int phy_addr)
-{
- s16 data;
-
- /* 79c874 has quit resembled bit assignments to BCM5201 */
- if (au1000_debug > 4)
- printk("am79c847_init\n");
-
- /* Stop auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
- /* Set advertisement to 10/100 and Half/Full duplex
- * (full capabilities) */
- data = mdio_read(dev, phy_addr, MII_ANADV);
- data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
- mdio_write(dev, phy_addr, MII_ANADV, data);
-
- /* Restart auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-
- mdio_write(dev, phy_addr, MII_CONTROL, data);
-
- if (au1000_debug > 4) dump_mii(dev, phy_addr);
- return 0;
-}
-
-int am79c874_reset(struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
- if (au1000_debug > 4)
- printk("am79c874_reset\n");
-
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int
-am79c874_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- // printk("am79c874_status\n");
- if (!dev) {
- printk(KERN_ERR "am79c874_status error: NULL dev\n");
- return -1;
- }
-
- aup = (struct au1000_private *) dev->priv;
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, MII_AMD_PHY_STAT);
- if (mii_data & MII_AMD_PHY_STAT_SPD) {
- if (mii_data & MII_AMD_PHY_STAT_FDX) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
-
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-int lxt971a_init(struct net_device *dev, int phy_addr)
-{
- if (au1000_debug > 4)
- printk("lxt971a_init\n");
-
- /* restart auto-negotiation */
- mdio_write(dev, phy_addr, MII_CONTROL,
- MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO | MII_CNTL_FDX);
-
- /* set up LEDs to correct display */
- mdio_write(dev, phy_addr, 20, 0x0422);
-
- if (au1000_debug > 4)
- dump_mii(dev, phy_addr);
- return 0;
-}
-
-int lxt971a_reset(struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
- if (au1000_debug > 4) {
- printk("lxt971a_reset\n");
- dump_mii(dev, phy_addr);
- }
-
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int
-lxt971a_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- if (!dev) {
- printk(KERN_ERR "lxt971a_status error: NULL dev\n");
- return -1;
- }
- aup = (struct au1000_private *) dev->priv;
-
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, MII_INTEL_PHY_STAT);
- if (mii_data & MII_INTEL_PHY_STAT_SPD) {
- if (mii_data & MII_INTEL_PHY_STAT_FDX) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
-
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-int ks8995m_init(struct net_device *dev, int phy_addr)
-{
- s16 data;
-
-// printk("ks8995m_init\n");
- /* Stop auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
- /* Set advertisement to 10/100 and Half/Full duplex
- * (full capabilities) */
- data = mdio_read(dev, phy_addr, MII_ANADV);
- data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
- mdio_write(dev, phy_addr, MII_ANADV, data);
-
- /* Restart auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
- mdio_write(dev, phy_addr, MII_CONTROL, data);
-
- if (au1000_debug > 4) dump_mii(dev, phy_addr);
-
- return 0;
-}
-
-int ks8995m_reset(struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
-// printk("ks8995m_reset\n");
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int ks8995m_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- if (!dev) {
- printk(KERN_ERR "ks8995m_status error: NULL dev\n");
- return -1;
- }
- aup = (struct au1000_private *) dev->priv;
-
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
- if (mii_data & MII_AUX_100) {
- if (mii_data & MII_AUX_FDX) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
-
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-int
-smsc_83C185_init (struct net_device *dev, int phy_addr)
-{
- s16 data;
-
- if (au1000_debug > 4)
- printk("smsc_83C185_init\n");
-
- /* Stop auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
- /* Set advertisement to 10/100 and Half/Full duplex
- * (full capabilities) */
- data = mdio_read(dev, phy_addr, MII_ANADV);
- data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
- mdio_write(dev, phy_addr, MII_ANADV, data);
-
- /* Restart auto-negotiation */
- data = mdio_read(dev, phy_addr, MII_CONTROL);
- data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-
- mdio_write(dev, phy_addr, MII_CONTROL, data);
-
- if (au1000_debug > 4) dump_mii(dev, phy_addr);
- return 0;
-}
-
-int
-smsc_83C185_reset (struct net_device *dev, int phy_addr)
-{
- s16 mii_control, timeout;
-
- if (au1000_debug > 4)
- printk("smsc_83C185_reset\n");
-
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
- mdelay(1);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
- if ((mii_control & MII_CNTL_RESET) == 0)
- break;
- mdelay(1);
- }
- if (mii_control & MII_CNTL_RESET) {
- printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
- return -1;
- }
- return 0;
-}
-
-int
-smsc_83C185_status (struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- u16 mii_data;
- struct au1000_private *aup;
-
- if (!dev) {
- printk(KERN_ERR "smsc_83C185_status error: NULL dev\n");
- return -1;
- }
-
- aup = (struct au1000_private *) dev->priv;
- mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-
- if (mii_data & MII_STAT_LINK) {
- *link = 1;
- mii_data = mdio_read(dev, aup->phy_addr, 0x1f);
- if (mii_data & (1<<3)) {
- if (mii_data & (1<<4)) {
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- }
- else {
- *speed = IF_PORT_100BASETX;
- dev->if_port = IF_PORT_100BASETX;
- }
- }
- else {
- *speed = IF_PORT_10BASET;
- dev->if_port = IF_PORT_10BASET;
- }
- }
- else {
- *link = 0;
- *speed = 0;
- dev->if_port = IF_PORT_UNKNOWN;
- }
- return 0;
-}
-
-
-#ifdef CONFIG_MIPS_BOSPORUS
-int stub_init(struct net_device *dev, int phy_addr)
-{
- //printk("PHY stub_init\n");
- return 0;
-}
-
-int stub_reset(struct net_device *dev, int phy_addr)
-{
- //printk("PHY stub_reset\n");
- return 0;
-}
-
-int
-stub_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
- //printk("PHY stub_status\n");
- *link = 1;
- /* hmmm, revisit */
- *speed = IF_PORT_100BASEFX;
- dev->if_port = IF_PORT_100BASEFX;
- return 0;
-}
-#endif
-
-struct phy_ops bcm_5201_ops = {
- bcm_5201_init,
- bcm_5201_reset,
- bcm_5201_status,
-};
-
-struct phy_ops am79c874_ops = {
- am79c874_init,
- am79c874_reset,
- am79c874_status,
-};
-
-struct phy_ops am79c901_ops = {
- am79c901_init,
- am79c901_reset,
- am79c901_status,
-};
-
-struct phy_ops lsi_80227_ops = {
- lsi_80227_init,
- lsi_80227_reset,
- lsi_80227_status,
-};
+/* autodetection defaults */
+#undef AU1XXX_PHY_SEARCH_HIGHEST_ADDR
+#define AU1XXX_PHY1_SEARCH_ON_MAC0
-struct phy_ops lxt971a_ops = {
- lxt971a_init,
- lxt971a_reset,
- lxt971a_status,
-};
+/* static PHY setup
+ *
+ * most boards PHY setup should be detectable properly with the
+ * autodetection algorithm in mii_probe(), but in some cases (e.g. if
+ * you have a switch attached, or want to use the PHY's interrupt
+ * notification capabilities) you can provide a static PHY
+ * configuration here
+ *
+ * IRQs may only be set, if a PHY address was configured
+ * If a PHY address is given, also a bus id is required to be set
+ *
+ * ps: make sure the used irqs are configured properly in the board
+ * specific irq-map
+ */
-struct phy_ops ks8995m_ops = {
- ks8995m_init,
- ks8995m_reset,
- ks8995m_status,
-};
+#if defined(CONFIG_MIPS_BOSPORUS)
+/*
+ * Micrel/Kendin 5 port switch attached to MAC0,
+ * MAC0 is associated with PHY address 5 (== WAN port)
+ * MAC1 is not associated with any PHY, since it's connected directly
+ * to the switch.
+ * no interrupts are used
+ */
+# define AU1XXX_PHY_STATIC_CONFIG
-struct phy_ops smsc_83C185_ops = {
- smsc_83C185_init,
- smsc_83C185_reset,
- smsc_83C185_status,
-};
+# define AU1XXX_PHY0_ADDR 5
+# define AU1XXX_PHY0_BUSID 0
+# undef AU1XXX_PHY0_IRQ
-#ifdef CONFIG_MIPS_BOSPORUS
-struct phy_ops stub_ops = {
- stub_init,
- stub_reset,
- stub_status,
-};
+# undef AU1XXX_PHY1_ADDR
+# undef AU1XXX_PHY1_BUSID
+# undef AU1XXX_PHY1_IRQ
#endif
-static struct mii_chip_info {
- const char * name;
- u16 phy_id0;
- u16 phy_id1;
- struct phy_ops *phy_ops;
- int dual_phy;
-} mii_chip_table[] = {
- {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
- {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
- {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
- {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0},
- {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
- {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
- {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
- {"Intel LXT971A Dual Speed PHY",0x0013,0x78e2, &lxt971a_ops,0},
- {"Kendin KS8995M 10/100 BaseT PHY",0x0022,0x1450, &ks8995m_ops,0},
- {"SMSC LAN83C185 10/100 BaseT PHY",0x0007,0xc0a3, &smsc_83C185_ops,0},
-#ifdef CONFIG_MIPS_BOSPORUS
- {"Stub", 0x1234, 0x5678, &stub_ops },
+#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)
+# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet
#endif
- {0,},
-};
-static int mdio_read(struct net_device *dev, int phy_id, int reg)
+/*
+ * MII operations
+ */
+static int mdio_read(struct net_device *dev, int phy_addr, int reg)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- volatile u32 *mii_control_reg;
- volatile u32 *mii_data_reg;
+ volatile u32 *const mii_control_reg = &aup->mac->mii_control;
+ volatile u32 *const mii_data_reg = &aup->mac->mii_data;
u32 timedout = 20;
u32 mii_control;
- #ifdef CONFIG_BCM5222_DUAL_PHY
- /* First time we probe, it's for the mac0 phy.
- * Since we haven't determined yet that we have a dual phy,
- * aup->mii->mii_control_reg won't be setup and we'll
- * default to the else statement.
- * By the time we probe for the mac1 phy, the mii_control_reg
- * will be setup to be the address of the mac0 phy control since
- * both phys are controlled through mac0.
- */
- if (aup->mii && aup->mii->mii_control_reg) {
- mii_control_reg = aup->mii->mii_control_reg;
- mii_data_reg = aup->mii->mii_data_reg;
- }
- else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
- /* assume both phys are controlled through mac0 */
- mii_control_reg = au_macs[0]->mii->mii_control_reg;
- mii_data_reg = au_macs[0]->mii->mii_data_reg;
- }
- else
- #endif
- {
- /* default control and data reg addresses */
- mii_control_reg = &aup->mac->mii_control;
- mii_data_reg = &aup->mac->mii_data;
- }
-
while (*mii_control_reg & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
@@ -834,7 +215,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg)
}
mii_control = MAC_SET_MII_SELECT_REG(reg) |
- MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;
+ MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
*mii_control_reg = mii_control;
@@ -850,32 +231,14 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg)
return (int)*mii_data_reg;
}
-static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
+static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- volatile u32 *mii_control_reg;
- volatile u32 *mii_data_reg;
+ volatile u32 *const mii_control_reg = &aup->mac->mii_control;
+ volatile u32 *const mii_data_reg = &aup->mac->mii_data;
u32 timedout = 20;
u32 mii_control;
- #ifdef CONFIG_BCM5222_DUAL_PHY
- if (aup->mii && aup->mii->mii_control_reg) {
- mii_control_reg = aup->mii->mii_control_reg;
- mii_data_reg = aup->mii->mii_data_reg;
- }
- else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
- /* assume both phys are controlled through mac0 */
- mii_control_reg = au_macs[0]->mii->mii_control_reg;
- mii_data_reg = au_macs[0]->mii->mii_data_reg;
- }
- else
- #endif
- {
- /* default control and data reg addresses */
- mii_control_reg = &aup->mac->mii_control;
- mii_data_reg = &aup->mac->mii_data;
- }
-
while (*mii_control_reg & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
@@ -886,165 +249,145 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
}
mii_control = MAC_SET_MII_SELECT_REG(reg) |
- MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;
+ MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
*mii_data_reg = value;
*mii_control_reg = mii_control;
}
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+ /* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
+ * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
+ struct net_device *const dev = bus->priv;
+
+ enable_mac(dev, 0); /* make sure the MAC associated with this
+ * mii_bus is enabled */
+ return mdio_read(dev, phy_addr, regnum);
+}
-static void dump_mii(struct net_device *dev, int phy_id)
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+ u16 value)
{
- int i, val;
+ struct net_device *const dev = bus->priv;
- for (i = 0; i < 7; i++) {
- if ((val = mdio_read(dev, phy_id, i)) >= 0)
- printk("%s: MII Reg %d=%x\n", dev->name, i, val);
- }
- for (i = 16; i < 25; i++) {
- if ((val = mdio_read(dev, phy_id, i)) >= 0)
- printk("%s: MII Reg %d=%x\n", dev->name, i, val);
- }
+ enable_mac(dev, 0); /* make sure the MAC associated with this
+ * mii_bus is enabled */
+ mdio_write(dev, phy_addr, regnum, value);
+ return 0;
}
-static int mii_probe (struct net_device * dev)
+static int mdiobus_reset(struct mii_bus *bus)
{
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
- int phy_addr;
-#ifdef CONFIG_MIPS_BOSPORUS
- int phy_found=0;
-#endif
+ struct net_device *const dev = bus->priv;
- /* search for total of 32 possible mii phy addresses */
- for (phy_addr = 0; phy_addr < 32; phy_addr++) {
- u16 mii_status;
- u16 phy_id0, phy_id1;
- int i;
+ enable_mac(dev, 0); /* make sure the MAC associated with this
+ * mii_bus is enabled */
+ return 0;
+}
- #ifdef CONFIG_BCM5222_DUAL_PHY
- /* Mask the already found phy, try next one */
- if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
- if (au_macs[0]->phy_addr == phy_addr)
- continue;
- }
- #endif
-
- mii_status = mdio_read(dev, phy_addr, MII_STATUS);
- if (mii_status == 0xffff || mii_status == 0x0000)
- /* the mii is not accessable, try next one */
- continue;
-
- phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);
- phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1);
-
- /* search our mii table for the current mii */
- for (i = 0; mii_chip_table[i].phy_id1; i++) {
- if (phy_id0 == mii_chip_table[i].phy_id0 &&
- phy_id1 == mii_chip_table[i].phy_id1) {
- struct mii_phy * mii_phy = aup->mii;
-
- printk(KERN_INFO "%s: %s at phy address %d\n",
- dev->name, mii_chip_table[i].name,
- phy_addr);
-#ifdef CONFIG_MIPS_BOSPORUS
- phy_found = 1;
-#endif
- mii_phy->chip_info = mii_chip_table+i;
- aup->phy_addr = phy_addr;
- aup->want_autoneg = 1;
- aup->phy_ops = mii_chip_table[i].phy_ops;
- aup->phy_ops->phy_init(dev,phy_addr);
-
- // Check for dual-phy and then store required
- // values and set indicators. We need to do
- // this now since mdio_{read,write} need the
- // control and data register addresses.
- #ifdef CONFIG_BCM5222_DUAL_PHY
- if ( mii_chip_table[i].dual_phy) {
-
- /* assume both phys are controlled
- * through MAC0. Board specific? */
-
- /* sanity check */
- if (!au_macs[0] || !au_macs[0]->mii)
- return -1;
- aup->mii->mii_control_reg = (u32 *)
- &au_macs[0]->mac->mii_control;
- aup->mii->mii_data_reg = (u32 *)
- &au_macs[0]->mac->mii_data;
- }
- #endif
- goto found;
- }
+static int mii_probe (struct net_device *dev)
+{
+ struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+ struct phy_device *phydev = NULL;
+
+#if defined(AU1XXX_PHY_STATIC_CONFIG)
+ BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
+
+ if(aup->mac_id == 0) { /* get PHY0 */
+# if defined(AU1XXX_PHY0_ADDR)
+ phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR];
+# else
+ printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
+ dev->name);
+ return 0;
+# endif /* defined(AU1XXX_PHY0_ADDR) */
+ } else if (aup->mac_id == 1) { /* get PHY1 */
+# if defined(AU1XXX_PHY1_ADDR)
+ phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR];
+# else
+ printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
+ dev->name);
+ return 0;
+# endif /* defined(AU1XXX_PHY1_ADDR) */
+ }
+
+#else /* defined(AU1XXX_PHY_STATIC_CONFIG) */
+ int phy_addr;
+
+ /* find the first (lowest address) PHY on the current MAC's MII bus */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
+ if (aup->mii_bus.phy_map[phy_addr]) {
+ phydev = aup->mii_bus.phy_map[phy_addr];
+# if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR)
+ break; /* break out with first one found */
+# endif
}
- }
-found:
-
-#ifdef CONFIG_MIPS_BOSPORUS
- /* This is a workaround for the Micrel/Kendin 5 port switch
- The second MAC doesn't see a PHY connected... so we need to
- trick it into thinking we have one.
-
- If this kernel is run on another Au1500 development board
- the stub will be found as well as the actual PHY. However,
- the last found PHY will be used... usually at Addr 31 (Db1500).
- */
- if ( (!phy_found) )
- {
- u16 phy_id0, phy_id1;
- int i;
- phy_id0 = 0x1234;
- phy_id1 = 0x5678;
-
- /* search our mii table for the current mii */
- for (i = 0; mii_chip_table[i].phy_id1; i++) {
- if (phy_id0 == mii_chip_table[i].phy_id0 &&
- phy_id1 == mii_chip_table[i].phy_id1) {
- struct mii_phy * mii_phy;
-
- printk(KERN_INFO "%s: %s at phy address %d\n",
- dev->name, mii_chip_table[i].name,
- phy_addr);
- mii_phy = kmalloc(sizeof(struct mii_phy),
- GFP_KERNEL);
- if (mii_phy) {
- mii_phy->chip_info = mii_chip_table+i;
- aup->phy_addr = phy_addr;
- mii_phy->next = aup->mii;
- aup->phy_ops =
- mii_chip_table[i].phy_ops;
- aup->mii = mii_phy;
- aup->phy_ops->phy_init(dev,phy_addr);
- } else {
- printk(KERN_ERR "%s: out of memory\n",
- dev->name);
- return -1;
- }
- mii_phy->chip_info = mii_chip_table+i;
- aup->phy_addr = phy_addr;
- aup->phy_ops = mii_chip_table[i].phy_ops;
- aup->phy_ops->phy_init(dev,phy_addr);
- break;
- }
+# if defined(AU1XXX_PHY1_SEARCH_ON_MAC0)
+ /* try harder to find a PHY */
+ if (!phydev && (aup->mac_id == 1)) {
+ /* no PHY found, maybe we have a dual PHY? */
+ printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, "
+ "let's see if it's attached to MAC0...\n");
+
+ BUG_ON(!au_macs[0]);
+
+ /* find the first (lowest address) non-attached PHY on
+ * the MAC0 MII bus */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ struct phy_device *const tmp_phydev =
+ au_macs[0]->mii_bus.phy_map[phy_addr];
+
+ if (!tmp_phydev)
+ continue; /* no PHY here... */
+
+ if (tmp_phydev->attached_dev)
+ continue; /* already claimed by MAC0 */
+
+ phydev = tmp_phydev;
+ break; /* found it */
}
}
- if (aup->mac_id == 0) {
- /* the Bosporus phy responds to addresses 0-5 but
- * 5 is the correct one.
- */
- aup->phy_addr = 5;
- }
-#endif
+# endif /* defined(AU1XXX_PHY1_SEARCH_OTHER_BUS) */
- if (aup->mii->chip_info == NULL) {
- printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n",
- dev->name);
+#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */
+ if (!phydev) {
+ printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
return -1;
}
- printk(KERN_INFO "%s: Using %s as default\n",
- dev->name, aup->mii->chip_info->name);
+ /* now we are supposed to have a proper phydev, to attach to... */
+ BUG_ON(!phydev);
+ BUG_ON(phydev->attached_dev);
+
+ phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0);
+
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+
+ aup->old_link = 0;
+ aup->old_speed = 0;
+ aup->old_duplex = -1;
+ aup->phy_dev = phydev;
+
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
return 0;
}
@@ -1096,35 +439,38 @@ static void hard_stop(struct net_device *dev)
au_sync_delay(10);
}
-
-static void reset_mac(struct net_device *dev)
+static void enable_mac(struct net_device *dev, int force_reset)
{
- int i;
- u32 flags;
+ unsigned long flags;
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- if (au1000_debug > 4)
- printk(KERN_INFO "%s: reset mac, aup %x\n",
- dev->name, (unsigned)aup);
-
spin_lock_irqsave(&aup->lock, flags);
- if (aup->timer.function == &au1000_timer) {/* check if timer initted */
- del_timer(&aup->timer);
- }
- hard_stop(dev);
- #ifdef CONFIG_BCM5222_DUAL_PHY
- if (aup->mac_id != 0) {
- #endif
- /* If BCM5222, we can't leave MAC0 in reset because then
- * we can't access the dual phy for ETH1 */
+ if(force_reset || (!aup->mac_enabled)) {
*aup->enable = MAC_EN_CLOCK_ENABLE;
au_sync_delay(2);
- *aup->enable = 0;
+ *aup->enable = (MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
+ | MAC_EN_CLOCK_ENABLE);
au_sync_delay(2);
- #ifdef CONFIG_BCM5222_DUAL_PHY
+
+ aup->mac_enabled = 1;
}
- #endif
+
+ spin_unlock_irqrestore(&aup->lock, flags);
+}
+
+static void reset_mac_unlocked(struct net_device *dev)
+{
+ struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+ int i;
+
+ hard_stop(dev);
+
+ *aup->enable = MAC_EN_CLOCK_ENABLE;
+ au_sync_delay(2);
+ *aup->enable = 0;
+ au_sync_delay(2);
+
aup->tx_full = 0;
for (i = 0; i < NUM_RX_DMA; i++) {
/* reset control bits */
@@ -1134,9 +480,26 @@ static void reset_mac(struct net_device *dev)
/* reset control bits */
aup->tx_dma_ring[i]->buff_stat &= ~0xf;
}
- spin_unlock_irqrestore(&aup->lock, flags);
+
+ aup->mac_enabled = 0;
+
}
+static void reset_mac(struct net_device *dev)
+{
+ struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+ unsigned long flags;
+
+ if (au1000_debug > 4)
+ printk(KERN_INFO "%s: reset mac, aup %x\n",
+ dev->name, (unsigned)aup);
+
+ spin_lock_irqsave(&aup->lock, flags);
+
+ reset_mac_unlocked (dev);
+
+ spin_unlock_irqrestore(&aup->lock, flags);
+}
/*
* Setup the receive and transmit "rings". These pointers are the addresses
@@ -1159,12 +522,27 @@ setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
}
static struct {
- int port;
u32 base_addr;
u32 macen_addr;
int irq;
struct net_device *dev;
-} iflist[2];
+} iflist[2] = {
+#ifdef CONFIG_SOC_AU1000
+ {AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT},
+ {AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1100
+ {AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1500
+ {AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT},
+ {AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT}
+#endif
+#ifdef CONFIG_SOC_AU1550
+ {AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT},
+ {AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT}
+#endif
+};
static int num_ifs;
@@ -1175,58 +553,14 @@ static int num_ifs;
*/
static int __init au1000_init_module(void)
{
- struct cpuinfo_mips *c = &current_cpu_data;
int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
struct net_device *dev;
int i, found_one = 0;
- switch (c->cputype) {
-#ifdef CONFIG_SOC_AU1000
- case CPU_AU1000:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1000_ETH0_BASE;
- iflist[1].base_addr = AU1000_ETH1_BASE;
- iflist[0].macen_addr = AU1000_MAC0_ENABLE;
- iflist[1].macen_addr = AU1000_MAC1_ENABLE;
- iflist[0].irq = AU1000_MAC0_DMA_INT;
- iflist[1].irq = AU1000_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1100
- case CPU_AU1100:
- num_ifs = 1 - ni;
- iflist[0].base_addr = AU1100_ETH0_BASE;
- iflist[0].macen_addr = AU1100_MAC0_ENABLE;
- iflist[0].irq = AU1100_MAC0_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1500
- case CPU_AU1500:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1500_ETH0_BASE;
- iflist[1].base_addr = AU1500_ETH1_BASE;
- iflist[0].macen_addr = AU1500_MAC0_ENABLE;
- iflist[1].macen_addr = AU1500_MAC1_ENABLE;
- iflist[0].irq = AU1500_MAC0_DMA_INT;
- iflist[1].irq = AU1500_MAC1_DMA_INT;
- break;
-#endif
-#ifdef CONFIG_SOC_AU1550
- case CPU_AU1550:
- num_ifs = 2 - ni;
- iflist[0].base_addr = AU1550_ETH0_BASE;
- iflist[1].base_addr = AU1550_ETH1_BASE;
- iflist[0].macen_addr = AU1550_MAC0_ENABLE;
- iflist[1].macen_addr = AU1550_MAC1_ENABLE;
- iflist[0].irq = AU1550_MAC0_DMA_INT;
- iflist[1].irq = AU1550_MAC1_DMA_INT;
- break;
-#endif
- default:
- num_ifs = 0;
- }
+ num_ifs = NUM_ETH_INTERFACES - ni;
+
for(i = 0; i < num_ifs; i++) {
- dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
+ dev = au1000_probe(i);
iflist[i].dev = dev;
if (dev)
found_one++;
@@ -1236,178 +570,31 @@ static int __init au1000_init_module(void)
return 0;
}
-static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
-{
- struct au1000_private *aup = (struct au1000_private *)dev->priv;
- u16 ctl, adv;
-
- /* Setup standard advertise */
- adv = mdio_read(dev, aup->phy_addr, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- mdio_write(dev, aup->phy_addr, MII_ADVERTISE, adv);
-
- /* Start/Restart aneg */
- ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
-
- return 0;
-}
+/*
+ * ethtool operations
+ */
-static int au1000_setup_forced(struct net_device *dev, int speed, int fd)
+static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct au1000_private *aup = (struct au1000_private *)dev->priv;
- u16 ctl;
-
- ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
-
- /* First reset the PHY */
- mdio_write(dev, aup->phy_addr, MII_BMCR, ctl | BMCR_RESET);
-
- /* Select speed & duplex */
- switch (speed) {
- case SPEED_10:
- break;
- case SPEED_100:
- ctl |= BMCR_SPEED100;
- break;
- case SPEED_1000:
- default:
- return -EINVAL;
- }
- if (fd == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
- mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
- return 0;
-}
-
-
-static void
-au1000_start_link(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct au1000_private *aup = (struct au1000_private *)dev->priv;
- u32 advertise;
- int autoneg;
- int forced_speed;
- int forced_duplex;
-
- /* Default advertise */
- advertise = GENMII_DEFAULT_ADVERTISE;
- autoneg = aup->want_autoneg;
- forced_speed = SPEED_100;
- forced_duplex = DUPLEX_FULL;
-
- /* Setup link parameters */
- if (cmd) {
- if (cmd->autoneg == AUTONEG_ENABLE) {
- advertise = cmd->advertising;
- autoneg = 1;
- } else {
- autoneg = 0;
-
- forced_speed = cmd->speed;
- forced_duplex = cmd->duplex;
- }
- }
+ if (aup->phy_dev)
+ return phy_ethtool_gset(aup->phy_dev, cmd);
- /* Configure PHY & start aneg */
- aup->want_autoneg = autoneg;
- if (autoneg)
- au1000_setup_aneg(dev, advertise);
- else
- au1000_setup_forced(dev, forced_speed, forced_duplex);
- mod_timer(&aup->timer, jiffies + HZ);
+ return -EINVAL;
}
-static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct au1000_private *aup = (struct au1000_private *)dev->priv;
- u16 link, speed;
-
- cmd->supported = GENMII_DEFAULT_FEATURES;
- cmd->advertising = GENMII_DEFAULT_ADVERTISE;
- cmd->port = PORT_MII;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->phy_address = aup->phy_addr;
- spin_lock_irq(&aup->lock);
- cmd->autoneg = aup->want_autoneg;
- aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
- if ((speed == IF_PORT_100BASETX) || (speed == IF_PORT_100BASEFX))
- cmd->speed = SPEED_100;
- else if (speed == IF_PORT_10BASET)
- cmd->speed = SPEED_10;
- if (link && (dev->if_port == IF_PORT_100BASEFX))
- cmd->duplex = DUPLEX_FULL;
- else
- cmd->duplex = DUPLEX_HALF;
- spin_unlock_irq(&aup->lock);
- return 0;
-}
-static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct au1000_private *aup = (struct au1000_private *)dev->priv;
- unsigned long features = GENMII_DEFAULT_FEATURES;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
- return -EINVAL;
- if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
- return -EINVAL;
- if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
- return -EINVAL;
- if (cmd->autoneg == AUTONEG_DISABLE)
- switch (cmd->speed) {
- case SPEED_10:
- if (cmd->duplex == DUPLEX_HALF &&
- (features & SUPPORTED_10baseT_Half) == 0)
- return -EINVAL;
- if (cmd->duplex == DUPLEX_FULL &&
- (features & SUPPORTED_10baseT_Full) == 0)
- return -EINVAL;
- break;
- case SPEED_100:
- if (cmd->duplex == DUPLEX_HALF &&
- (features & SUPPORTED_100baseT_Half) == 0)
- return -EINVAL;
- if (cmd->duplex == DUPLEX_FULL &&
- (features & SUPPORTED_100baseT_Full) == 0)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- else if ((features & SUPPORTED_Autoneg) == 0)
- return -EINVAL;
-
- spin_lock_irq(&aup->lock);
- au1000_start_link(dev, cmd);
- spin_unlock_irq(&aup->lock);
- return 0;
-}
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
-static int au1000_nway_reset(struct net_device *dev)
-{
- struct au1000_private *aup = (struct au1000_private *)dev->priv;
+ if (aup->phy_dev)
+ return phy_ethtool_sset(aup->phy_dev, cmd);
- if (!aup->want_autoneg)
- return -EINVAL;
- spin_lock_irq(&aup->lock);
- au1000_start_link(dev, NULL);
- spin_unlock_irq(&aup->lock);
- return 0;
+ return -EINVAL;
}
static void
@@ -1422,21 +609,14 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
info->regdump_len = 0;
}
-static u32 au1000_get_link(struct net_device *dev)
-{
- return netif_carrier_ok(dev);
-}
-
static struct ethtool_ops au1000_ethtool_ops = {
.get_settings = au1000_get_settings,
.set_settings = au1000_set_settings,
.get_drvinfo = au1000_get_drvinfo,
- .nway_reset = au1000_nway_reset,
- .get_link = au1000_get_link
+ .get_link = ethtool_op_get_link,
};
-static struct net_device *
-au1000_probe(u32 ioaddr, int irq, int port_num)
+static struct net_device * au1000_probe(int port_num)
{
static unsigned version_printed = 0;
struct au1000_private *aup = NULL;
@@ -1444,106 +624,115 @@ au1000_probe(u32 ioaddr, int irq, int port_num)
db_dest_t *pDB, *pDBfree;
char *pmac, *argptr;
char ethaddr[6];
- int i, err;
+ int irq, i, err;
+ u32 base, macen;
+
+ if (port_num >= NUM_ETH_INTERFACES)
+ return NULL;
- if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
+ base = CPHYSADDR(iflist[port_num].base_addr );
+ macen = CPHYSADDR(iflist[port_num].macen_addr);
+ irq = iflist[port_num].irq;
+
+ if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
+ !request_mem_region(macen, 4, "Au1x00 ENET"))
return NULL;
- if (version_printed++ == 0)
+ if (version_printed++ == 0)
printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
dev = alloc_etherdev(sizeof(struct au1000_private));
if (!dev) {
- printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
return NULL;
}
- if ((err = register_netdev(dev))) {
- printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
- err);
+ if ((err = register_netdev(dev)) != 0) {
+ printk(KERN_ERR "%s: Cannot register net device, error %d\n",
+ DRV_NAME, err);
free_netdev(dev);
return NULL;
}
- printk("%s: Au1x Ethernet found at 0x%x, irq %d\n",
- dev->name, ioaddr, irq);
+ printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
+ dev->name, base, irq);
aup = dev->priv;
/* Allocate the data buffers */
/* Snooping works fine with eth on all au1xxx */
- aup->vaddr = (u32)dma_alloc_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- &aup->dma_addr,
- 0);
+ aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
+ (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ &aup->dma_addr, 0);
if (!aup->vaddr) {
free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+ release_mem_region( base, MAC_IOSIZE);
+ release_mem_region(macen, 4);
return NULL;
}
/* aup->mac is the base address of the MAC's registers */
- aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
+ aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
+
/* Setup some variables for quick register address access */
- if (ioaddr == iflist[0].base_addr)
- {
- /* check env variables first */
- if (!get_ethernet_addr(ethaddr)) {
+ aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
+ aup->mac_id = port_num;
+ au_macs[port_num] = aup;
+
+ if (port_num == 0) {
+ /* Check the environment variables first */
+ if (get_ethernet_addr(ethaddr) == 0)
memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
- } else {
+ else {
/* Check command line */
argptr = prom_getcmdline();
- if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
- printk(KERN_INFO "%s: No mac address found\n",
- dev->name);
- /* use the hard coded mac addresses */
- } else {
+ if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
+ printk(KERN_INFO "%s: No MAC address found\n",
+ dev->name);
+ /* Use the hard coded MAC addresses */
+ else {
str2eaddr(ethaddr, pmac + strlen("ethaddr="));
memcpy(au1000_mac_addr, ethaddr,
- sizeof(au1000_mac_addr));
+ sizeof(au1000_mac_addr));
}
}
- aup->enable = (volatile u32 *)
- ((unsigned long)iflist[0].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
- aup->mac_id = 0;
- au_macs[0] = aup;
- }
- else
- if (ioaddr == iflist[1].base_addr)
- {
- aup->enable = (volatile u32 *)
- ((unsigned long)iflist[1].macen_addr);
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
- dev->dev_addr[4] += 0x10;
+ } else if (port_num == 1)
setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
- aup->mac_id = 1;
- au_macs[1] = aup;
- }
- else
- {
- printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
- }
- /* bring the device out of reset, otherwise probing the mii
- * will hang */
- *aup->enable = MAC_EN_CLOCK_ENABLE;
- au_sync_delay(2);
- *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
- MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
- au_sync_delay(2);
-
- aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
- if (!aup->mii) {
- printk(KERN_ERR "%s: out of memory\n", dev->name);
- goto err_out;
- }
- aup->mii->next = NULL;
- aup->mii->chip_info = NULL;
- aup->mii->status = 0;
- aup->mii->mii_control_reg = 0;
- aup->mii->mii_data_reg = 0;
+ /*
+ * Assign to the Ethernet ports two consecutive MAC addresses
+ * to match those that are printed on their stickers
+ */
+ memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
+ dev->dev_addr[5] += port_num;
+
+ *aup->enable = 0;
+ aup->mac_enabled = 0;
+
+ aup->mii_bus.priv = dev;
+ aup->mii_bus.read = mdiobus_read;
+ aup->mii_bus.write = mdiobus_write;
+ aup->mii_bus.reset = mdiobus_reset;
+ aup->mii_bus.name = "au1000_eth_mii";
+ aup->mii_bus.id = aup->mac_id;
+ aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ for(i = 0; i < PHY_MAX_ADDR; ++i)
+ aup->mii_bus.irq[i] = PHY_POLL;
+
+ /* if known, set corresponding PHY IRQs */
+#if defined(AU1XXX_PHY_STATIC_CONFIG)
+# if defined(AU1XXX_PHY0_IRQ)
+ if (AU1XXX_PHY0_BUSID == aup->mii_bus.id)
+ aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
+# endif
+# if defined(AU1XXX_PHY1_IRQ)
+ if (AU1XXX_PHY1_BUSID == aup->mii_bus.id)
+ aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
+# endif
+#endif
+ mdiobus_register(&aup->mii_bus);
if (mii_probe(dev) != 0) {
goto err_out;
@@ -1580,7 +769,7 @@ au1000_probe(u32 ioaddr, int irq, int port_num)
}
spin_lock_init(&aup->lock);
- dev->base_addr = ioaddr;
+ dev->base_addr = base;
dev->irq = irq;
dev->open = au1000_open;
dev->hard_start_xmit = au1000_tx;
@@ -1589,7 +778,6 @@ au1000_probe(u32 ioaddr, int irq, int port_num)
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &au1000_ioctl;
SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
- dev->set_config = &au1000_set_config;
dev->tx_timeout = au1000_tx_timeout;
dev->watchdog_timeo = ETH_TX_TIMEOUT;
@@ -1605,7 +793,7 @@ err_out:
/* here we should have a valid dev plus aup-> register addresses
* so we can reset the mac properly.*/
reset_mac(dev);
- kfree(aup->mii);
+
for (i = 0; i < NUM_RX_DMA; i++) {
if (aup->rx_db_inuse[i])
ReleaseDB(aup, aup->rx_db_inuse[i]);
@@ -1614,13 +802,12 @@ err_out:
if (aup->tx_db_inuse[i])
ReleaseDB(aup, aup->tx_db_inuse[i]);
}
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
+ dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ (void *)aup->vaddr, aup->dma_addr);
unregister_netdev(dev);
free_netdev(dev);
- release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
+ release_mem_region( base, MAC_IOSIZE);
+ release_mem_region(macen, 4);
return NULL;
}
@@ -1639,19 +826,14 @@ static int au1000_init(struct net_device *dev)
u32 flags;
int i;
u32 control;
- u16 link, speed;
if (au1000_debug > 4)
printk("%s: au1000_init\n", dev->name);
- spin_lock_irqsave(&aup->lock, flags);
-
/* bring the device out of reset */
- *aup->enable = MAC_EN_CLOCK_ENABLE;
- au_sync_delay(2);
- *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 |
- MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
- au_sync_delay(20);
+ enable_mac(dev, 1);
+
+ spin_lock_irqsave(&aup->lock, flags);
aup->mac->control = 0;
aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
@@ -1667,12 +849,16 @@ static int au1000_init(struct net_device *dev)
}
au_sync();
- aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
- control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
+ control = MAC_RX_ENABLE | MAC_TX_ENABLE;
#ifndef CONFIG_CPU_LITTLE_ENDIAN
control |= MAC_BIG_ENDIAN;
#endif
- if (link && (dev->if_port == IF_PORT_100BASEFX)) {
+ if (aup->phy_dev) {
+ if (aup->phy_dev->link && (DUPLEX_FULL == aup->phy_dev->duplex))
+ control |= MAC_FULL_DUPLEX;
+ else
+ control |= MAC_DISABLE_RX_OWN;
+ } else { /* PHY-less op, assume full-duplex */
control |= MAC_FULL_DUPLEX;
}
@@ -1684,57 +870,84 @@ static int au1000_init(struct net_device *dev)
return 0;
}
-static void au1000_timer(unsigned long data)
+static void
+au1000_adjust_link(struct net_device *dev)
{
- struct net_device *dev = (struct net_device *)data;
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- unsigned char if_port;
- u16 link, speed;
+ struct phy_device *phydev = aup->phy_dev;
+ unsigned long flags;
- if (!dev) {
- /* fatal error, don't restart the timer */
- printk(KERN_ERR "au1000_timer error: NULL dev\n");
- return;
- }
+ int status_change = 0;
- if_port = dev->if_port;
- if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) {
- if (link) {
- if (!netif_carrier_ok(dev)) {
- netif_carrier_on(dev);
- printk(KERN_INFO "%s: link up\n", dev->name);
- }
- }
- else {
- if (netif_carrier_ok(dev)) {
- netif_carrier_off(dev);
- dev->if_port = 0;
- printk(KERN_INFO "%s: link down\n", dev->name);
- }
+ BUG_ON(!aup->phy_dev);
+
+ spin_lock_irqsave(&aup->lock, flags);
+
+ if (phydev->link && (aup->old_speed != phydev->speed)) {
+ // speed changed
+
+ switch(phydev->speed) {
+ case SPEED_10:
+ case SPEED_100:
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Speed (%d) is not 10/100 ???\n",
+ dev->name, phydev->speed);
+ break;
}
+
+ aup->old_speed = phydev->speed;
+
+ status_change = 1;
}
- if (link && (dev->if_port != if_port) &&
- (dev->if_port != IF_PORT_UNKNOWN)) {
+ if (phydev->link && (aup->old_duplex != phydev->duplex)) {
+ // duplex mode changed
+
+ /* switching duplex mode requires to disable rx and tx! */
hard_stop(dev);
- if (dev->if_port == IF_PORT_100BASEFX) {
- printk(KERN_INFO "%s: going to full duplex\n",
- dev->name);
- aup->mac->control |= MAC_FULL_DUPLEX;
- au_sync_delay(1);
- }
- else {
- aup->mac->control &= ~MAC_FULL_DUPLEX;
- au_sync_delay(1);
- }
+
+ if (DUPLEX_FULL == phydev->duplex)
+ aup->mac->control = ((aup->mac->control
+ | MAC_FULL_DUPLEX)
+ & ~MAC_DISABLE_RX_OWN);
+ else
+ aup->mac->control = ((aup->mac->control
+ & ~MAC_FULL_DUPLEX)
+ | MAC_DISABLE_RX_OWN);
+ au_sync_delay(1);
+
enable_rx_tx(dev);
+ aup->old_duplex = phydev->duplex;
+
+ status_change = 1;
}
- aup->timer.expires = RUN_AT((1*HZ));
- aup->timer.data = (unsigned long)dev;
- aup->timer.function = &au1000_timer; /* timer handler */
- add_timer(&aup->timer);
+ if(phydev->link != aup->old_link) {
+ // link state changed
+
+ if (phydev->link) // link went up
+ netif_schedule(dev);
+ else { // link went down
+ aup->old_speed = 0;
+ aup->old_duplex = -1;
+ }
+
+ aup->old_link = phydev->link;
+ status_change = 1;
+ }
+ spin_unlock_irqrestore(&aup->lock, flags);
+
+ if (status_change) {
+ if (phydev->link)
+ printk(KERN_INFO "%s: link up (%d/%s)\n",
+ dev->name, phydev->speed,
+ DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+ else
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ }
}
static int au1000_open(struct net_device *dev)
@@ -1745,25 +958,26 @@ static int au1000_open(struct net_device *dev)
if (au1000_debug > 4)
printk("%s: open: dev=%p\n", dev->name, dev);
+ if ((retval = request_irq(dev->irq, &au1000_interrupt, 0,
+ dev->name, dev))) {
+ printk(KERN_ERR "%s: unable to get IRQ %d\n",
+ dev->name, dev->irq);
+ return retval;
+ }
+
if ((retval = au1000_init(dev))) {
printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
free_irq(dev->irq, dev);
return retval;
}
- netif_start_queue(dev);
- if ((retval = request_irq(dev->irq, &au1000_interrupt, 0,
- dev->name, dev))) {
- printk(KERN_ERR "%s: unable to get IRQ %d\n",
- dev->name, dev->irq);
- return retval;
+ if (aup->phy_dev) {
+ /* cause the PHY state machine to schedule a link state check */
+ aup->phy_dev->state = PHY_CHANGELINK;
+ phy_start(aup->phy_dev);
}
- init_timer(&aup->timer); /* used in ioctl() */
- aup->timer.expires = RUN_AT((3*HZ));
- aup->timer.data = (unsigned long)dev;
- aup->timer.function = &au1000_timer; /* timer handler */
- add_timer(&aup->timer);
+ netif_start_queue(dev);
if (au1000_debug > 4)
printk("%s: open: Initialization done.\n", dev->name);
@@ -1773,16 +987,19 @@ static int au1000_open(struct net_device *dev)
static int au1000_close(struct net_device *dev)
{
- u32 flags;
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
+ unsigned long flags;
+ struct au1000_private *const aup = (struct au1000_private *) dev->priv;
if (au1000_debug > 4)
printk("%s: close: dev=%p\n", dev->name, dev);
- reset_mac(dev);
+ if (aup->phy_dev)
+ phy_stop(aup->phy_dev);
spin_lock_irqsave(&aup->lock, flags);
-
+
+ reset_mac_unlocked (dev);
+
/* stop the device */
netif_stop_queue(dev);
@@ -1804,21 +1021,18 @@ static void __exit au1000_cleanup_module(void)
if (dev) {
aup = (struct au1000_private *) dev->priv;
unregister_netdev(dev);
- kfree(aup->mii);
- for (j = 0; j < NUM_RX_DMA; j++) {
+ for (j = 0; j < NUM_RX_DMA; j++)
if (aup->rx_db_inuse[j])
ReleaseDB(aup, aup->rx_db_inuse[j]);
- }
- for (j = 0; j < NUM_TX_DMA; j++) {
+ for (j = 0; j < NUM_TX_DMA; j++)
if (aup->tx_db_inuse[j])
ReleaseDB(aup, aup->tx_db_inuse[j]);
- }
- dma_free_noncoherent(NULL,
- MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
- (void *)aup->vaddr,
- aup->dma_addr);
+ dma_free_noncoherent(NULL, MAX_BUF_SIZE *
+ (NUM_TX_BUFFS + NUM_RX_BUFFS),
+ (void *)aup->vaddr, aup->dma_addr);
+ release_mem_region(dev->base_addr, MAC_IOSIZE);
+ release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
free_netdev(dev);
- release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
}
}
}
@@ -1829,7 +1043,7 @@ static void update_tx_stats(struct net_device *dev, u32 status)
struct net_device_stats *ps = &aup->stats;
if (status & TX_FRAME_ABORTED) {
- if (dev->if_port == IF_PORT_100BASEFX) {
+ if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
/* any other tx errors are only valid
* in half duplex mode */
@@ -2070,23 +1284,6 @@ static void au1000_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ?
- ethernet_polynomial : 0);
- }
- return crc;
-}
-
static void set_rx_mode(struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
@@ -2120,126 +1317,15 @@ static void set_rx_mode(struct net_device *dev)
}
}
-
static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct au1000_private *aup = (struct au1000_private *)dev->priv;
- u16 *data = (u16 *)&rq->ifr_ifru;
-
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- case SIOCGMIIPHY:
- if (!netif_running(dev)) return -EINVAL;
- data[0] = aup->phy_addr;
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- case SIOCGMIIREG:
- data[3] = mdio_read(dev, data[0], data[1]);
- return 0;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- mdio_write(dev, data[0], data[1],data[2]);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-
-}
-
-
-static int au1000_set_config(struct net_device *dev, struct ifmap *map)
-{
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
- u16 control;
- if (au1000_debug > 4) {
- printk("%s: set_config called: dev->if_port %d map->port %x\n",
- dev->name, dev->if_port, map->port);
- }
+ if (!netif_running(dev)) return -EINVAL;
- switch(map->port){
- case IF_PORT_UNKNOWN: /* use auto here */
- printk(KERN_INFO "%s: config phy for aneg\n",
- dev->name);
- dev->if_port = map->port;
- /* Link Down: the timer will bring it up */
- netif_carrier_off(dev);
-
- /* read current control */
- control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
- control &= ~(MII_CNTL_FDX | MII_CNTL_F100);
-
- /* enable auto negotiation and reset the negotiation */
- mdio_write(dev, aup->phy_addr, MII_CONTROL,
- control | MII_CNTL_AUTO |
- MII_CNTL_RST_AUTO);
+ if (!aup->phy_dev) return -EINVAL; // PHY not controllable
- break;
-
- case IF_PORT_10BASET: /* 10BaseT */
- printk(KERN_INFO "%s: config phy for 10BaseT\n",
- dev->name);
- dev->if_port = map->port;
-
- /* Link Down: the timer will bring it up */
- netif_carrier_off(dev);
-
- /* set Speed to 10Mbps, Half Duplex */
- control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
- control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO |
- MII_CNTL_FDX);
-
- /* disable auto negotiation and force 10M/HD mode*/
- mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
- break;
-
- case IF_PORT_100BASET: /* 100BaseT */
- case IF_PORT_100BASETX: /* 100BaseTx */
- printk(KERN_INFO "%s: config phy for 100BaseTX\n",
- dev->name);
- dev->if_port = map->port;
-
- /* Link Down: the timer will bring it up */
- netif_carrier_off(dev);
-
- /* set Speed to 100Mbps, Half Duplex */
- /* disable auto negotiation and enable 100MBit Mode */
- control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
- control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX);
- control |= MII_CNTL_F100;
- mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
- break;
-
- case IF_PORT_100BASEFX: /* 100BaseFx */
- printk(KERN_INFO "%s: config phy for 100BaseFX\n",
- dev->name);
- dev->if_port = map->port;
-
- /* Link Down: the timer will bring it up */
- netif_carrier_off(dev);
-
- /* set Speed to 100Mbps, Full Duplex */
- /* disable auto negotiation and enable 100MBit Mode */
- control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
- control &= ~MII_CNTL_AUTO;
- control |= MII_CNTL_F100 | MII_CNTL_FDX;
- mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
- break;
- case IF_PORT_10BASE2: /* 10Base2 */
- case IF_PORT_AUI: /* AUI */
- /* These Modes are not supported (are they?)*/
- printk(KERN_ERR "%s: 10Base2/AUI not supported",
- dev->name);
- return -EOPNOTSUPP;
- break;
-
- default:
- printk(KERN_ERR "%s: Invalid media selected",
- dev->name);
- return -EINVAL;
- }
- return 0;
+ return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
}
static struct net_device_stats *au1000_get_stats(struct net_device *dev)
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 7f9326e39cc0..41c2f848d2c4 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -40,120 +40,6 @@
#define MULTICAST_FILTER_LIMIT 64
-/* FIXME
- * The PHY defines should be in a separate file.
- */
-
-/* MII register offsets */
-#define MII_CONTROL 0x0000
-#define MII_STATUS 0x0001
-#define MII_PHY_ID0 0x0002
-#define MII_PHY_ID1 0x0003
-#define MII_ANADV 0x0004
-#define MII_ANLPAR 0x0005
-#define MII_AEXP 0x0006
-#define MII_ANEXT 0x0007
-#define MII_LSI_PHY_CONFIG 0x0011
-/* Status register */
-#define MII_LSI_PHY_STAT 0x0012
-#define MII_AMD_PHY_STAT MII_LSI_PHY_STAT
-#define MII_INTEL_PHY_STAT 0x0011
-
-#define MII_AUX_CNTRL 0x0018
-/* mii registers specific to AMD 79C901 */
-#define MII_STATUS_SUMMARY = 0x0018
-
-/* MII Control register bit definitions. */
-#define MII_CNTL_FDX 0x0100
-#define MII_CNTL_RST_AUTO 0x0200
-#define MII_CNTL_ISOLATE 0x0400
-#define MII_CNTL_PWRDWN 0x0800
-#define MII_CNTL_AUTO 0x1000
-#define MII_CNTL_F100 0x2000
-#define MII_CNTL_LPBK 0x4000
-#define MII_CNTL_RESET 0x8000
-
-/* MII Status register bit */
-#define MII_STAT_EXT 0x0001
-#define MII_STAT_JAB 0x0002
-#define MII_STAT_LINK 0x0004
-#define MII_STAT_CAN_AUTO 0x0008
-#define MII_STAT_FAULT 0x0010
-#define MII_STAT_AUTO_DONE 0x0020
-#define MII_STAT_CAN_T 0x0800
-#define MII_STAT_CAN_T_FDX 0x1000
-#define MII_STAT_CAN_TX 0x2000
-#define MII_STAT_CAN_TX_FDX 0x4000
-#define MII_STAT_CAN_T4 0x8000
-
-
-#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */
-#define MII_ID1_MODEL 0x03F0 /* model number */
-#define MII_ID1_REV 0x000F /* model number */
-
-/* MII NWAY Register Bits ...
- valid for the ANAR (Auto-Negotiation Advertisement) and
- ANLPAR (Auto-Negotiation Link Partner) registers */
-#define MII_NWAY_NODE_SEL 0x001f
-#define MII_NWAY_CSMA_CD 0x0001
-#define MII_NWAY_T 0x0020
-#define MII_NWAY_T_FDX 0x0040
-#define MII_NWAY_TX 0x0080
-#define MII_NWAY_TX_FDX 0x0100
-#define MII_NWAY_T4 0x0200
-#define MII_NWAY_PAUSE 0x0400
-#define MII_NWAY_RF 0x2000 /* Remote Fault */
-#define MII_NWAY_ACK 0x4000 /* Remote Acknowledge */
-#define MII_NWAY_NP 0x8000 /* Next Page (Enable) */
-
-/* mii stsout register bits */
-#define MII_STSOUT_LINK_FAIL 0x4000
-#define MII_STSOUT_SPD 0x0080
-#define MII_STSOUT_DPLX 0x0040
-
-/* mii stsics register bits */
-#define MII_STSICS_SPD 0x8000
-#define MII_STSICS_DPLX 0x4000
-#define MII_STSICS_LINKSTS 0x0001
-
-/* mii stssum register bits */
-#define MII_STSSUM_LINK 0x0008
-#define MII_STSSUM_DPLX 0x0004
-#define MII_STSSUM_AUTO 0x0002
-#define MII_STSSUM_SPD 0x0001
-
-/* lsi phy status register */
-#define MII_LSI_PHY_STAT_FDX 0x0040
-#define MII_LSI_PHY_STAT_SPD 0x0080
-
-/* amd phy status register */
-#define MII_AMD_PHY_STAT_FDX 0x0800
-#define MII_AMD_PHY_STAT_SPD 0x0400
-
-/* intel phy status register */
-#define MII_INTEL_PHY_STAT_FDX 0x0200
-#define MII_INTEL_PHY_STAT_SPD 0x4000
-
-/* Auxilliary Control/Status Register */
-#define MII_AUX_FDX 0x0001
-#define MII_AUX_100 0x0002
-#define MII_AUX_F100 0x0004
-#define MII_AUX_ANEG 0x0008
-
-typedef struct mii_phy {
- struct mii_phy * next;
- struct mii_chip_info * chip_info;
- u16 status;
- u32 *mii_control_reg;
- u32 *mii_data_reg;
-} mii_phy_t;
-
-struct phy_ops {
- int (*phy_init) (struct net_device *, int);
- int (*phy_reset) (struct net_device *, int);
- int (*phy_status) (struct net_device *, int, u16 *, u16 *);
-};
-
/*
* Data Buffer Descriptor. Data buffers must be aligned on 32 byte
* boundary for both, receive and transmit.
@@ -200,7 +86,6 @@ typedef struct mac_reg {
struct au1000_private {
-
db_dest_t *pDBfree;
db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
@@ -213,8 +98,15 @@ struct au1000_private {
u32 tx_full;
int mac_id;
- mii_phy_t *mii;
- struct phy_ops *phy_ops;
+
+ int mac_enabled; /* whether MAC is currently enabled and running (req. for mdio) */
+
+ int old_link; /* used by au1000_adjust_link */
+ int old_speed;
+ int old_duplex;
+
+ struct phy_device *phy_dev;
+ struct mii_bus mii_bus;
/* These variables are just for quick access to certain regs addresses. */
volatile mac_reg_t *mac; /* mac registers */
@@ -223,14 +115,6 @@ struct au1000_private {
u32 vaddr; /* virtual address of rx/tx buffers */
dma_addr_t dma_addr; /* dma address of rx/tx buffers */
- u8 *hash_table;
- u32 hash_mode;
- u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
- int phy_addr; /* phy address */
- u32 options; /* User-settable misc. driver options. */
- u32 drv_flags;
- int want_autoneg;
struct net_device_stats stats;
- struct timer_list timer;
spinlock_t lock; /* Serialise access to device */
};
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 3d306681919e..d8233e0b7899 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -650,9 +650,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
- if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ if (dma_mapping_error(mapping) ||
+ mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
/* Sigh... */
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ if (!dma_mapping_error(mapping))
+ pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA);
if (skb == NULL)
@@ -660,8 +662,10 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
mapping = pci_map_single(bp->pdev, skb->data,
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
- if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(mapping) ||
+ mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ if (!dma_mapping_error(mapping))
+ pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -967,9 +971,10 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if (mapping + len > B44_DMA_MASK) {
+ if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
+ if (!dma_mapping_error(mapping))
+ pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
GFP_ATOMIC|GFP_DMA);
@@ -978,8 +983,9 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(bp->pdev, bounce_skb->data,
len, PCI_DMA_TODEVICE);
- if (mapping + len > B44_DMA_MASK) {
- pci_unmap_single(bp->pdev, mapping,
+ if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
+ if (!dma_mapping_error(mapping))
+ pci_unmap_single(bp->pdev, mapping,
len, PCI_DMA_TODEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
@@ -1203,7 +1209,8 @@ static int b44_alloc_consistent(struct b44 *bp)
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
- if (rx_ring_dma + size > B44_DMA_MASK) {
+ if (dma_mapping_error(rx_ring_dma) ||
+ rx_ring_dma + size > B44_DMA_MASK) {
kfree(rx_ring);
goto out_err;
}
@@ -1229,7 +1236,8 @@ static int b44_alloc_consistent(struct b44 *bp)
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
- if (tx_ring_dma + size > B44_DMA_MASK) {
+ if (dma_mapping_error(tx_ring_dma) ||
+ tx_ring_dma + size > B44_DMA_MASK) {
kfree(tx_ring);
goto out_err;
}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 5ca99e26660a..702d546567ad 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -32,6 +32,7 @@
#include <asm/irq.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
+#include <asm/page.h>
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
@@ -49,14 +50,15 @@
#include <linux/crc32.h>
#include <linux/prefetch.h>
#include <linux/cache.h>
+#include <linux/zlib.h>
#include "bnx2.h"
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.4.39"
-#define DRV_MODULE_RELDATE "March 22, 2006"
+#define DRV_MODULE_VERSION "1.4.42"
+#define DRV_MODULE_RELDATE "June 12, 2006"
#define RUN_AT(x) (jiffies + (x))
@@ -1820,7 +1822,7 @@ reuse_rx:
skb->protocol = eth_type_trans(skb, bp->dev);
if ((len > (bp->dev->mtu + ETH_HLEN)) &&
- (htons(skb->protocol) != 0x8100)) {
+ (ntohs(skb->protocol) != 0x8100)) {
dev_kfree_skb_irq(skb);
goto next_rx;
@@ -2009,7 +2011,7 @@ bnx2_poll(struct net_device *dev, int *budget)
return 1;
}
-/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
+/* Called with rtnl_lock from vlan functions and also netif_tx_lock
* from set_multicast.
*/
static void
@@ -2083,6 +2085,92 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(&bp->phy_lock);
}
+#define FW_BUF_SIZE 0x8000
+
+static int
+bnx2_gunzip_init(struct bnx2 *bp)
+{
+ if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
+ goto gunzip_nomem1;
+
+ if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
+ goto gunzip_nomem2;
+
+ bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+ if (bp->strm->workspace == NULL)
+ goto gunzip_nomem3;
+
+ return 0;
+
+gunzip_nomem3:
+ kfree(bp->strm);
+ bp->strm = NULL;
+
+gunzip_nomem2:
+ vfree(bp->gunzip_buf);
+ bp->gunzip_buf = NULL;
+
+gunzip_nomem1:
+ printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
+ "uncompression.\n", bp->dev->name);
+ return -ENOMEM;
+}
+
+static void
+bnx2_gunzip_end(struct bnx2 *bp)
+{
+ kfree(bp->strm->workspace);
+
+ kfree(bp->strm);
+ bp->strm = NULL;
+
+ if (bp->gunzip_buf) {
+ vfree(bp->gunzip_buf);
+ bp->gunzip_buf = NULL;
+ }
+}
+
+static int
+bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
+{
+ int n, rc;
+
+ /* check gzip header */
+ if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
+ return -EINVAL;
+
+ n = 10;
+
+#define FNAME 0x8
+ if (zbuf[3] & FNAME)
+ while ((zbuf[n++] != 0) && (n < len));
+
+ bp->strm->next_in = zbuf + n;
+ bp->strm->avail_in = len - n;
+ bp->strm->next_out = bp->gunzip_buf;
+ bp->strm->avail_out = FW_BUF_SIZE;
+
+ rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
+ if (rc != Z_OK)
+ return rc;
+
+ rc = zlib_inflate(bp->strm, Z_FINISH);
+
+ *outlen = FW_BUF_SIZE - bp->strm->avail_out;
+ *outbuf = bp->gunzip_buf;
+
+ if ((rc != Z_OK) && (rc != Z_STREAM_END))
+ printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
+ bp->dev->name, bp->strm->msg);
+
+ zlib_inflateEnd(bp->strm);
+
+ if (rc == Z_STREAM_END)
+ return 0;
+
+ return rc;
+}
+
static void
load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
u32 rv2p_proc)
@@ -2092,9 +2180,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
for (i = 0; i < rv2p_code_len; i += 8) {
- REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code);
+ REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
rv2p_code++;
- REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code);
+ REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
rv2p_code++;
if (rv2p_proc == RV2P_PROC1) {
@@ -2134,7 +2222,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
int j;
for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
- REG_WR_IND(bp, offset, fw->text[j]);
+ REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
}
}
@@ -2190,15 +2278,32 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
REG_WR_IND(bp, cpu_reg->mode, val);
}
-static void
+static int
bnx2_init_cpus(struct bnx2 *bp)
{
struct cpu_reg cpu_reg;
struct fw_info fw;
+ int rc = 0;
+ void *text;
+ u32 text_len;
+
+ if ((rc = bnx2_gunzip_init(bp)) != 0)
+ return rc;
/* Initialize the RV2P processor. */
- load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1);
- load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2);
+ rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
+ &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+
+ rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
+ &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
/* Initialize the RX Processor. */
cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -2222,7 +2327,13 @@ bnx2_init_cpus(struct bnx2 *bp)
fw.text_addr = bnx2_RXP_b06FwTextAddr;
fw.text_len = bnx2_RXP_b06FwTextLen;
fw.text_index = 0;
- fw.text = bnx2_RXP_b06FwText;
+
+ rc = bnx2_gunzip(bp, bnx2_RXP_b06FwText, sizeof(bnx2_RXP_b06FwText),
+ &text, &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ fw.text = text;
fw.data_addr = bnx2_RXP_b06FwDataAddr;
fw.data_len = bnx2_RXP_b06FwDataLen;
@@ -2268,7 +2379,13 @@ bnx2_init_cpus(struct bnx2 *bp)
fw.text_addr = bnx2_TXP_b06FwTextAddr;
fw.text_len = bnx2_TXP_b06FwTextLen;
fw.text_index = 0;
- fw.text = bnx2_TXP_b06FwText;
+
+ rc = bnx2_gunzip(bp, bnx2_TXP_b06FwText, sizeof(bnx2_TXP_b06FwText),
+ &text, &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ fw.text = text;
fw.data_addr = bnx2_TXP_b06FwDataAddr;
fw.data_len = bnx2_TXP_b06FwDataLen;
@@ -2314,7 +2431,13 @@ bnx2_init_cpus(struct bnx2 *bp)
fw.text_addr = bnx2_TPAT_b06FwTextAddr;
fw.text_len = bnx2_TPAT_b06FwTextLen;
fw.text_index = 0;
- fw.text = bnx2_TPAT_b06FwText;
+
+ rc = bnx2_gunzip(bp, bnx2_TPAT_b06FwText, sizeof(bnx2_TPAT_b06FwText),
+ &text, &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ fw.text = text;
fw.data_addr = bnx2_TPAT_b06FwDataAddr;
fw.data_len = bnx2_TPAT_b06FwDataLen;
@@ -2360,7 +2483,13 @@ bnx2_init_cpus(struct bnx2 *bp)
fw.text_addr = bnx2_COM_b06FwTextAddr;
fw.text_len = bnx2_COM_b06FwTextLen;
fw.text_index = 0;
- fw.text = bnx2_COM_b06FwText;
+
+ rc = bnx2_gunzip(bp, bnx2_COM_b06FwText, sizeof(bnx2_COM_b06FwText),
+ &text, &text_len);
+ if (rc)
+ goto init_cpu_err;
+
+ fw.text = text;
fw.data_addr = bnx2_COM_b06FwDataAddr;
fw.data_len = bnx2_COM_b06FwDataLen;
@@ -2384,6 +2513,9 @@ bnx2_init_cpus(struct bnx2 *bp)
load_cpu_fw(bp, &cpu_reg, &fw);
+init_cpu_err:
+ bnx2_gunzip_end(bp);
+ return rc;
}
static int
@@ -2945,7 +3077,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
int buf_size)
{
u32 written, offset32, len32;
- u8 *buf, start[4], end[4];
+ u8 *buf, start[4], end[4], *flash_buffer = NULL;
int rc = 0;
int align_start, align_end;
@@ -2985,12 +3117,19 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
memcpy(buf + align_start, data_buf, buf_size);
}
+ if (bp->flash_info->buffered == 0) {
+ flash_buffer = kmalloc(264, GFP_KERNEL);
+ if (flash_buffer == NULL) {
+ rc = -ENOMEM;
+ goto nvram_write_end;
+ }
+ }
+
written = 0;
while ((written < len32) && (rc == 0)) {
u32 page_start, page_end, data_start, data_end;
u32 addr, cmd_flags;
int i;
- u8 flash_buffer[264];
/* Find the page_start addr */
page_start = offset32 + written;
@@ -3061,7 +3200,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
}
/* Loop to write the new data from data_start to data_end */
- for (addr = data_start; addr < data_end; addr += 4, i++) {
+ for (addr = data_start; addr < data_end; addr += 4, i += 4) {
if ((addr == page_end - 4) ||
((bp->flash_info->buffered) &&
(addr == data_end - 4))) {
@@ -3109,6 +3248,9 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
}
nvram_write_end:
+ if (bp->flash_info->buffered == 0)
+ kfree(flash_buffer);
+
if (align_start || align_end)
kfree(buf);
return rc;
@@ -3246,7 +3388,9 @@ bnx2_init_chip(struct bnx2 *bp)
* context block must have already been enabled. */
bnx2_init_context(bp);
- bnx2_init_cpus(bp);
+ if ((rc = bnx2_init_cpus(bp)) != 0)
+ return rc;
+
bnx2_init_nvram(bp);
bnx2_set_mac_addr(bp);
@@ -3546,7 +3690,9 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
if (rc)
return rc;
- bnx2_init_chip(bp);
+ if ((rc = bnx2_init_chip(bp)) != 0)
+ return rc;
+
bnx2_init_tx_ring(bp);
bnx2_init_rx_ring(bp);
return 0;
@@ -4024,6 +4170,8 @@ bnx2_timer(unsigned long data)
msg = (u32) ++bp->fw_drv_pulse_wr_seq;
REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
+ bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+
if ((bp->phy_flags & PHY_SERDES_FLAG) &&
(CHIP_NUM(bp) == CHIP_NUM_5706)) {
@@ -4242,7 +4390,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
}
#endif
-/* Called with dev->xmit_lock.
+/* Called with netif_tx_lock.
* hard_start_xmit is pseudo-lockless - a lock is only required when
* the tx queue is full. This way, we get the benefit of lockless
* operations most of the time without the complexities to handle
@@ -4300,7 +4448,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
skb->nh.iph->check = 0;
- skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+ skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
skb->h.th->check =
~csum_tcpudp_magic(skb->nh.iph->saddr,
skb->nh.iph->daddr,
@@ -4494,6 +4642,10 @@ bnx2_get_stats(struct net_device *dev)
net_stats->tx_aborted_errors +
net_stats->tx_carrier_errors;
+ net_stats->rx_missed_errors =
+ (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
+ stats_blk->stat_FwRxDrop);
+
return net_stats;
}
@@ -4976,7 +5128,7 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
-#define BNX2_NUM_STATS 45
+#define BNX2_NUM_STATS 46
static struct {
char string[ETH_GSTRING_LEN];
@@ -5026,6 +5178,7 @@ static struct {
{ "rx_mac_ctrl_frames" },
{ "rx_filtered_packets" },
{ "rx_discards" },
+ { "rx_fw_discards" },
};
#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
@@ -5076,6 +5229,7 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
STATS_OFFSET32(stat_MacControlFramesReceived),
STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
STATS_OFFSET32(stat_IfInMBUFDiscards),
+ STATS_OFFSET32(stat_FwRxDrop),
};
/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
@@ -5086,7 +5240,7 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
4,0,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,
- 4,4,4,4,4,
+ 4,4,4,4,4,4,
};
static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
@@ -5094,7 +5248,7 @@ static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,
- 4,4,4,4,4,
+ 4,4,4,4,4,4,
};
#define BNX2_NUM_TESTS 6
@@ -5624,7 +5778,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
}
}
- if (CHIP_NUM(bp) == CHIP_NUM_5708)
+ if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
+ (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
+ (CHIP_ID(bp) == CHIP_ID_5708_B1))
bp->flags |= NO_WOL_FLAG;
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index b87925f6a228..5845e334941b 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -231,6 +231,7 @@ struct statistics_block {
u32 stat_GenStat13;
u32 stat_GenStat14;
u32 stat_GenStat15;
+ u32 stat_FwRxDrop;
};
@@ -3481,6 +3482,8 @@ struct l2_fhdr {
#define BNX2_COM_SCRATCH 0x00120000
+#define BNX2_FW_RX_DROP_COUNT 0x00120084
+
/*
* cp_reg definition
@@ -3747,7 +3750,12 @@ struct l2_fhdr {
#define DMA_READ_CHANS 5
#define DMA_WRITE_CHANS 3
-#define BCM_PAGE_BITS 12
+/* Use CPU native page size up to 16K for the ring sizes. */
+#if (PAGE_SHIFT > 14)
+#define BCM_PAGE_BITS 14
+#else
+#define BCM_PAGE_BITS PAGE_SHIFT
+#endif
#define BCM_PAGE_SIZE (1 << BCM_PAGE_BITS)
#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct tx_bd))
@@ -3770,7 +3778,7 @@ struct l2_fhdr {
#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
-#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8)
+#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> (BCM_PAGE_BITS - 4))
#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
/* Context size. */
@@ -4048,6 +4056,9 @@ struct bnx2 {
u32 flash_size;
int status_stats_size;
+
+ struct z_stream_s *strm;
+ void *gunzip_buf;
};
static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index 8158974c35a8..2d753dca0d75 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -7,7 +7,7 @@
* the Free Software Foundation, except as noted below.
*
* This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004, 2005 Broadcom Corporation.
+ * source code, Copyright (c) 2004, 2005, 2006 Broadcom Corporation.
*
* Permission is hereby granted for the distribution of this firmware data
* in hexadecimal or equivalent format, provided this copyright notice is
@@ -28,943 +28,641 @@ static const u32 bnx2_COM_b06FwBssAddr = 0x08005860;
static const int bnx2_COM_b06FwBssLen = 0x88;
static const u32 bnx2_COM_b06FwSbssAddr = 0x08005840;
static const int bnx2_COM_b06FwSbssLen = 0x1c;
-static u32 bnx2_COM_b06FwText[(0x57bc/4) + 1] = {
- 0x0a00022d, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x322e352e,
- 0x38000000, 0x02050802, 0x00000000, 0x00000003, 0x00000014, 0x00000032,
- 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000010, 0x000003e8, 0x0000ea60, 0x00000001, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x0000ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000002, 0x00000020, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24425840,
- 0x3c030800, 0x246358e8, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004,
- 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261008b4, 0x3c1c0800,
- 0x279c5840, 0x0e0002f7, 0x00000000, 0x0000000d, 0x27bdffe8, 0x3c1a8000,
- 0x3c020008, 0x0342d825, 0x3c036010, 0xafbf0010, 0x8c655000, 0x3c020800,
- 0x24470f30, 0x3c040800, 0x24865860, 0x2402ff7f, 0x00a22824, 0x34a5380c,
- 0xac655000, 0x00002821, 0x24020037, 0x24030c80, 0xaf420008, 0xaf430024,
- 0xacc70000, 0x24a50001, 0x2ca20016, 0x1440fffc, 0x24c60004, 0x24845860,
- 0x3c020800, 0x24420f3c, 0x3c030800, 0x24630e2c, 0xac820004, 0x3c020800,
- 0x24420a2c, 0x3c050800, 0x24a51268, 0xac82000c, 0x3c020800, 0x244243dc,
- 0xac830008, 0x3c030800, 0x24633698, 0xac820014, 0x3c020800, 0x24423c24,
- 0xac830018, 0xac83001c, 0x3c030800, 0x24630f44, 0xac820024, 0x3c020800,
- 0x244243ac, 0xac83002c, 0x3c030800, 0x246343cc, 0xac820030, 0x3c020800,
- 0x244242f0, 0xac830034, 0x3c030800, 0x24633d78, 0xac82003c, 0x3c020800,
- 0x24420fd4, 0xac850010, 0xac850020, 0xac830040, 0x0e0010b7, 0xac820050,
- 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0, 0xafb00010, 0x27500100,
- 0xafbf0018, 0xafb10014, 0x9203000b, 0x24020003, 0x1462005b, 0x96110008,
- 0x32220001, 0x10400009, 0x27430080, 0x8e020000, 0x96040014, 0x000211c2,
- 0x00021040, 0x00621821, 0xa4640000, 0x0a0002d0, 0x3c020800, 0x3c020800,
- 0x8c430020, 0x1060002a, 0x3c030800, 0x0e00148e, 0x00000000, 0x97420108,
- 0x8f850018, 0x9743010c, 0x3042003e, 0x00021400, 0x00621825, 0xaca30000,
- 0x8f840018, 0x8f420100, 0xac820004, 0x97430116, 0x9742010e, 0x8f840018,
- 0x00031c00, 0x00431025, 0xac820008, 0x97430110, 0x97440112, 0x8f850018,
- 0x00031c00, 0x00832025, 0xaca4000c, 0x97420114, 0x8f840018, 0x3042ffff,
- 0xac820010, 0x8f830018, 0xac600014, 0x8f820018, 0x3c030800, 0xac400018,
- 0x946258ce, 0x8f840018, 0x3c032000, 0x00431025, 0xac82001c, 0x0e0014cc,
- 0x24040001, 0x3c030800, 0x8c620040, 0x24420001, 0xac620040, 0x3c020800,
- 0x8c430044, 0x32240004, 0x24630001, 0x10800017, 0xac430044, 0x8f4202b8,
- 0x04430007, 0x8e020020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001,
- 0x0a0002f2, 0xac830060, 0x3c060800, 0x8cc4005c, 0xaf420280, 0x96030016,
- 0x00001021, 0xa7430284, 0x8e050004, 0x24840001, 0x3c031000, 0xaf450288,
- 0xaf4302b8, 0x0a0002f2, 0xacc4005c, 0x32220002, 0x0a0002f2, 0x0002102b,
- 0x3c026000, 0xac400808, 0x0000000d, 0x00001021, 0x8fbf0018, 0x8fb10014,
- 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffc8, 0xafbf0034, 0xafbe0030,
- 0xafb7002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018,
- 0xafb10014, 0x0e000244, 0xafb00010, 0x3c170800, 0x3c160800, 0x24110020,
- 0x24150030, 0x2794000c, 0x27930008, 0x3c124000, 0x3c1e0800, 0x8f820004,
- 0x3c040800, 0x8c830020, 0x10430005, 0x8ee200a4, 0xaf830004, 0x0e001593,
- 0x00000000, 0x8ee200a4, 0x8ec300a0, 0x10430004, 0x26c400a0, 0x94820002,
- 0xa742009e, 0xaee300a4, 0x8f500000, 0x32020007, 0x1040ffee, 0x32020001,
- 0x1040002c, 0x32020002, 0x8f420100, 0xaf420020, 0x8f430104, 0xaf4300a8,
- 0x9342010b, 0x93630000, 0x306300ff, 0x10710005, 0x304400ff, 0x10750006,
- 0x2c820016, 0x0a000333, 0x00000000, 0xaf940000, 0x0a000334, 0x2c820016,
- 0xaf930000, 0x0a000334, 0x00000000, 0xaf800000, 0x14400005, 0x00041880,
- 0x0e0003cc, 0x00000000, 0x0a000340, 0x00000000, 0x3c020800, 0x24425860,
- 0x00621821, 0x8c620000, 0x0040f809, 0x00000000, 0x10400005, 0x3c030800,
- 0x8f420104, 0x3c016020, 0xac220014, 0x3c030800, 0x8c620034, 0xaf520138,
- 0x24420001, 0xac620034, 0x32020002, 0x1040001a, 0x32020004, 0x8f420140,
- 0xaf420020, 0x93630000, 0x306300ff, 0x10710005, 0x00000000, 0x10750006,
- 0x00000000, 0x0a00035d, 0x00000000, 0xaf940000, 0x0a00035e, 0x00000000,
- 0xaf930000, 0x0a00035e, 0x00000000, 0xaf800000, 0x0e000c7b, 0x00000000,
- 0x3c040800, 0x8c820038, 0xaf520178, 0x24420001, 0xac820038, 0x32020004,
- 0x1040ffa4, 0x00000000, 0x8f420180, 0xaf420020, 0x93630000, 0x306300ff,
- 0x10710005, 0x00000000, 0x10750006, 0x00000000, 0x0a000378, 0x00000000,
- 0xaf940000, 0x0a000379, 0x00000000, 0xaf930000, 0x0a000379, 0x00000000,
- 0xaf800000, 0x8f430180, 0x24020f00, 0x14620005, 0x00000000, 0x8f420188,
- 0xa742009c, 0x0a000387, 0x8fc2003c, 0x93620000, 0x14510004, 0x8fc2003c,
- 0x0e000bad, 0x00000000, 0x8fc2003c, 0xaf5201b8, 0x24420001, 0x0a00030b,
- 0xafc2003c, 0x27bdffe8, 0xafbf0010, 0x97420108, 0x24033000, 0x30447000,
- 0x10830016, 0x28823001, 0x10400007, 0x24024000, 0x1080000b, 0x24022000,
- 0x1082000c, 0x00000000, 0x0a0003b3, 0x00000000, 0x10820010, 0x24025000,
- 0x10820012, 0x00000000, 0x0a0003b3, 0x00000000, 0x0000000d, 0x0a0003b5,
- 0x00001021, 0x0e000442, 0x00000000, 0x0a0003b6, 0x8fbf0010, 0x0e00041a,
- 0x00000000, 0x0a0003b5, 0x00001021, 0x0e000669, 0x00000000, 0x0a0003b5,
- 0x00001021, 0x0e001467, 0x00000000, 0x0a0003b5, 0x00001021, 0x0000000d,
- 0x00001021, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x93620000, 0x24030020,
- 0x304400ff, 0x10830005, 0x24020030, 0x10820007, 0x00000000, 0x0a0003c9,
- 0x00000000, 0x2782000c, 0xaf820000, 0x03e00008, 0x00000000, 0x27820008,
- 0xaf820000, 0x03e00008, 0x00000000, 0xaf800000, 0x03e00008, 0x00000000,
- 0x0000000d, 0x03e00008, 0x00001021, 0x03e00008, 0x00001021, 0x27440100,
- 0x94830008, 0x30620004, 0x10400017, 0x30620002, 0x8f4202b8, 0x04430007,
- 0x8c820020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001, 0x03e00008,
- 0xac830060, 0xaf420280, 0x94830016, 0x3c060800, 0xa7430284, 0x8c850004,
- 0x8cc4005c, 0x00001021, 0x3c031000, 0x24840001, 0xaf450288, 0xaf4302b8,
- 0x03e00008, 0xacc4005c, 0x14400003, 0x3c040800, 0x03e00008, 0x00001021,
- 0x8c830084, 0x24020001, 0x24630001, 0x03e00008, 0xac830084, 0x27450100,
- 0x3c040800, 0x8c820088, 0x94a3000c, 0x24420001, 0x007a1821, 0xac820088,
- 0x8ca40018, 0x90664000, 0xaf440038, 0x8ca2001c, 0x2403fff8, 0x00063600,
- 0x00431024, 0x34420004, 0x3c030005, 0xaf42003c, 0xaf430030, 0x00000000,
- 0x00000000, 0x00000000, 0xaf460404, 0x00000000, 0x00000000, 0x00000000,
- 0x3c020006, 0x34420001, 0xaf420030, 0x00000000, 0x00000000, 0x00000000,
- 0x8f420000, 0x30420010, 0x1040fffd, 0x00001021, 0x03e00008, 0x00000000,
- 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x1060001e,
- 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020018, 0xac620000,
- 0x8f840018, 0x9602000c, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018,
- 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018,
- 0x3c026000, 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce,
- 0x8f850018, 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c,
- 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010,
- 0x27500100, 0xafbf0014, 0x92020009, 0x14400003, 0x3c020800, 0x0a00046c,
- 0x24020001, 0x8c430020, 0x1060001f, 0x00001021, 0x0e00148e, 0x00000000,
- 0x8f830018, 0x8e020018, 0xac620000, 0x8f840018, 0x9602000c, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448, 0xac830018,
- 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018, 0x00021400, 0x00441025,
- 0x24040001, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf0014, 0x8fb00010,
- 0x03e00008, 0x27bd0018, 0x3c0b0800, 0x8d6808b0, 0x3c070800, 0x24e700b0,
- 0x00084900, 0x01271821, 0xac640000, 0x93620005, 0x97660008, 0x00e95021,
- 0x93630023, 0x9364003f, 0x25080001, 0x00021600, 0x00063400, 0x00461025,
- 0x00031a00, 0x00431025, 0x00822025, 0xad440004, 0x9362007e, 0x9366007f,
- 0x8f630178, 0x9364007a, 0x00021600, 0x00063400, 0x00461025, 0x00031a00,
- 0x00431025, 0x00822025, 0xad440008, 0x93620080, 0x9363007d, 0x3108007f,
- 0x01403821, 0xad6808b0, 0x00021600, 0x00031c00, 0x00431025, 0x00451025,
- 0x03e00008, 0xace2000c, 0x27bdffb8, 0xafb3002c, 0x00009821, 0xafbe0040,
- 0x0000f021, 0xafb50034, 0x27550100, 0xafbf0044, 0xafb7003c, 0xafb60038,
- 0xafb40030, 0xafb20028, 0xafb10024, 0xafb00020, 0xafa00010, 0xafa00014,
- 0x96a20008, 0x8f540100, 0x8eb10018, 0x30420001, 0x10400037, 0x02a0b821,
- 0x8f630054, 0x2622ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d,
- 0x00000000, 0x2400015c, 0x0a0004e5, 0x00002021, 0x8f62004c, 0x02221023,
- 0x18400028, 0x00002021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c,
- 0x308400ff, 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c,
- 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001,
- 0x00021023, 0x30420005, 0x0a0004e5, 0x34440004, 0x27660100, 0x00041080,
- 0x00c21021, 0x8c430000, 0x02231823, 0x04600004, 0x24820001, 0x30440007,
- 0x1485fff9, 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094,
- 0x24040005, 0x24420001, 0x0a0004e5, 0xac620094, 0x24040004, 0x00809821,
- 0x9362003f, 0x304400ff, 0x38830016, 0x2c630001, 0x38820010, 0x2c420001,
- 0x00621825, 0x1460000c, 0x24020001, 0x38830008, 0x2c630001, 0x38820014,
- 0x2c420001, 0x00621825, 0x14600005, 0x24020001, 0x24020012, 0x14820002,
- 0x00001021, 0x24020001, 0x10400009, 0x00000000, 0x8ea20020, 0x8f630040,
- 0x0040b021, 0x00431023, 0x5c400010, 0x8f760040, 0x0a000511, 0x00000000,
- 0x9343010b, 0x24020004, 0x1462000a, 0x8eb60020, 0x8f630040, 0x3c021000,
- 0x00761823, 0x0043102a, 0x10400004, 0x00000000, 0x0000000d, 0x00000000,
- 0x240002fa, 0x9343010b, 0x24020004, 0x5462000b, 0x96a20008, 0x24020001,
- 0xafa20010, 0x96a20008, 0x24030001, 0xafa30018, 0x8eb2001c, 0x36730002,
- 0x30420020, 0x0a000526, 0xafa20014, 0x36730080, 0x30420002, 0x10400003,
- 0xafa00018, 0x0a000526, 0x8eb2001c, 0x8eb20014, 0x2402fffb, 0x02628024,
- 0x1200002a, 0x3c030800, 0x8c620030, 0x02021024, 0x10400026, 0x3c020800,
- 0x8c430020, 0x10600024, 0x32620004, 0x0e00148e, 0x00000000, 0x8f830018,
- 0x8f420100, 0xac620000, 0x8f840018, 0x02401821, 0x32620002, 0xac900004,
- 0x8f840018, 0x54400001, 0x02c01821, 0xac830008, 0x8f830018, 0x8ee20020,
- 0xac62000c, 0x8f840018, 0x8f620040, 0xac820010, 0x8f830018, 0x8ee20018,
- 0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
- 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc,
- 0xaca3001c, 0x32620004, 0x10400063, 0x00003821, 0x3c029000, 0x34420001,
- 0x3c038000, 0x02821025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000,
- 0x8f65005c, 0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821,
- 0x00a2102b, 0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023,
- 0xaf710064, 0x3c023fff, 0x0a000580, 0x3442ffff, 0x8f62005c, 0x02221023,
- 0x04400011, 0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff,
- 0x3442ffff, 0xaf710064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004,
- 0x02251021, 0x3c053fff, 0x34a5ffff, 0x02251021, 0xaf62005c, 0x24070001,
- 0xaf71004c, 0x8f620054, 0x16220005, 0x00000000, 0x93620023, 0x30420040,
- 0x10400017, 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001,
- 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804,
- 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b,
- 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021,
- 0xaf62000c, 0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000,
- 0x34420001, 0x02821025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004,
- 0x00000000, 0x0e0013c4, 0x00000000, 0x00403821, 0x54e00001, 0x241e0001,
- 0x8f700040, 0x8f620040, 0x14520003, 0x00521023, 0x0a0005bf, 0x00001021,
- 0x28420001, 0x10400041, 0x8fa20010, 0x0e000fae, 0x02402021, 0xaf720040,
- 0x9362003e, 0x30420001, 0x1440000b, 0x3c029000, 0x93620022, 0x24420001,
- 0xa3620022, 0x93630022, 0x3c020800, 0x8c440098, 0x0064182b, 0x14600027,
- 0x3c020800, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000,
- 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
- 0x34420001, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020,
- 0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050273, 0x0a0005f2,
- 0x24050001, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
- 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x24050001, 0x24020001, 0xa7620012,
- 0xa3600022, 0x0a0005fe, 0x2ca20001, 0x9743007a, 0x9444002a, 0x00002821,
- 0x00641821, 0x3063fffe, 0xa7630012, 0x2ca20001, 0x00021023, 0x03c2f024,
- 0x8fa20010, 0x10400004, 0x8fa30014, 0x0e0013c1, 0x00000000, 0x8fa30014,
- 0x10600003, 0x00000000, 0x0e0010eb, 0x00000000, 0x13c0001f, 0x3c029000,
- 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074,
- 0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000, 0x02802021,
- 0x0e000470, 0x2405036c, 0x0a00062b, 0x8fa20018, 0x8f4201f8, 0x00431024,
- 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, 0xaf4301f8,
- 0x8fa20018, 0x5040002f, 0x96a20008, 0x8f620048, 0x8f630024, 0x00761821,
- 0xaf630048, 0x9764003c, 0x00501023, 0x0044102b, 0x10400025, 0x3c029000,
- 0x34420001, 0x3c040800, 0x8c830080, 0x8f450100, 0x3c068000, 0x24630001,
- 0x00a21025, 0xac830080, 0xaf420020, 0x8f420020, 0x00461024, 0x1440fffd,
- 0x00000000, 0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074,
- 0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021,
- 0x0e000470, 0x2405038a, 0x0a00065b, 0x96a20008, 0x8f4201f8, 0x00431024,
- 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8,
- 0x96a20008, 0x8fbf0044, 0x8fbe0040, 0x8fb7003c, 0x8fb60038, 0x8fb50034,
- 0x8fb40030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x00021042,
- 0x30420001, 0x03e00008, 0x27bd0048, 0x27bdffe0, 0xafbf0018, 0x97420108,
- 0x24030019, 0x304400ff, 0x10830065, 0x2882001a, 0x1040001a, 0x2882000a,
- 0x1040000f, 0x28820008, 0x10400040, 0x24020001, 0x1082003a, 0x28820002,
- 0x50400005, 0x24020006, 0x10800032, 0x3c026000, 0x0a0006fb, 0x00000000,
- 0x1082003d, 0x00000000, 0x0a0006fb, 0x00000000, 0x2402000b, 0x10820044,
- 0x2882000b, 0x1440004b, 0x2402000e, 0x10820045, 0x00000000, 0x0a0006fb,
- 0x00000000, 0x24020020, 0x10820062, 0x28820021, 0x1040000e, 0x2402001c,
- 0x1082004c, 0x2882001d, 0x10400005, 0x2402001b, 0x10820043, 0x00000000,
- 0x0a0006fb, 0x00000000, 0x2402001f, 0x10820050, 0x00000000, 0x0a0006fb,
- 0x00000000, 0x240200c1, 0x10820042, 0x288200c2, 0x10400005, 0x24020080,
- 0x10820021, 0x00000000, 0x0a0006fb, 0x00000000, 0x240200c2, 0x1082003d,
- 0x240200c9, 0x50820049, 0xafa00010, 0x0a0006fb, 0x00000000, 0x0e001163,
- 0xac400808, 0x0a0006fd, 0x8fbf0018, 0x3c026000, 0x8c444448, 0x3c030800,
- 0xac640064, 0x0e001163, 0x00000000, 0x3c026000, 0x8c444448, 0x3c030800,
- 0x0a0006fc, 0xac640068, 0x8f440100, 0x0e0006ff, 0x00000000, 0x3c026000,
- 0x8c444448, 0x3c030800, 0x0a0006fc, 0xac64006c, 0x0e001191, 0x00000000,
- 0x0a0006fd, 0x8fbf0018, 0x8f440100, 0x0e0011bb, 0x00000000, 0x0a0006fd,
- 0x8fbf0018, 0x0e001202, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0000000d,
- 0x0a0006fd, 0x8fbf0018, 0x0e000826, 0x00000000, 0x0a0006fd, 0x8fbf0018,
- 0x8f440100, 0x0e001264, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00134e,
- 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00087c, 0x27440100, 0x0a0006fd,
- 0x8fbf0018, 0x8f640040, 0x0e000fae, 0x00000000, 0x0a0006fd, 0x8fbf0018,
- 0x8f440100, 0x0e001059, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e001417,
- 0x00000000, 0x0a0006fd, 0x8fbf0018, 0xafa00014, 0x8f440100, 0x8f450118,
- 0x8f46011c, 0x0e001439, 0x8f470120, 0x0a0006fd, 0x8fbf0018, 0x0000000d,
- 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x9742010c,
- 0x1440005e, 0x00803821, 0x3c029000, 0x34420001, 0x00e21025, 0xaf420020,
- 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023,
- 0x30420010, 0x14400026, 0x3c030800, 0x8f630074, 0x3c027fff, 0x3442ffff,
- 0x00621824, 0xaf630074, 0x93620005, 0x34420001, 0xa3620005, 0x8f63004c,
- 0x8f620054, 0x10620021, 0x24040001, 0x9762006a, 0x00022880, 0x50a00001,
- 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821,
- 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050,
- 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824,
- 0x00a21021, 0xaf62000c, 0x0a00073d, 0x24040001, 0x8c6200a8, 0x00002021,
- 0x24420001, 0xac6200a8, 0x0000000d, 0x00000000, 0x2400044d, 0x3c028000,
- 0x34420001, 0x00e21025, 0xaf420020, 0x1080001f, 0x3c029000, 0x34420001,
- 0x00e21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
- 0x00e31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00e02021, 0x0e000470,
- 0x24050455, 0x0a000761, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
- 0x24020002, 0x3c031000, 0xaf4701c0, 0xa34201c4, 0xaf4301f8, 0x0e001163,
- 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafbf0024,
- 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x93630005,
- 0x00809821, 0x24020030, 0x30630030, 0x146200ac, 0x00a0a021, 0x3c020800,
- 0x8c430020, 0x106000a6, 0x00000000, 0x0e00148e, 0x00000000, 0x8f830018,
- 0xac730000, 0x936200c4, 0x30420002, 0x10400004, 0x24020001, 0x8f830018,
- 0x0a000784, 0x00000000, 0x8f830018, 0x24020003, 0xac620004, 0x8f6200dc,
- 0x8f630040, 0x00431023, 0x18400004, 0x00000000, 0x0000000d, 0x00000000,
- 0x24000509, 0x8f840018, 0x8f6200dc, 0xac820008, 0x8f830018, 0xac60000c,
- 0x8f820018, 0xac400010, 0x8f830018, 0x8f62004c, 0x3c100800, 0xac620014,
- 0x8f850018, 0x3c026000, 0x8c434448, 0x261258c0, 0x00002021, 0xaca30018,
- 0x9642000e, 0x8f850018, 0x3c034010, 0x00431025, 0x0e0014cc, 0xaca2001c,
- 0x8f830018, 0xac730000, 0x9362003e, 0x9363003f, 0x8f840018, 0x00021200,
- 0x00621825, 0xac830004, 0x93620081, 0x93630082, 0x8f840018, 0x00021600,
- 0x00031c00, 0x00431025, 0xac820008, 0x8f830018, 0x8f620040, 0xac62000c,
- 0x8f840018, 0x8f620048, 0xac820010, 0x8f71004c, 0x8f820018, 0xac510014,
- 0x8f620050, 0x8f850018, 0x00401821, 0x02221023, 0x5c400001, 0x02201821,
- 0x00002021, 0xaca30018, 0x9642000e, 0x8f850018, 0x3c03c00b, 0x00431025,
- 0x0e0014cc, 0xaca2001c, 0x8f620054, 0x8f840018, 0x00401821, 0x02221023,
- 0x5c400001, 0x02201821, 0xac830000, 0x8f840018, 0x8f630058, 0xac830004,
- 0x93620023, 0x30420010, 0x10400004, 0x00000000, 0x8f830018, 0x0a0007dd,
- 0x8f620148, 0x8f830018, 0x8f62005c, 0xac620008, 0x8f830018, 0x8f620060,
- 0xac62000c, 0x8f840018, 0x8f620064, 0xac820010, 0x97630068, 0x9762006a,
- 0x8f840018, 0x00031c00, 0x00431025, 0xac820014, 0x8f850018, 0x00002021,
- 0x2402ffff, 0x260358c0, 0xaca20018, 0x9462000e, 0x8f850018, 0x3c03c00c,
- 0x00431025, 0x0e0014cc, 0xaca2001c, 0x8f840018, 0x8f630018, 0xac830000,
- 0x936200c4, 0x30420002, 0x10400006, 0x00000000, 0x976200c8, 0x8f830018,
- 0x3042ffff, 0x0a000803, 0xac620004, 0x8f820018, 0xac400004, 0x8f830018,
- 0x8f62006c, 0xac620008, 0x8f840018, 0x8f6200dc, 0xac82000c, 0x8f830018,
- 0xac600010, 0x93620005, 0x8f830018, 0x00021600, 0x00541025, 0xac620014,
- 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x260258c0, 0xaca30018,
- 0x9443000e, 0x8f850018, 0x3c02400d, 0x00621825, 0x0e0014cc, 0xaca3001c,
- 0x0e00122e, 0x02602021, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb00010,
- 0x27500100, 0xafbf0018, 0xafb10014, 0x9603000c, 0x240200c1, 0x54620024,
- 0x8e040000, 0x3c029000, 0x8f450100, 0x34420001, 0x3c038000, 0x00a21025,
- 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d,
- 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x00a31825,
- 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470, 0x240505b2,
- 0x0a000878, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002,
- 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x0a000878, 0x8fbf0018,
- 0x8f65004c, 0x24060001, 0x0e0012a3, 0x240705be, 0x3c020800, 0x8c430020,
- 0x9611000c, 0x1060001d, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018,
- 0xac500000, 0x8f840018, 0x00111400, 0xac820004, 0x8f830018, 0xac600008,
- 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f840018, 0x240205c1,
- 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
- 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc,
- 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
- 0x27bdffb0, 0xafb5003c, 0x0000a821, 0xafbe0048, 0x0000f021, 0xafb70044,
- 0x0000b821, 0xafb30034, 0x00009821, 0xafb60040, 0x0080b021, 0xafbf004c,
- 0xafb40038, 0xafb20030, 0xafb1002c, 0xafb00028, 0xafa00010, 0x8f620040,
- 0x8ec30014, 0x96d1000c, 0x00431023, 0x04410025, 0x8ed40000, 0x32220401,
- 0x1040030c, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000,
- 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
- 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020,
- 0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050664, 0x0a000ba2,
- 0x8fbf004c, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
- 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x0a000ba2, 0x8fbf004c, 0x32220010,
- 0x1040006b, 0x00003021, 0x9362003f, 0x92c6000f, 0x304500ff, 0x24c3fff8,
- 0x2c62000f, 0x10400057, 0x3c020800, 0x244257c0, 0x00031880, 0x00621821,
- 0x8c640000, 0x00800008, 0x00000000, 0x38a20012, 0x0a000924, 0x0002a82b,
- 0x2402000e, 0x14a20004, 0x2402000c, 0x24150001, 0x0a000924, 0x24060010,
- 0x10a20049, 0x38a30010, 0x2c630001, 0x38a20016, 0x2c420001, 0x00621825,
- 0x1460004d, 0x0000a821, 0x24020014, 0x10a2004a, 0x00000000, 0x0000000d,
- 0x00000000, 0x2400069c, 0x0a000924, 0x0000a821, 0x24020016, 0x14a20005,
- 0x2402000c, 0x24150001, 0x24060010, 0x0a000924, 0x3231fffd, 0x10a20032,
- 0x38a30010, 0x2c630001, 0x38a2000e, 0x2c420001, 0x00621825, 0x14600036,
- 0x0000a821, 0x24020014, 0x14a20003, 0x24150001, 0x0a000924, 0x24060012,
- 0x0000000d, 0x00000000, 0x240006bc, 0x0a000924, 0x0000a821, 0x2402000e,
- 0x14a20004, 0x24020016, 0x24150001, 0x0a000924, 0x3231fffb, 0x14a20004,
- 0x24020014, 0x24150001, 0x0a000924, 0x3231fffd, 0x54a20013, 0x92c2000e,
- 0x24150001, 0x24060012, 0x0a000924, 0x3231fffd, 0x2402000c, 0x54a2000c,
- 0x92c2000e, 0x92c3000e, 0x2402000a, 0x10620005, 0x24150001, 0x0000000d,
- 0x00000000, 0x240006e8, 0x24150001, 0x0a000924, 0x24060014, 0x92c2000e,
- 0x14a20003, 0x00000000, 0x0a000924, 0x24150001, 0x10a6ffc1, 0x24020012,
- 0x10a20005, 0x0000a821, 0x0000000d, 0x00000000, 0x24000704, 0x0000a821,
- 0x12a00022, 0x32220004, 0x10400002, 0x24020001, 0xafa20010, 0x32230102,
- 0x24020002, 0x1462000f, 0x00000000, 0x92c2000a, 0x30420020, 0x1440000b,
- 0x00000000, 0x8f630048, 0x8f620040, 0x14620004, 0x00000000, 0x8f620048,
- 0x24420001, 0xaf620048, 0x8f620040, 0x24420001, 0xaf620040, 0xa366003f,
- 0x38c30012, 0x2c630001, 0x38c20010, 0x2c420001, 0x00621825, 0x10600005,
- 0x3c030800, 0x8c620074, 0x24420001, 0x0e00140d, 0xac620074, 0x32220040,
- 0x32230020, 0xafa30020, 0x32230080, 0xafa30024, 0x32230001, 0xafa30018,
- 0x32230008, 0xafa3001c, 0x32230100, 0x104000c4, 0xafa30014, 0x8ec60010,
- 0x8f630054, 0x24c2ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d,
- 0x00000000, 0x2400015c, 0x0a000989, 0x00009021, 0x8f62004c, 0x00c21023,
- 0x18400028, 0x00009021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c,
- 0x308400ff, 0x24420001, 0x30a500ff, 0x00804021, 0x1485000b, 0xac62008c,
- 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001,
- 0x00021023, 0x30420005, 0x0a000989, 0x34520004, 0x27670100, 0x00041080,
- 0x00e21021, 0x8c430000, 0x00c31823, 0x04600004, 0x24820001, 0x30440007,
- 0x1485fff9, 0x00041080, 0x10880007, 0x3c030800, 0xa3640121, 0x8c620094,
- 0x24120005, 0x24420001, 0x0a000989, 0xac620094, 0x24120004, 0x32420001,
- 0x10400021, 0x3c020800, 0x8c430020, 0x8ed00000, 0x1060001c, 0x8ed30010,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001,
- 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f820018, 0xac530014, 0x8f850018, 0x3c026000, 0x8c434448,
- 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010,
- 0x00621825, 0x0e0014cc, 0xaca3001c, 0x24130001, 0x32420004, 0x10400068,
- 0x00003821, 0x3c029000, 0x8ec60010, 0x34420001, 0x3c038000, 0x02821025,
- 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
- 0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c,
- 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006,
- 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf660064, 0x3c023fff,
- 0x0a0009da, 0x3442ffff, 0x8f62005c, 0x00c21023, 0x04400011, 0x00000000,
- 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf660064,
- 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x00c51021, 0x3c053fff,
- 0x34a5ffff, 0x00c51021, 0xaf62005c, 0x24070001, 0xaf66004c, 0x8fa20010,
- 0x10400003, 0x00000000, 0xaf660050, 0xaf660054, 0x8f620054, 0x14c20005,
- 0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a,
- 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800,
- 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021,
- 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074,
- 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x93620082, 0x30420080,
- 0x50400001, 0xa3600081, 0x3c028000, 0x34420001, 0x02821025, 0xaf420020,
- 0x9363007e, 0x9362007a, 0x10620005, 0x00e0b821, 0x0e0013c4, 0x00000000,
- 0x00403821, 0x00e0b821, 0x8fa30020, 0x10600009, 0x8fa20010, 0x8ec20018,
- 0xaf620018, 0x8ec3001c, 0xaf63001c, 0x8ec20020, 0x24170001, 0xaf620058,
- 0x8fa20010, 0x10400057, 0x8fa30024, 0x93620023, 0x30420040, 0x10400053,
- 0x00000000, 0x16600021, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040001e,
- 0x24130001, 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018,
- 0x24020001, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
- 0x8f830018, 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000,
- 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
- 0x3c024010, 0x00621825, 0xaca3001c, 0x0e0014cc, 0x24130001, 0x8e420020,
- 0x1040001c, 0x8ed00000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000,
- 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c,
- 0x8f820018, 0xac400010, 0x8f830018, 0x24020798, 0xac620014, 0x8f850018,
- 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce,
- 0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000,
- 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x24020001, 0xaf62000c, 0x93630023, 0x3c028000, 0x34420001,
- 0x02821025, 0x306300bf, 0xa3630023, 0xaf420020, 0x8fa30024, 0x10600012,
- 0x8fa30018, 0x9362007c, 0x24420001, 0xa362007c, 0x9363007e, 0x9362007a,
- 0x1462000b, 0x8fa30018, 0x9362007c, 0x3c030800, 0x8c640024, 0x0044102b,
- 0x14400005, 0x8fa30018, 0x0e0013c4, 0x00000000, 0x02e2b825, 0x8fa30018,
- 0x3062ffff, 0x10400003, 0x32220200, 0x0a000a94, 0x241e0004, 0x10400003,
- 0x00000000, 0x241e0040, 0x24170001, 0x12a000d0, 0x32220002, 0x104000cf,
- 0x8fa2001c, 0x92c2000a, 0x30420002, 0x5040003b, 0x92c2000a, 0x93620023,
- 0x30420008, 0x54400037, 0x92c2000a, 0x3c020800, 0x8c430020, 0x10600023,
- 0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000,
- 0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040,
- 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018,
- 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018,
- 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
- 0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
- 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630008,
- 0xa3630023, 0xaf420020, 0x92c2000a, 0x30420020, 0x1040008e, 0x8fa2001c,
- 0x93620023, 0x30420001, 0x14400035, 0x3c020800, 0x8c430020, 0x10600023,
- 0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000,
- 0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040,
- 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018,
- 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018,
- 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
- 0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
- 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630001,
- 0xa3630023, 0xaf420020, 0x93620023, 0x30420040, 0x10400052, 0x8fa2001c,
- 0x16600020, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040003c, 0x3c029000,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x24020001,
- 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448,
- 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010,
- 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x3c029000,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x3c02008d,
- 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f840018, 0x240207ee, 0xac820014, 0x8f850018, 0x3c026000,
- 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
- 0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001,
- 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x306300bf,
- 0xa3630023, 0xaf420020, 0x8fa2001c, 0x1040000e, 0x8fa20014, 0x92c2000a,
- 0xa3620082, 0x57c00005, 0x37de0008, 0x8fa30014, 0x10600004, 0x00000000,
- 0x37de0008, 0x0a000b75, 0x24170001, 0x0e0012cf, 0x02802021, 0x8fa20014,
- 0x10400003, 0x00000000, 0x37de0010, 0x24170001, 0x12e00020, 0x3c029000,
- 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x03c21025, 0xa362007d,
- 0x8f640074, 0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000,
- 0x02802021, 0x0e000470, 0x2405082a, 0x0a000b9b, 0x00000000, 0x8f4201f8,
- 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4,
- 0xaf4301f8, 0x9363003f, 0x24020012, 0x14620004, 0x8fbf004c, 0x0e00140d,
- 0x00000000, 0x8fbf004c, 0x8fbe0048, 0x8fb70044, 0x8fb60040, 0x8fb5003c,
- 0x8fb40038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x03e00008,
- 0x27bd0050, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f500180, 0x97420184,
- 0x30420200, 0x14400015, 0x00000000, 0x8f430188, 0x3c02ff00, 0x00621824,
- 0x3c020200, 0x10620031, 0x0043102b, 0x14400007, 0x3c020300, 0x1060000b,
- 0x3c020100, 0x1062000d, 0x00000000, 0x0a000c2c, 0x00000000, 0x10620027,
- 0x3c020400, 0x1062003e, 0x02002021, 0x0a000c2c, 0x00000000, 0x0e000c31,
- 0x02002021, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420020, 0x1440005e,
- 0x8fbf0014, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000,
- 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000,
- 0x34630001, 0x02031825, 0x34420020, 0xa3620005, 0xaf430020, 0x93620005,
- 0x30420020, 0x14400003, 0x02002021, 0x0000000d, 0x02002021, 0x0e000766,
- 0x24055854, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420001, 0x1040003f,
- 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020,
- 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, 0x34420004, 0xa3620023,
- 0x93630005, 0x3c048000, 0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020,
- 0x34840001, 0x02042025, 0x0a000c0a, 0xaf440020, 0x00002821, 0x00003021,
- 0x0e000fb1, 0x240708d9, 0x3c020800, 0x8c430020, 0x10600023, 0x8fbf0014,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x93630082, 0x9362003f,
- 0x8f840018, 0x00031a00, 0x00431025, 0xac820004, 0x8f830018, 0xac600008,
- 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014,
- 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
- 0x944358ce, 0x8f850018, 0x3c02400a, 0x00621825, 0x0e0014cc, 0xaca3001c,
- 0x0a000c2e, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008,
- 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x8f420188, 0x00803021, 0x93640000,
- 0x24030020, 0x00021402, 0x10830008, 0x304500ff, 0x3c036018, 0x8c625000,
- 0x34420400, 0xac625000, 0x0000000d, 0x00000000, 0x24000955, 0x9363003f,
- 0x24020012, 0x14620023, 0x3c029000, 0x34420001, 0x3c038000, 0x00c21025,
- 0xaf650178, 0xa365007a, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
- 0x00c31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00c02021, 0x0e000470,
- 0x24050963, 0x0a000c79, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd,
- 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a000c79,
- 0x8fbf0010, 0x9362007e, 0x1445000e, 0x00000000, 0x8f620178, 0x1045000b,
- 0x00000000, 0x8f820000, 0xaf650178, 0x8f660178, 0x8f440180, 0x8f65004c,
- 0x8c430000, 0x0060f809, 0x30c600ff, 0x0a000c79, 0x8fbf0010, 0xaf650178,
- 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93630000,
- 0x24020020, 0x10620005, 0x00000000, 0x93630000, 0x24020030, 0x1462004d,
- 0x8fbf0010, 0x93420148, 0x2444ffff, 0x2c830005, 0x10600047, 0x3c020800,
- 0x24425800, 0x00041880, 0x00621821, 0x8c640000, 0x00800008, 0x00000000,
- 0x8f430144, 0x8f62000c, 0x14620006, 0x24020001, 0xaf62000c, 0x0e000d59,
- 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x8f62000c, 0x0a000cca, 0x00000000,
- 0x97630010, 0x8f420144, 0x14430006, 0x24020001, 0xa7620010, 0x0e00137a,
- 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620010, 0x0a000cca, 0x00000000,
- 0x97630012, 0x8f420144, 0x14430006, 0x24020001, 0xa7620012, 0x0e001395,
- 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620012, 0x0a000cca, 0x00000000,
- 0x97630014, 0x8f420144, 0x14430006, 0x24020001, 0xa7620014, 0x0e0013bb,
- 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620014, 0x0a000cca, 0x00000000,
- 0x97630016, 0x8f420144, 0x14430006, 0x24020001, 0xa7620016, 0x0e0013be,
- 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620016, 0x14400006, 0x8fbf0010,
- 0x3c030800, 0x8c620070, 0x24420001, 0xac620070, 0x8fbf0010, 0x03e00008,
- 0x27bd0018, 0x27bdffe0, 0x3c029000, 0xafbf001c, 0xafb20018, 0xafb10014,
- 0xafb00010, 0x8f500140, 0x34420001, 0x3c038000, 0x02021025, 0xaf420020,
- 0x8f420020, 0x00431024, 0x1440fffd, 0x24020012, 0x24030080, 0xa362003f,
- 0xa3630082, 0x93620023, 0x30420040, 0x10400007, 0x00008821, 0x93620023,
- 0x24110001, 0x304200bf, 0xa3620023, 0x0a000cf0, 0x3c028000, 0x3c028000,
- 0x34420001, 0x3c039000, 0x34630001, 0x3c048000, 0x02021025, 0x02031825,
- 0xaf420020, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000,
- 0x9362007d, 0x3c038000, 0x34420020, 0xa362007d, 0x8f640074, 0x34630001,
- 0x02031825, 0xaf430020, 0x04810006, 0x3c038000, 0x02002021, 0x0e000470,
- 0x24050a63, 0x0a000d13, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
- 0x24020002, 0x3c031000, 0xaf5001c0, 0xa34201c4, 0xaf4301f8, 0x1220003f,
- 0x3c120800, 0x8e420020, 0x8f71004c, 0x1040003c, 0x8fbf001c, 0x0e00148e,
- 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f820018, 0xac510014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
- 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825,
- 0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x8fbf001c, 0x0e00148e,
- 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x3c02008d, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f840018, 0x24020a6a, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448,
- 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019,
- 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
- 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x93620081,
- 0x3c030800, 0x8c640048, 0x0044102b, 0x14400005, 0x00000000, 0x0e000cd3,
- 0x00000000, 0x0a000da4, 0x8fbf0010, 0x93620081, 0x24420001, 0x0e0013c4,
- 0xa3620081, 0x9763006a, 0x00032880, 0x14a00002, 0x00403821, 0x24050001,
- 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804,
- 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b,
- 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021,
- 0xaf62000c, 0x10e00021, 0x3c029000, 0x8f450140, 0x34420001, 0x3c038000,
- 0x00a21025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
- 0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001,
- 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470,
- 0x24050a92, 0x0a000da4, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd,
- 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x8fbf0010,
- 0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafb3001c, 0x27530100, 0xafbf0024,
- 0xafb40020, 0xafb20018, 0xafb10014, 0xafb00010, 0x96620008, 0x3c140800,
- 0x8f520100, 0x30420001, 0x104000da, 0x00000000, 0x8e700018, 0x8f630054,
- 0x2602ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, 0x00000000,
- 0x2400015c, 0x0a000dea, 0x00008821, 0x8f62004c, 0x02021023, 0x18400028,
- 0x00008821, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff,
- 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c, 0x3c040800,
- 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, 0x00021023,
- 0x30420005, 0x0a000dea, 0x34510004, 0x27660100, 0x00041080, 0x00c21021,
- 0x8c430000, 0x02031823, 0x04600004, 0x24820001, 0x30440007, 0x1485fff9,
- 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094, 0x24110005,
- 0x24420001, 0x0a000dea, 0xac620094, 0x24110004, 0x32220001, 0x1040001e,
- 0x8e820020, 0x1040001d, 0x32220004, 0x0e00148e, 0x00000000, 0x8f820018,
- 0xac520000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018, 0xac600008,
- 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac500014,
- 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018,
- 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc, 0xaca3001c,
- 0x32220004, 0x10400081, 0x00003821, 0x3c029000, 0x34420001, 0x3c038000,
- 0x02421025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c,
- 0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b,
- 0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf700064,
- 0x3c023fff, 0x0a000e37, 0x3442ffff, 0x8f62005c, 0x02021023, 0x04400011,
- 0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff,
- 0xaf700064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x02051021,
- 0x3c053fff, 0x34a5ffff, 0x02051021, 0xaf62005c, 0x24070001, 0xaf70004c,
- 0x8f620054, 0x16020005, 0x00000000, 0x93620023, 0x30420040, 0x10400017,
- 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068,
- 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b,
- 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001,
- 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c,
- 0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000, 0x34420001,
- 0x02421025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, 0x00000000,
- 0x0e0013c4, 0x00000000, 0x00403821, 0x10e0001f, 0x3c029000, 0x34420001,
- 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001,
- 0x02431825, 0xaf430020, 0x04810006, 0x3c038000, 0x02402021, 0x0e000470,
- 0x24050b3d, 0x0a000e8d, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd,
- 0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4, 0xaf4301f8, 0x9342010b,
- 0x9343010b, 0x8e820020, 0x27500100, 0x38630006, 0x10400029, 0x2c710001,
- 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
- 0x96020008, 0xac820004, 0x8f830018, 0x8e020014, 0xac620008, 0x8f850018,
- 0x3c026000, 0x8c434448, 0xaca3000c, 0x8f840018, 0x96020012, 0xac820010,
- 0x8f850018, 0x8e030020, 0xaca30014, 0x9602000c, 0x9603000e, 0x8f840018,
- 0x00021400, 0x00431025, 0xac820018, 0x12200005, 0x3c020800, 0x944358ce,
- 0x8f840018, 0x0a000eb8, 0x3c024013, 0x944358ce, 0x8f840018, 0x3c024014,
- 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8e700014, 0x8f620040,
- 0x14500003, 0x00501023, 0x0a000ec3, 0x00001021, 0x28420001, 0x1040003a,
- 0x00000000, 0x0e000fae, 0x02002021, 0xaf700040, 0x9362003e, 0x30420001,
- 0x1440000b, 0x3c029000, 0x93620022, 0x24420001, 0xa3620022, 0x93630022,
- 0x3c020800, 0x8c440098, 0x0064182b, 0x14600025, 0x3c020800, 0x3c029000,
- 0x34420001, 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d,
- 0x8f640074, 0x34630001, 0x02431825, 0xaf430020, 0x04810006, 0x3c038000,
- 0x02402021, 0x0e000470, 0x24050273, 0x0a000ef6, 0x24020001, 0x8f4201f8,
- 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4,
- 0xaf4301f8, 0x24020001, 0xa7620012, 0x0a000efe, 0xa3600022, 0x9743007a,
- 0x9444002a, 0x00641821, 0x3063fffe, 0xa7630012, 0x97420108, 0x8fbf0024,
- 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042,
- 0x30420001, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb20018, 0x3c120800,
- 0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400046, 0xafb10014,
- 0x0e00148e, 0x00000000, 0x8f840018, 0x8e020000, 0xac820000, 0x936300b1,
- 0x936200c5, 0x8f850018, 0x00031e00, 0x00021400, 0x34420100, 0x00621825,
- 0xaca30004, 0x8f840018, 0x8e02001c, 0xac820008, 0x8f830018, 0x8f620048,
- 0xac62000c, 0x8f840018, 0x96020012, 0xac820010, 0x8f830018, 0x8f620040,
- 0x24040001, 0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800,
- 0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018, 0x3c024016, 0x00621825,
- 0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010, 0x1060001c, 0x8e420020,
- 0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000,
- 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c,
- 0x8f820018, 0xac400010, 0x8f830018, 0xac600014, 0x8f850018, 0x3c036000,
- 0x8c634448, 0x24040001, 0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015,
- 0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0xafb20018,
- 0x3c120800, 0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400041,
- 0xafb10014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000,
- 0x8f840018, 0x24020100, 0xac820004, 0x8f830018, 0x8e02001c, 0xac620008,
- 0x8f840018, 0x8e020018, 0xac82000c, 0x8f830018, 0x96020012, 0xac620010,
- 0x8f840018, 0x96020008, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448,
- 0x24040001, 0x3c020800, 0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018,
- 0x3c024017, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010,
- 0x1060001c, 0x8e420020, 0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000,
- 0x8f820018, 0xac500000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008,
- 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0xac600014,
- 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, 0xaca30018, 0x9622000e,
- 0x8f850018, 0x3c034015, 0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021,
- 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
- 0x27bdfff0, 0x03e00008, 0x27bd0010, 0x27bdffd0, 0xafb10014, 0x00808821,
- 0xafb40020, 0x00c0a021, 0xafbf0028, 0xafb50024, 0xafb3001c, 0xafb20018,
- 0xafb00010, 0x93620023, 0x00e0a821, 0x30420040, 0x1040003e, 0x30b3ffff,
- 0x3c120800, 0x8e420020, 0x1040003a, 0x8f70004c, 0x0e00148e, 0x00000000,
- 0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018,
- 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
- 0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800,
- 0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010, 0x00621825,
- 0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001b, 0x00000000, 0x0e00148e,
- 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x3c02008d, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f820018, 0xac550014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001,
- 0xaca30018, 0x9602000e, 0x8f850018, 0x3c034019, 0x00431025, 0x0e0014cc,
- 0xaca2001c, 0x93620023, 0x30420020, 0x14400003, 0x3c120800, 0x1280003f,
- 0x3c029000, 0x8e420020, 0x8f70004c, 0x1040003b, 0x3c029000, 0x0e00148e,
- 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f820018, 0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448,
- 0x3c020800, 0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010,
- 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001c, 0x3c029000,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x00131400,
- 0xac820004, 0x8f830018, 0xac750008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c036000, 0x8c634448,
- 0x24040001, 0xaca30018, 0x9602000e, 0x8f850018, 0x3c03401b, 0x00431025,
- 0x0e0014cc, 0xaca2001c, 0x3c029000, 0x34420001, 0x02221025, 0xaf420020,
- 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023,
- 0x3c028000, 0x34420001, 0x02221025, 0x8fbf0028, 0x8fb50024, 0x8fb40020,
- 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3063009f, 0xa3630023,
- 0xaf420020, 0x03e00008, 0x27bd0030, 0x27bdffe0, 0xafb10014, 0x27510100,
- 0x3c029000, 0x34420001, 0xafb00010, 0x00808021, 0x02021025, 0x3c038000,
- 0xafbf0018, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000,
- 0xa7600008, 0x8f63005c, 0x3c028000, 0x34420001, 0xaf630148, 0x8f640050,
- 0x02021025, 0x3c039000, 0xaf64017c, 0xaf420020, 0x8f450100, 0x34630001,
- 0x3c048000, 0x00a31825, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd,
- 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d, 0x8f640074,
- 0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021,
- 0x0e000470, 0x24050de5, 0x0a001093, 0x3c020800, 0x8f4201f8, 0x00431024,
- 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8,
- 0x3c020800, 0x8c430020, 0x1060001e, 0x8fbf0018, 0x0e00148e, 0x00000000,
- 0x8f830018, 0xac700000, 0x9622000c, 0x8f840018, 0x00021400, 0xac820004,
- 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010,
- 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001,
- 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401f, 0x00621825,
- 0x0e0014cc, 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008,
- 0x27bd0020, 0x3c020800, 0x24424c3c, 0xaf82000c, 0x03e00008, 0x00000000,
- 0x27bdffe8, 0xafb00010, 0x27500100, 0xafbf0014, 0x8e02001c, 0x14400003,
- 0x3c020800, 0x0000000d, 0x3c020800, 0x8c430020, 0x10600020, 0x00001021,
- 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
- 0x8e02001c, 0xac820004, 0x8f830018, 0xac600008, 0x8f840018, 0x8e020018,
- 0xac82000c, 0x8f850018, 0x96020012, 0xaca20010, 0x8f830018, 0x3c026000,
- 0xac600014, 0x8f840018, 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce,
- 0x8f840018, 0x3c024012, 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001,
- 0x00001021, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800,
- 0x97430078, 0x9444002e, 0x00001021, 0x00641821, 0x3063fffe, 0x03e00008,
- 0xa7630010, 0x27bdfff0, 0x00001021, 0x03e00008, 0x27bd0010, 0x8f420100,
- 0x34420001, 0xaf4200a4, 0x03e00008, 0x00001021, 0x27bdffe0, 0xafbf0018,
- 0xafb10014, 0xafb00010, 0x9362007e, 0x30d000ff, 0x16020031, 0x00808821,
- 0x8f620178, 0x1602002e, 0x00000000, 0x9362007f, 0x1602002b, 0x00000000,
- 0x9362007a, 0x16020004, 0x00000000, 0x0000000d, 0x00000000, 0x240009d2,
- 0x0e0013e6, 0x00000000, 0x3c039000, 0x34630001, 0x3c048000, 0x02231825,
- 0xa370007a, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000,
- 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, 0x02231825,
- 0xaf430020, 0x04810006, 0x3c038000, 0x02202021, 0x0e000470, 0x240509dd,
- 0x0a001138, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002,
- 0x3c031000, 0xaf5101c0, 0xa34201c4, 0xaf4301f8, 0x0a001138, 0x8fbf0018,
- 0x0000000d, 0x00000000, 0x240009e2, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
- 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x30a500ff, 0x3c029000, 0x34420001,
- 0x00803821, 0x00e21025, 0x3c038000, 0xafbf0010, 0xaf420020, 0x8f420020,
- 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x00a21025,
- 0xa362007d, 0x8f640074, 0x34630001, 0x00e31825, 0xaf430020, 0x04810006,
- 0x3c038000, 0x00e02021, 0x0e000470, 0x00c02821, 0x0a001161, 0x8fbf0010,
- 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4701c0,
- 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800,
- 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x10600024, 0xafbf0014,
- 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018,
- 0x8e020004, 0xac820004, 0x8f830018, 0x8e020018, 0xac620008, 0x8f840018,
- 0x8e03001c, 0xac83000c, 0x9602000c, 0x9203000a, 0x8f840018, 0x00021400,
- 0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
- 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018,
- 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014,
- 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8,
- 0xafb00010, 0x27500100, 0x10600020, 0xafbf0014, 0x0e00148e, 0x00000000,
- 0x8f820018, 0xac400000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008,
- 0x8f830018, 0xac60000c, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400,
- 0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018,
- 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018,
- 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014,
- 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010, 0x27500100,
- 0xafbf0014, 0x9602000c, 0x10400024, 0x00802821, 0x3c020800, 0x8c430020,
- 0x1060003a, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f840018, 0x8e030000,
- 0xac830000, 0x9602000c, 0x8f840018, 0x00021400, 0xac820004, 0x8f830018,
- 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018,
- 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800,
- 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02400b, 0x00621825, 0x0e0014cc,
- 0xaca3001c, 0x0a0011ff, 0x8fbf0014, 0x93620005, 0x30420010, 0x14400015,
- 0x3c029000, 0x34420001, 0x00a21025, 0xaf420020, 0x3c038000, 0x8f420020,
- 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x93620005, 0x34630001,
- 0x00a02021, 0x00a31825, 0x24055852, 0x34420010, 0xa3620005, 0x0e000766,
- 0xaf430020, 0x0a0011ff, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010,
- 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010,
- 0x27500100, 0x10600022, 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f840018,
- 0x8e020004, 0xac820000, 0x9603000c, 0x9762002c, 0x8f840018, 0x00031c00,
- 0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
- 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000,
- 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018,
- 0x3c02400e, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x0e00122e, 0x8e040000,
- 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c038000, 0x8f420278,
- 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf440240, 0xa3420244,
- 0x03e00008, 0xaf430278, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014,
- 0x00808821, 0xafb20018, 0x00c09021, 0xafb00010, 0x30b0ffff, 0x1060001c,
- 0xafbf001c, 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018,
- 0x00101400, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c,
- 0x8f830018, 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000,
- 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024019,
- 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x27450100,
- 0xafbf0010, 0x94a3000c, 0x240200c1, 0x14620031, 0x00803021, 0x3c029000,
- 0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024,
- 0x1440fffd, 0x3c028000, 0x34420001, 0x3c049000, 0x34840001, 0x3c058000,
- 0x24030012, 0x00c21025, 0x00c42025, 0xa363003f, 0xaf420020, 0xaf440020,
- 0x8f420020, 0x00451024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000,
- 0x34420020, 0xa362007d, 0x8f640074, 0x34630001, 0x00c31825, 0xaf430020,
- 0x04810006, 0x3c038000, 0x00c02021, 0x0e000470, 0x24050906, 0x0a0012a1,
- 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000,
- 0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a0012a1, 0x8fbf0010, 0x00c02021,
- 0x94a5000c, 0x24060001, 0x0e000fb1, 0x2407090e, 0x8fbf0010, 0x03e00008,
- 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00808021,
- 0xafb20018, 0x00a09021, 0xafb10014, 0x30d100ff, 0x1060001c, 0xafbf001c,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001,
- 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000, 0x8c434448,
- 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024010, 0x00621825,
- 0xac83001c, 0x0e0014cc, 0x02202021, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
- 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010,
- 0x93620005, 0x30420001, 0x10400036, 0x00808021, 0x3c029000, 0x34420001,
- 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x93620023, 0x34420004, 0xa3620023, 0x93630005, 0x3c048000,
- 0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020, 0x34840001, 0x02042025,
- 0xaf440020, 0x10600020, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f820018,
- 0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00, 0x00431025,
- 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018,
- 0xac600010, 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448,
- 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c02400a, 0x00621825,
- 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf0014, 0x8fb00010, 0x03e00008,
- 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014, 0x00808821,
- 0xafb20018, 0x00a09021, 0xafb00010, 0x30d000ff, 0x1060002f, 0xafbf001c,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f830018, 0xac700004,
- 0x8f820018, 0xac520008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
- 0x9763006a, 0x00032880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081,
- 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001,
- 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021,
- 0x8f830018, 0x2402fffe, 0x00822824, 0x3c026000, 0xac650014, 0x8f840018,
- 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024011,
- 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014,
- 0xafb00010, 0x8f440100, 0x27500100, 0x8f650050, 0x0e0010fc, 0x9206001b,
- 0x3c020800, 0x8c430020, 0x1060001d, 0x8e100018, 0x0e00148e, 0x00000000,
- 0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f840018,
- 0x8f620050, 0xac820008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
- 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018, 0x8c434448, 0x24040001,
- 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401c, 0x00621825,
- 0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018,
- 0x8f430238, 0x3c020800, 0x04610013, 0x8c44009c, 0x2406fffe, 0x3c050800,
- 0x3c038000, 0x2484ffff, 0x14800009, 0x00000000, 0x97420078, 0x8ca3007c,
- 0x24420001, 0x00461024, 0x24630001, 0xa7620010, 0x03e00008, 0xaca3007c,
- 0x8f420238, 0x00431024, 0x1440fff3, 0x2484ffff, 0x8f420140, 0x3c031000,
- 0xaf420200, 0x03e00008, 0xaf430238, 0x27bdffe8, 0x3c029000, 0xafbf0010,
- 0x8f450140, 0x34420001, 0x3c038000, 0x00a21025, 0xaf420020, 0x8f420020,
- 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001,
- 0xa362007d, 0x8f640074, 0x34630001, 0x00a31825, 0xaf430020, 0x04810006,
- 0x3c038000, 0x00a02021, 0x0e000470, 0x24050ac7, 0x0a0013b9, 0x8fbf0010,
- 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0,
- 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x0000000d,
- 0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x24020001,
- 0x03e00008, 0xa7620010, 0x9362003f, 0x304400ff, 0x3883000e, 0x2c630001,
- 0x38820010, 0x2c420001, 0x00621825, 0x14600003, 0x24020012, 0x14820003,
- 0x00000000, 0x03e00008, 0x00001021, 0x9363007e, 0x9362007a, 0x14620006,
- 0x00000000, 0x9363007e, 0x24020001, 0x24630001, 0x03e00008, 0xa363007e,
- 0x9362007e, 0x8f630178, 0x304200ff, 0x14430006, 0x00000000, 0x9363000b,
- 0x24020001, 0x24630001, 0x03e00008, 0xa363000b, 0x03e00008, 0x00001021,
- 0x9362000b, 0x10400023, 0x00001021, 0xa360000b, 0x9362003f, 0x304400ff,
- 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, 0x00621825, 0x14600017,
- 0x00001821, 0x24020012, 0x10820014, 0x00000000, 0x9363007e, 0x9362007a,
- 0x14620007, 0x00000000, 0x9362007e, 0x24030001, 0x24420001, 0xa362007e,
- 0x03e00008, 0x00601021, 0x9362007e, 0x8f630178, 0x304200ff, 0x14430005,
- 0x00001821, 0x9362000b, 0x24030001, 0x24420001, 0xa362000b, 0x03e00008,
- 0x00601021, 0x03e00008, 0x00000000, 0x24040001, 0xaf64000c, 0x8f6300dc,
- 0x8f6200cc, 0x50620001, 0xa7640010, 0xa7640012, 0xa7640014, 0x03e00008,
- 0xa7640016, 0x3c020800, 0x8c430020, 0x27bdffe8, 0x1060001b, 0xafbf0010,
- 0x0e00148e, 0x00000000, 0x8f820018, 0xac400000, 0x8f830018, 0xac600004,
- 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010,
- 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, 0x8c434448, 0x3c020800,
- 0xac830018, 0x944358ce, 0x8f840018, 0x3c024020, 0x00621825, 0xac83001c,
- 0x0e0014cc, 0x24040001, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800,
- 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00a08021, 0xafb10014, 0x00c08821,
- 0xafb20018, 0x00e09021, 0x1060001e, 0xafbf001c, 0x0e00148e, 0x00000000,
- 0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f820018,
- 0xac510008, 0x8f830018, 0xac72000c, 0x8f840018, 0x8fa20030, 0xac820010,
- 0x8f830018, 0x8fa20034, 0xac620014, 0x8f840018, 0x3c026000, 0x8c434448,
- 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c0240c9, 0x00621825,
- 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
- 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, 0x8c430020, 0x27bdffe8,
- 0xafb00010, 0x27500100, 0x1060001d, 0xafbf0014, 0x0e00148e, 0x00000000,
- 0x8f830018, 0x8e020004, 0xac620000, 0x8f840018, 0x8e020018, 0xac820004,
- 0x8f850018, 0x8e020000, 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018,
- 0xac400010, 0x8f830018, 0xac600014, 0x8f820018, 0xac400018, 0x96030008,
- 0x3c020800, 0x944458ce, 0x8f850018, 0x00031c00, 0x00641825, 0x24040001,
- 0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018,
- 0x3c060800, 0x24c558c0, 0x3c02000a, 0x03421821, 0x94640006, 0x94a2000a,
- 0x00441023, 0x00021400, 0x00021c03, 0x04610006, 0xa4a40006, 0x0000000d,
- 0x00000000, 0x2400005a, 0x0a0014a3, 0x24020001, 0x8f820014, 0x0062102b,
- 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1040001c, 0x274a0400,
- 0x3c07000a, 0x3c020800, 0x244558c0, 0x94a9000a, 0x8f880014, 0x03471021,
- 0x94430006, 0x00402021, 0xa4a30006, 0x94820006, 0xa4a20006, 0x01221023,
- 0x00021400, 0x00021403, 0x04410006, 0x0048102b, 0x0000000d, 0x00000000,
- 0x2400005a, 0x0a0014be, 0x24020001, 0x14400002, 0x00001021, 0x24020001,
- 0x304200ff, 0x1440ffec, 0x03471021, 0x24c458c0, 0x8c820010, 0xaf420038,
- 0x8c830014, 0x3c020005, 0xaf43003c, 0xaf420030, 0xaf800010, 0xaf8a0018,
- 0x03e00008, 0x00000000, 0x27bdffe0, 0x8f820010, 0x8f850018, 0x3c070800,
- 0x24e858c0, 0xafbf001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x9503000a,
- 0x8d060014, 0x00009021, 0x309000ff, 0x00e08821, 0x24420001, 0x24a50020,
- 0x24630001, 0xaf820010, 0xaf850018, 0xa503000a, 0x24c30020, 0x3c028000,
- 0x04c10007, 0xad030014, 0x00621024, 0x14400005, 0x262258c0, 0x8d020010,
- 0x24420001, 0xad020010, 0x262258c0, 0x9444000a, 0x94450018, 0x0010102b,
- 0x00a41826, 0x2c630001, 0x00621825, 0x1060001c, 0x3c030006, 0x8f820010,
- 0x24120001, 0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000,
- 0x00000000, 0x27450400, 0x8f420000, 0x30420010, 0x1040fffd, 0x262258c0,
- 0x9444000a, 0x94430018, 0xaf800010, 0xaf850018, 0x14830012, 0x262758c0,
- 0x0e00155a, 0x00000000, 0x1600000e, 0x262758c0, 0x0e00148e, 0x00000000,
- 0x0a001517, 0x262758c0, 0x00041c00, 0x00031c03, 0x00051400, 0x00021403,
- 0x00621823, 0x18600002, 0x3c026000, 0xac400808, 0x262758c0, 0x94e2000e,
- 0x94e3000c, 0x24420001, 0xa4e2000e, 0x3042ffff, 0x50430001, 0xa4e0000e,
- 0x12000005, 0x3c02000a, 0x94e2000a, 0xa74200a2, 0x0a001554, 0x02401021,
- 0x03421821, 0x94640006, 0x94e2000a, 0x00441023, 0x00021400, 0x00021c03,
- 0x04610006, 0xa4e40006, 0x0000000d, 0x00000000, 0x2400005a, 0x0a001536,
- 0x24020001, 0x8f820014, 0x0062102b, 0x14400002, 0x00001021, 0x24020001,
- 0x304200ff, 0x1040001b, 0x3c020800, 0x3c06000a, 0x244558c0, 0x94a8000a,
- 0x8f870014, 0x03461021, 0x94430006, 0x00402021, 0xa4a30006, 0x94820006,
- 0xa4a20006, 0x01021023, 0x00021400, 0x00021403, 0x04410006, 0x0047102b,
- 0x0000000d, 0x00000000, 0x2400005a, 0x0a001550, 0x24020001, 0x14400002,
- 0x00001021, 0x24020001, 0x304200ff, 0x1440ffec, 0x03461021, 0x02401021,
- 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
- 0x3c020800, 0x244558c0, 0x94a3001a, 0x8ca40024, 0x00403021, 0x000318c0,
- 0x00832021, 0xaf44003c, 0x8ca20020, 0xaf420038, 0x3c020050, 0x34420008,
- 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x8f420000, 0x30420020,
- 0x1040fffd, 0x00000000, 0x8f430400, 0x24c658c0, 0xacc30010, 0x8f420404,
- 0x3c030020, 0xacc20014, 0xaf430030, 0x94c40018, 0x94c3001c, 0x94c2001a,
- 0x94c5001e, 0x00832021, 0x24420001, 0xa4c2001a, 0x3042ffff, 0x14450002,
- 0xa4c40018, 0xa4c0001a, 0x03e00008, 0x00000000, 0x8f820010, 0x3c030006,
- 0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000, 0x00000000,
- 0x27430400, 0x8f420000, 0x30420010, 0x1040fffd, 0x00000000, 0xaf800010,
- 0xaf830018, 0x03e00008, 0x00000000, 0x27bdffe8, 0xafb00010, 0x3c100800,
- 0x261058c0, 0x3c05000a, 0x02002021, 0x03452821, 0xafbf0014, 0x0e0015b0,
- 0x2406000a, 0x96020002, 0x9603001e, 0x3042000f, 0x24420003, 0x00431804,
- 0x24027fff, 0x0043102b, 0xaf830014, 0x10400004, 0x00000000, 0x0000000d,
- 0x00000000, 0x24000043, 0x0e00155a, 0x00000000, 0x8fbf0014, 0x8fb00010,
- 0x03e00008, 0x27bd0018, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff,
- 0x24a50004, 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000,
- 0x0a0015c1, 0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004,
- 0x00a01021, 0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c036000,
- 0x8c642b7c, 0x3c036010, 0x8c6553fc, 0x00041582, 0x00042302, 0x308403ff,
- 0x00052d82, 0x00441026, 0x0002102b, 0x0005282b, 0x00451025, 0x1440000d,
- 0x3c020050, 0x34420004, 0xaf400038, 0xaf40003c, 0xaf420030, 0x00000000,
- 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, 0x3c020020, 0xaf420030,
- 0x0000000d, 0x03e00008, 0x00000000, 0x3c020050, 0x34420004, 0xaf440038,
- 0xaf45003c, 0xaf420030, 0x00000000, 0x00000000, 0x8f420000, 0x30420020,
- 0x1040fffd, 0x3c020020, 0xaf420030, 0x03e00008, 0x00000000, 0x00000000};
+static u8 bnx2_COM_b06FwText[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x09, 0x83, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5b, 0x7d, 0x6c,
+ 0x5b, 0xd7, 0x75, 0x3f, 0xef, 0xf1, 0x51, 0x7a, 0x96, 0x68, 0xf9, 0x99,
+ 0x7e, 0x96, 0x59, 0x4f, 0xb1, 0x49, 0xf1, 0xc9, 0xd2, 0x62, 0x2d, 0x63,
+ 0x34, 0x35, 0xd1, 0x3a, 0x26, 0x66, 0x48, 0xda, 0x71, 0x36, 0x67, 0xa0,
+ 0x1d, 0x05, 0x51, 0x51, 0xaf, 0xd0, 0x48, 0xd9, 0xcd, 0xb2, 0x0c, 0x73,
+ 0x96, 0xb4, 0x70, 0xbc, 0xb4, 0xa1, 0x25, 0x79, 0xf5, 0x06, 0x45, 0xcf,
+ 0xb3, 0x34, 0x39, 0xc0, 0x82, 0x41, 0x10, 0x9d, 0x3a, 0x7f, 0x30, 0xa5,
+ 0xed, 0x7c, 0x19, 0xe8, 0x12, 0x29, 0xb2, 0x93, 0xb5, 0x43, 0xd0, 0xa6,
+ 0x68, 0xff, 0xe8, 0x8a, 0x6e, 0x30, 0x52, 0x0c, 0xf3, 0x3a, 0xa0, 0x30,
+ 0xfa, 0xc7, 0xe6, 0x2d, 0x1f, 0xdc, 0xef, 0xdc, 0x77, 0x1f, 0xf9, 0x48,
+ 0x51, 0x96, 0x1c, 0x34, 0x5d, 0xb7, 0x99, 0x80, 0xf0, 0xde, 0xbd, 0xf7,
+ 0xbc, 0x7b, 0xcf, 0x3d, 0xdf, 0xe7, 0xdc, 0xab, 0x5f, 0x53, 0xa9, 0x85,
+ 0xe4, 0x6f, 0x2d, 0xfe, 0xc2, 0x7f, 0xf4, 0xc7, 0xb9, 0xdb, 0x3e, 0x7d,
+ 0x5b, 0x1f, 0x5e, 0x07, 0x54, 0xdd, 0xaf, 0x72, 0xbf, 0x0f, 0x7f, 0x26,
+ 0xfe, 0xfa, 0xe4, 0x7b, 0xa3, 0x9f, 0x81, 0xbf, 0x2b, 0x18, 0x1c, 0xfe,
+ 0x09, 0x91, 0xb2, 0x0c, 0x8c, 0xf7, 0x57, 0x2e, 0x5f, 0x7f, 0x9c, 0x17,
+ 0x0e, 0xaf, 0x62, 0x9e, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf,
+ 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0xff, 0x3f, 0x3f, 0x9f, 0x13, 0x72,
+ 0x88, 0x98, 0x85, 0xff, 0x48, 0x57, 0xe3, 0x89, 0xa1, 0xa4, 0x45, 0xba,
+ 0x2f, 0x7e, 0x65, 0x28, 0x67, 0x11, 0x25, 0x8a, 0xdb, 0xc3, 0x29, 0xfa,
+ 0xb0, 0x9c, 0x37, 0x35, 0xe2, 0xfe, 0x5b, 0xe2, 0x1f, 0x3c, 0xfd, 0xfa,
+ 0x9d, 0x91, 0xab, 0xb3, 0x3e, 0xd2, 0x8d, 0xf8, 0xcb, 0xba, 0xb1, 0x8d,
+ 0xf4, 0x0e, 0x7c, 0xf3, 0x5c, 0xf7, 0x7f, 0xa8, 0xd4, 0xe6, 0xce, 0x75,
+ 0xa5, 0xfc, 0x7a, 0x37, 0xe5, 0x37, 0xc7, 0x75, 0x52, 0xe3, 0x5d, 0x3f,
+ 0x48, 0xfa, 0x8c, 0x61, 0x5f, 0xdc, 0xa0, 0xf9, 0x12, 0x65, 0x0e, 0x4c,
+ 0xf0, 0x1a, 0xb1, 0x75, 0xf7, 0x62, 0x2e, 0x2d, 0x3e, 0x3c, 0xf4, 0x67,
+ 0xd6, 0xd3, 0x65, 0xd5, 0xb2, 0x7a, 0xe6, 0x28, 0x30, 0xf0, 0x7c, 0x3f,
+ 0xc6, 0x8b, 0x91, 0x1e, 0xa2, 0x3b, 0x49, 0xb5, 0xf2, 0x01, 0x9f, 0xa5,
+ 0x53, 0xb2, 0x64, 0x51, 0xaa, 0x44, 0xf4, 0x77, 0x45, 0x85, 0x9e, 0xb7,
+ 0xda, 0x69, 0xae, 0xf7, 0x83, 0x72, 0x02, 0xb8, 0xbc, 0x6d, 0x0d, 0x0f,
+ 0x8d, 0x5b, 0x3c, 0x57, 0x7c, 0x9d, 0x83, 0x6f, 0x6f, 0x5b, 0xce, 0xd2,
+ 0x68, 0xb4, 0xc8, 0x7d, 0xbd, 0x2d, 0xdc, 0xe7, 0x8f, 0x3f, 0x1c, 0x7c,
+ 0xde, 0x0a, 0xc8, 0xbe, 0x1f, 0xa5, 0x92, 0x98, 0x6f, 0xac, 0xc8, 0xb0,
+ 0xcf, 0xde, 0x91, 0xb3, 0x4c, 0xd9, 0x6f, 0xc5, 0x93, 0x56, 0x08, 0xfd,
+ 0x1d, 0x72, 0x2c, 0xbd, 0x2e, 0x67, 0x59, 0x72, 0xac, 0x88, 0x6f, 0x7a,
+ 0x65, 0xff, 0x3b, 0xa9, 0x9c, 0x15, 0x93, 0xfd, 0x57, 0x93, 0x49, 0xab,
+ 0x5f, 0xf6, 0x1f, 0xbe, 0x2b, 0x67, 0xc5, 0x65, 0xff, 0xf7, 0x81, 0x8b,
+ 0x41, 0xc7, 0x8a, 0x61, 0xfc, 0x25, 0x30, 0xfe, 0x9a, 0x41, 0x6d, 0x19,
+ 0x8c, 0x61, 0xef, 0xb6, 0x4e, 0x97, 0x7d, 0x21, 0x7a, 0xbd, 0xfb, 0x32,
+ 0x68, 0x63, 0xd0, 0xd9, 0x12, 0x29, 0x99, 0xee, 0x10, 0x68, 0x62, 0xd2,
+ 0xb9, 0x52, 0x2b, 0xf9, 0x4e, 0xfa, 0xb0, 0xe7, 0xcf, 0x51, 0xd6, 0xd4,
+ 0x69, 0xfd, 0x8c, 0x42, 0x9d, 0x7d, 0x6b, 0x28, 0x61, 0xe4, 0x29, 0xd5,
+ 0x8d, 0x28, 0x6e, 0xd2, 0x24, 0x6d, 0x66, 0x71, 0xbd, 0x8a, 0x1e, 0x95,
+ 0x22, 0xa1, 0x2c, 0x28, 0x3c, 0x72, 0xfa, 0x5d, 0x8e, 0x39, 0xb1, 0x26,
+ 0xff, 0x85, 0x29, 0x35, 0x71, 0x2b, 0x0d, 0x1b, 0x8c, 0x0f, 0x80, 0x05,
+ 0x1f, 0x74, 0x25, 0x79, 0x2a, 0x44, 0xc7, 0xec, 0x80, 0x92, 0x3a, 0x75,
+ 0x37, 0x25, 0x63, 0x64, 0xaa, 0xd4, 0x25, 0xbe, 0x2d, 0x14, 0x43, 0x34,
+ 0x6e, 0x93, 0x92, 0xb4, 0x99, 0x5e, 0xed, 0x18, 0x6f, 0x13, 0xb0, 0xe8,
+ 0xeb, 0xf0, 0x51, 0x97, 0x91, 0x22, 0x9d, 0x71, 0x46, 0x7f, 0x50, 0x49,
+ 0x8b, 0x39, 0x44, 0x7f, 0x78, 0x8c, 0x02, 0x74, 0xba, 0x68, 0x4a, 0xd8,
+ 0x72, 0x39, 0x19, 0x33, 0x00, 0x07, 0xda, 0xd9, 0x26, 0x0d, 0xe3, 0x39,
+ 0x6a, 0xf3, 0xfa, 0x21, 0xc8, 0xcc, 0xb7, 0x87, 0xb2, 0xd3, 0x62, 0xbe,
+ 0xb0, 0x2f, 0xce, 0xf3, 0x75, 0x00, 0xee, 0x1d, 0xe0, 0xa5, 0x90, 0x26,
+ 0x78, 0x95, 0xa0, 0xec, 0x84, 0x02, 0x79, 0xc2, 0x53, 0xd0, 0x2d, 0x0d,
+ 0xfc, 0x35, 0xb2, 0xfa, 0x14, 0xca, 0x59, 0x9b, 0x28, 0x6f, 0xa0, 0x5d,
+ 0xbc, 0xa0, 0x26, 0xed, 0x66, 0x4a, 0x69, 0x61, 0xec, 0x5f, 0xc8, 0x0a,
+ 0x8d, 0xe1, 0x1b, 0xd5, 0x62, 0x98, 0x9f, 0x61, 0xef, 0xc3, 0x82, 0xfe,
+ 0x4d, 0xf1, 0xfd, 0x74, 0x69, 0x22, 0xaf, 0x26, 0x4b, 0xed, 0xe4, 0x9b,
+ 0x89, 0x40, 0x9a, 0xc7, 0xd5, 0xd4, 0x19, 0x8d, 0xfc, 0x93, 0x0a, 0x41,
+ 0x3e, 0x0c, 0x5f, 0xfc, 0xb8, 0xba, 0xb3, 0x74, 0x41, 0x4d, 0x95, 0xf8,
+ 0x1b, 0xc0, 0x16, 0x55, 0xd0, 0x96, 0xdf, 0xb7, 0x83, 0x96, 0x34, 0xac,
+ 0xc6, 0x75, 0x3d, 0x51, 0x64, 0x99, 0xe5, 0x6f, 0xc1, 0x0f, 0xec, 0xe5,
+ 0x9c, 0x0d, 0xfe, 0x08, 0x7e, 0x85, 0xc1, 0xaf, 0x6f, 0x82, 0x5f, 0xfd,
+ 0xe0, 0x53, 0x8c, 0xde, 0x28, 0xf5, 0xd2, 0x6b, 0xa5, 0x1e, 0x7a, 0x15,
+ 0x32, 0xf9, 0x4a, 0x29, 0x4c, 0x2f, 0x97, 0x3a, 0xe8, 0xa5, 0x52, 0x88,
+ 0xce, 0x0b, 0x1e, 0xa6, 0x21, 0xff, 0x82, 0xaf, 0xfa, 0x26, 0xf0, 0xa4,
+ 0x1d, 0x3c, 0x59, 0x0f, 0x79, 0xd9, 0x08, 0xf9, 0x9b, 0xee, 0xd6, 0x69,
+ 0xaa, 0x9b, 0x12, 0x41, 0xf4, 0x6f, 0x89, 0x6b, 0x82, 0x4e, 0x1a, 0xc6,
+ 0xc7, 0x26, 0xfc, 0x94, 0x32, 0x4e, 0xd3, 0x7b, 0x93, 0x1a, 0x8d, 0x95,
+ 0xa6, 0x36, 0x3a, 0x7c, 0xe3, 0xf6, 0x2c, 0x5d, 0x44, 0x5f, 0xca, 0x98,
+ 0xa5, 0x4b, 0xdb, 0x54, 0x1a, 0x9d, 0xfe, 0x1b, 0x4a, 0x9e, 0x39, 0x4d,
+ 0x3f, 0xfe, 0x3a, 0x51, 0x06, 0x34, 0x51, 0xfb, 0x7e, 0x5a, 0x4e, 0x18,
+ 0xa0, 0x45, 0x5f, 0xaf, 0x90, 0x08, 0xb5, 0x8f, 0x79, 0x19, 0x86, 0xae,
+ 0x68, 0x4a, 0xca, 0x7e, 0x01, 0xfa, 0xd2, 0xaa, 0x24, 0xa7, 0x88, 0x72,
+ 0x53, 0x65, 0xca, 0xc5, 0xfc, 0xf4, 0x98, 0x51, 0xa6, 0x74, 0xac, 0x89,
+ 0xbe, 0x68, 0xb4, 0xd3, 0x68, 0xef, 0x6f, 0xf8, 0xdc, 0x5c, 0x65, 0xba,
+ 0xd4, 0x8f, 0x77, 0xee, 0x23, 0x9a, 0x12, 0xef, 0x4e, 0x7f, 0xbe, 0xe4,
+ 0xa7, 0x84, 0x99, 0x0f, 0x69, 0xf4, 0x8e, 0xcf, 0xc1, 0x29, 0xe1, 0x8e,
+ 0x81, 0x57, 0xc3, 0xb0, 0x0f, 0x8e, 0x0c, 0x66, 0x27, 0xd6, 0x5c, 0x4b,
+ 0x88, 0x6e, 0xc0, 0x0b, 0xd9, 0xd3, 0x18, 0x8f, 0x61, 0x25, 0x6e, 0x52,
+ 0xa7, 0xd0, 0x8d, 0x7e, 0xc0, 0x0c, 0x28, 0xfb, 0x4a, 0xcc, 0x6b, 0xbc,
+ 0x17, 0x19, 0xd7, 0xcd, 0x80, 0xd5, 0xf0, 0x4c, 0x48, 0x9c, 0xbd, 0x78,
+ 0xf2, 0x5c, 0x8c, 0x27, 0x3f, 0x7f, 0xcf, 0x83, 0xe7, 0xe7, 0x2b, 0xef,
+ 0x53, 0x9e, 0xf7, 0x7c, 0xe9, 0x4f, 0x03, 0x0e, 0x7e, 0x4c, 0xcf, 0x01,
+ 0x1a, 0x9d, 0x38, 0x2c, 0xd7, 0xc2, 0x7b, 0x91, 0xd7, 0x38, 0x0d, 0x3a,
+ 0x09, 0xc8, 0x15, 0xd6, 0x3a, 0xec, 0x59, 0xeb, 0x49, 0xcf, 0x5a, 0x4f,
+ 0x7a, 0xd6, 0xca, 0x83, 0xb6, 0xb4, 0x4e, 0xb5, 0xfc, 0xd0, 0x51, 0xee,
+ 0x39, 0x8e, 0x39, 0x9f, 0x03, 0x5f, 0xbe, 0x0a, 0x98, 0x38, 0x2d, 0xda,
+ 0xa0, 0xc7, 0x94, 0x46, 0x7b, 0x4d, 0x7e, 0x7f, 0xb1, 0xd5, 0xc1, 0x8b,
+ 0xdf, 0x2f, 0x48, 0x9c, 0x5a, 0x1d, 0xb8, 0xd2, 0x15, 0xa1, 0xff, 0xf3,
+ 0x25, 0xd6, 0x4f, 0x8a, 0xf9, 0x2c, 0x3a, 0x94, 0x8e, 0xb5, 0xd3, 0x98,
+ 0xa1, 0xc4, 0x46, 0x7b, 0x9a, 0x99, 0x8e, 0x09, 0xd5, 0x6a, 0x85, 0x0e,
+ 0x50, 0x58, 0x65, 0xdb, 0x25, 0xf0, 0x7b, 0x49, 0xe2, 0x61, 0x70, 0x3b,
+ 0xa3, 0x5a, 0xc1, 0xba, 0x7e, 0x96, 0xdf, 0x57, 0xf0, 0xce, 0x32, 0x9c,
+ 0xd4, 0x9c, 0xb5, 0x5f, 0x45, 0x9b, 0xed, 0xce, 0x66, 0xd9, 0x76, 0xc7,
+ 0xff, 0xa0, 0xa9, 0xb6, 0xfd, 0x05, 0xb3, 0xb6, 0xed, 0xea, 0x82, 0xd7,
+ 0x66, 0xf1, 0xde, 0xc2, 0xe4, 0xb3, 0x58, 0x8e, 0xfc, 0xc0, 0x35, 0x06,
+ 0x3d, 0x6c, 0x96, 0x38, 0x7c, 0x4b, 0xe2, 0x00, 0x5c, 0x01, 0x37, 0x5a,
+ 0xe2, 0x6f, 0x04, 0x4b, 0xea, 0xda, 0x4c, 0x43, 0xf7, 0x7d, 0xad, 0x18,
+ 0xbf, 0xec, 0xe3, 0x75, 0xdc, 0x27, 0x29, 0x69, 0xe8, 0xc9, 0xd8, 0xb4,
+ 0x46, 0xd9, 0xd8, 0x26, 0x21, 0xd7, 0xd9, 0x58, 0xd5, 0x06, 0x8c, 0x4e,
+ 0xd4, 0xdb, 0x00, 0xfe, 0x8e, 0x6d, 0x80, 0xa3, 0xfb, 0x63, 0xd3, 0x6c,
+ 0x0b, 0x1c, 0xdd, 0x3f, 0x36, 0xc1, 0x36, 0x41, 0xcc, 0x09, 0xfd, 0x67,
+ 0x3b, 0xe0, 0xda, 0x00, 0xfe, 0x86, 0x6d, 0x80, 0x0f, 0xf2, 0xcd, 0xf3,
+ 0xb9, 0x6b, 0x8f, 0xd7, 0xcd, 0x3b, 0xce, 0xb6, 0x45, 0xd9, 0xd9, 0xcd,
+ 0x30, 0xc7, 0xb1, 0x76, 0x80, 0x0a, 0xd3, 0xcc, 0xc3, 0x48, 0xe8, 0x08,
+ 0x1d, 0x17, 0x36, 0xef, 0xf4, 0x04, 0x25, 0x0e, 0x9e, 0x18, 0xa0, 0x34,
+ 0x6c, 0xc0, 0xdc, 0xc4, 0xb5, 0x32, 0xf8, 0x78, 0x47, 0x13, 0x59, 0xb0,
+ 0x75, 0xf0, 0x93, 0xfd, 0x7e, 0xf2, 0xc5, 0xe3, 0x90, 0xb7, 0x98, 0xf0,
+ 0x5d, 0xd5, 0x9f, 0xa6, 0xed, 0xaa, 0x69, 0x37, 0xc1, 0x3f, 0x62, 0xde,
+ 0xfe, 0x98, 0x90, 0x4d, 0xef, 0x2f, 0x09, 0x1b, 0x94, 0x8c, 0x7d, 0x08,
+ 0xf9, 0x75, 0x69, 0xe4, 0xea, 0x1f, 0xdb, 0xfa, 0x2b, 0x1e, 0x1f, 0xb2,
+ 0x05, 0x76, 0xdf, 0x84, 0x3c, 0xb9, 0x76, 0x9f, 0xed, 0x71, 0x88, 0x6d,
+ 0x26, 0xf4, 0x8d, 0x6d, 0x70, 0x80, 0xd4, 0x19, 0x4d, 0xda, 0x69, 0x5d,
+ 0xda, 0xe9, 0x00, 0x6c, 0x34, 0xb7, 0x0d, 0xd9, 0x36, 0x45, 0x1b, 0xf6,
+ 0x1a, 0xf6, 0x70, 0x77, 0x3a, 0x35, 0xc1, 0xfe, 0x10, 0xbe, 0x7b, 0x86,
+ 0x75, 0xf8, 0xdb, 0x43, 0x23, 0xd3, 0xc2, 0x07, 0xb0, 0xff, 0x80, 0x65,
+ 0x66, 0x1b, 0xce, 0xb6, 0x1c, 0xfb, 0x2e, 0x62, 0xdd, 0x8a, 0xad, 0x64,
+ 0x39, 0xf1, 0xe2, 0xc5, 0x38, 0xad, 0x21, 0xf5, 0xa4, 0x43, 0x6b, 0x35,
+ 0xfe, 0xa8, 0x46, 0x2d, 0x4c, 0x63, 0xc6, 0x7f, 0x2b, 0x70, 0xe6, 0x7d,
+ 0xfd, 0x4f, 0xe0, 0xcc, 0xeb, 0xd6, 0xe3, 0x4d, 0x7a, 0x6b, 0xfc, 0xac,
+ 0xfe, 0xf0, 0x33, 0xa4, 0x37, 0xc7, 0xcf, 0xd2, 0xbf, 0x58, 0x74, 0x9f,
+ 0x0e, 0x3f, 0xdb, 0xad, 0xc0, 0xcf, 0x16, 0xa1, 0xef, 0x53, 0x3a, 0x1d,
+ 0x3c, 0x15, 0xc9, 0xfc, 0x2b, 0x45, 0x61, 0x3f, 0x76, 0xd0, 0xc8, 0x94,
+ 0x42, 0x7a, 0x17, 0xb5, 0xc3, 0x7f, 0xf4, 0x37, 0x61, 0xfe, 0x5d, 0x44,
+ 0x9b, 0x1d, 0xbf, 0xd9, 0x15, 0x1e, 0x05, 0xff, 0xd3, 0x2f, 0x7e, 0x05,
+ 0xdf, 0x3c, 0x4d, 0x07, 0xa7, 0x0e, 0x2b, 0x39, 0xfb, 0x08, 0xe0, 0x97,
+ 0x83, 0xd5, 0x01, 0x9b, 0x07, 0xec, 0x97, 0x31, 0xef, 0xd3, 0xa4, 0xdf,
+ 0x1e, 0x19, 0x48, 0x28, 0xc0, 0xe3, 0x45, 0x01, 0x2f, 0x7d, 0x71, 0x97,
+ 0xb1, 0x53, 0xf0, 0x3f, 0x40, 0xef, 0x15, 0x2f, 0x80, 0xbe, 0xbd, 0xf0,
+ 0x39, 0x91, 0x67, 0x61, 0x93, 0xe1, 0x8f, 0x22, 0x57, 0x31, 0x2d, 0x7c,
+ 0x11, 0x29, 0x0f, 0x76, 0xa7, 0x41, 0xef, 0x38, 0xfc, 0xd3, 0x00, 0xfc,
+ 0x53, 0x0c, 0xbe, 0xa9, 0x07, 0x7e, 0xc9, 0x82, 0x5f, 0x0a, 0x83, 0x1f,
+ 0x06, 0xcd, 0xc2, 0x47, 0xcd, 0x42, 0xfe, 0xe7, 0x66, 0x48, 0x19, 0x04,
+ 0xad, 0xcf, 0xc1, 0x3f, 0x26, 0x63, 0x77, 0x42, 0xcf, 0x22, 0x17, 0x66,
+ 0xd5, 0x41, 0xca, 0xc1, 0x9f, 0x77, 0x6e, 0x8b, 0x62, 0xbd, 0x26, 0x4a,
+ 0x84, 0x5c, 0x1d, 0xe5, 0xdf, 0x7e, 0x85, 0xac, 0x7f, 0x06, 0xef, 0x22,
+ 0x61, 0xa2, 0x3d, 0x94, 0xb5, 0xa3, 0x46, 0xa7, 0xda, 0x03, 0x18, 0x6e,
+ 0x87, 0x95, 0x03, 0x53, 0x11, 0x05, 0xfb, 0x03, 0xcd, 0x27, 0x60, 0xeb,
+ 0xcb, 0x34, 0x1e, 0x63, 0x3d, 0x29, 0xd3, 0xf3, 0xb1, 0xc8, 0x40, 0x9e,
+ 0x5a, 0xe9, 0x98, 0x39, 0x21, 0x7c, 0xbc, 0x16, 0x3f, 0x21, 0x74, 0x2c,
+ 0x67, 0xe1, 0x59, 0xec, 0x54, 0xb2, 0x53, 0xbc, 0x7e, 0x14, 0x5a, 0xee,
+ 0xc7, 0x93, 0xe7, 0x07, 0xdd, 0xfa, 0x49, 0x39, 0xd8, 0x9d, 0x87, 0x77,
+ 0x88, 0x18, 0x8b, 0x58, 0x39, 0x35, 0x11, 0x0d, 0x45, 0x55, 0x8d, 0x86,
+ 0x35, 0x85, 0x46, 0x61, 0x6f, 0xd2, 0xb1, 0xff, 0x2c, 0x1f, 0x33, 0x79,
+ 0xbc, 0x99, 0xbe, 0x2a, 0xfc, 0x0d, 0xd6, 0x2e, 0x4c, 0x63, 0x5d, 0x3f,
+ 0xf8, 0xcb, 0xeb, 0xf2, 0x3c, 0x68, 0xc3, 0xf6, 0x6b, 0x56, 0xe4, 0xd9,
+ 0x3c, 0xed, 0x00, 0x6d, 0xd9, 0x66, 0xc1, 0x3e, 0x0c, 0x60, 0xed, 0x5e,
+ 0xd8, 0x4f, 0x3c, 0x93, 0xbd, 0x1c, 0x07, 0x05, 0x68, 0xd8, 0x64, 0x79,
+ 0xd4, 0xe5, 0x98, 0xe9, 0x19, 0xf3, 0xcb, 0xb1, 0x20, 0xfe, 0xe0, 0x7f,
+ 0x4d, 0x96, 0x19, 0x6e, 0x73, 0x4c, 0xc6, 0x34, 0x09, 0xd3, 0xdc, 0x64,
+ 0x02, 0x34, 0x8b, 0x9c, 0x4d, 0x10, 0xd3, 0x0c, 0x46, 0x7b, 0x7f, 0x82,
+ 0xbe, 0x64, 0xaf, 0xf7, 0x3b, 0xb6, 0xb0, 0x55, 0x49, 0xc1, 0x17, 0xa8,
+ 0x56, 0x0b, 0x7c, 0x45, 0x98, 0x5e, 0x15, 0xb0, 0x64, 0xa8, 0xf1, 0x68,
+ 0xe8, 0x4b, 0x74, 0xab, 0xb0, 0x11, 0x09, 0xc3, 0x4b, 0xe3, 0xff, 0x52,
+ 0xc9, 0x72, 0xbf, 0x69, 0xa5, 0xec, 0x20, 0xf3, 0x89, 0xd7, 0x33, 0x68,
+ 0xae, 0xe4, 0xbc, 0xfb, 0x10, 0xa3, 0x16, 0x60, 0x6b, 0xce, 0x4f, 0xaa,
+ 0xf4, 0xf8, 0x1d, 0xf0, 0x65, 0xb1, 0x6d, 0x58, 0xcb, 0xc4, 0x78, 0x1e,
+ 0x6d, 0x15, 0x6d, 0xe8, 0x99, 0x11, 0x02, 0x8f, 0xb9, 0x9f, 0xe1, 0x4c,
+ 0xfc, 0xbd, 0xcf, 0xb1, 0x75, 0x3e, 0xab, 0xde, 0x4a, 0x14, 0x64, 0x7a,
+ 0xc5, 0x40, 0x2b, 0xcb, 0x50, 0xd5, 0x6d, 0xc2, 0x5f, 0x3b, 0xb6, 0xc4,
+ 0x82, 0x2e, 0xc2, 0xe6, 0xf6, 0x79, 0x75, 0x91, 0xe3, 0x09, 0x57, 0x17,
+ 0x23, 0xa1, 0x84, 0x0a, 0x5b, 0xdc, 0xa7, 0xd1, 0x09, 0xd1, 0x56, 0x28,
+ 0x31, 0x18, 0x09, 0x2d, 0xa8, 0x1c, 0x4b, 0x33, 0x6c, 0x18, 0xf1, 0x4a,
+ 0x40, 0xc2, 0x22, 0x9e, 0xb3, 0xdd, 0x98, 0x30, 0x84, 0x7e, 0x53, 0xf4,
+ 0x1f, 0xab, 0xe8, 0xa8, 0x13, 0xff, 0xa9, 0x88, 0x11, 0x0b, 0x88, 0x11,
+ 0x53, 0x42, 0x47, 0x8d, 0x04, 0x72, 0x04, 0xd0, 0xdc, 0xd1, 0xcf, 0x42,
+ 0x91, 0x71, 0xc9, 0xb1, 0x5c, 0x0e, 0x00, 0x99, 0x13, 0x8e, 0x7d, 0xa4,
+ 0x3c, 0xc7, 0x91, 0xa3, 0xea, 0x53, 0x34, 0x5c, 0x60, 0x3f, 0x8e, 0x3f,
+ 0x9b, 0x6d, 0x2d, 0xec, 0xa3, 0xf0, 0xc5, 0x51, 0xf0, 0x39, 0x0f, 0x1a,
+ 0xac, 0x97, 0x74, 0xdd, 0x4f, 0x07, 0xec, 0x3d, 0xa0, 0x79, 0x9c, 0x46,
+ 0x4e, 0x8d, 0xb0, 0xcc, 0xf6, 0x14, 0x28, 0xd2, 0x73, 0x8c, 0xb6, 0x1b,
+ 0x73, 0x2c, 0xdf, 0x83, 0xe5, 0x1d, 0xe0, 0x85, 0xd0, 0x51, 0xc8, 0x20,
+ 0x65, 0x0b, 0x23, 0xf4, 0x58, 0x89, 0xfb, 0xf2, 0xa0, 0x1d, 0xe2, 0xda,
+ 0xfe, 0xfd, 0x52, 0xce, 0x31, 0x9f, 0xe6, 0xce, 0x37, 0x22, 0xe7, 0x63,
+ 0x38, 0x86, 0xe1, 0x6f, 0xaa, 0xf3, 0xee, 0x14, 0x3c, 0x8d, 0x18, 0x5d,
+ 0x6a, 0x79, 0x87, 0x1f, 0xe3, 0xcf, 0xf7, 0xf3, 0x3b, 0xe6, 0x81, 0xef,
+ 0x6f, 0xb6, 0xf6, 0x00, 0x76, 0x10, 0x73, 0xfa, 0xa9, 0xb3, 0xdd, 0xc5,
+ 0x37, 0x81, 0xb5, 0xd9, 0xcf, 0x31, 0x9f, 0x1f, 0xa1, 0xec, 0xa9, 0x7c,
+ 0x8f, 0x0a, 0x19, 0x9b, 0xcd, 0x28, 0xe4, 0xb7, 0x1e, 0xa6, 0xdc, 0xa9,
+ 0xa3, 0x6c, 0x37, 0x40, 0xab, 0x3d, 0xb4, 0x6b, 0x22, 0xd2, 0x73, 0x80,
+ 0x34, 0xb1, 0xce, 0x5b, 0x24, 0xe8, 0x1f, 0x9b, 0x15, 0xbe, 0x20, 0x43,
+ 0xe9, 0x89, 0xed, 0xa1, 0x4b, 0xe8, 0x1b, 0x1e, 0x8c, 0x84, 0x17, 0xe8,
+ 0x09, 0xd0, 0xe5, 0x23, 0xf8, 0x22, 0xab, 0x67, 0x0c, 0x3a, 0x84, 0x9c,
+ 0x0a, 0xeb, 0x8f, 0x4a, 0xda, 0xe0, 0xbb, 0xcc, 0x51, 0xd0, 0x8f, 0xf2,
+ 0x0e, 0x4d, 0x99, 0x9e, 0x4c, 0xcb, 0xaf, 0xc0, 0xf6, 0x1c, 0x11, 0xb1,
+ 0x4b, 0x56, 0xd0, 0xee, 0xd2, 0x06, 0x47, 0x0e, 0x60, 0x8b, 0x30, 0xef,
+ 0xe5, 0x41, 0x85, 0xb6, 0x20, 0x4e, 0x3f, 0x24, 0x78, 0xeb, 0xa3, 0x7d,
+ 0x66, 0xd4, 0xd8, 0x47, 0xf3, 0x7e, 0x27, 0x56, 0xc0, 0x3c, 0x3d, 0xf7,
+ 0x60, 0x0f, 0x90, 0x53, 0xfb, 0xeb, 0xeb, 0xa8, 0x2d, 0x12, 0x4e, 0xa8,
+ 0x09, 0xfa, 0x93, 0xd2, 0xdd, 0xe4, 0xe8, 0x77, 0x2b, 0xdb, 0x7e, 0xf0,
+ 0xb0, 0xd3, 0x69, 0x5b, 0x78, 0x16, 0x3a, 0xb1, 0x1e, 0xe3, 0xfe, 0xac,
+ 0xc0, 0x7d, 0x84, 0xba, 0xa1, 0x6b, 0x22, 0x8f, 0x39, 0x51, 0x8b, 0x17,
+ 0xf3, 0xbc, 0x9e, 0xcf, 0x5f, 0xc6, 0x3c, 0xdc, 0xcf, 0x70, 0x78, 0x2f,
+ 0x3c, 0x41, 0x23, 0x90, 0xc7, 0x5c, 0x7f, 0x57, 0x68, 0x0c, 0xdf, 0xa4,
+ 0x4a, 0x4d, 0x74, 0x54, 0xe3, 0xf1, 0x48, 0x38, 0xaf, 0x1e, 0x42, 0xdc,
+ 0xf3, 0xb8, 0xea, 0xb7, 0x7e, 0xe6, 0x67, 0xbf, 0xe3, 0xb7, 0xae, 0x29,
+ 0xd5, 0xb9, 0x10, 0x87, 0x8a, 0xdc, 0x60, 0x41, 0x19, 0x2c, 0x5d, 0x52,
+ 0x92, 0x85, 0x6b, 0x4a, 0xaa, 0xc4, 0x30, 0x8e, 0xce, 0x67, 0xcf, 0x74,
+ 0x82, 0x4e, 0x1f, 0x89, 0xef, 0xe6, 0x7a, 0x8f, 0x50, 0xea, 0xd4, 0xad,
+ 0x94, 0x9e, 0xe6, 0xbc, 0x34, 0x02, 0x7c, 0x3f, 0x2a, 0xe7, 0x62, 0x41,
+ 0xca, 0x9d, 0xe1, 0x31, 0xb6, 0x5f, 0xd6, 0xd5, 0x45, 0x1f, 0xef, 0x9f,
+ 0xf9, 0x6f, 0x52, 0xc1, 0x7e, 0x53, 0xd2, 0x8f, 0xdf, 0x7d, 0x9c, 0x93,
+ 0xe1, 0xf7, 0x6f, 0x86, 0xd3, 0xb7, 0x95, 0x16, 0x36, 0xdc, 0xc8, 0x3e,
+ 0x57, 0xb3, 0xc7, 0x47, 0x7d, 0x7e, 0x6b, 0x7b, 0x13, 0xb5, 0x84, 0x80,
+ 0xc3, 0x4a, 0x7b, 0x64, 0x98, 0x5f, 0x87, 0x1c, 0xb0, 0x4d, 0xd9, 0x0d,
+ 0x7e, 0x5a, 0x6c, 0xc3, 0x60, 0x93, 0x76, 0x53, 0xae, 0xc4, 0xb2, 0x1d,
+ 0x35, 0x32, 0x90, 0xb1, 0x34, 0x75, 0xb1, 0x1e, 0xb9, 0xba, 0x07, 0xdb,
+ 0x9d, 0x87, 0xed, 0x46, 0x3c, 0x64, 0x53, 0xbe, 0x29, 0xce, 0x36, 0xbc,
+ 0x0b, 0xb2, 0x85, 0xbe, 0x62, 0x55, 0x17, 0x77, 0x2d, 0xc1, 0x5d, 0x5b,
+ 0xc2, 0xa3, 0x02, 0xd5, 0xe2, 0x3f, 0x4b, 0x8c, 0xff, 0x5f, 0x00, 0xff,
+ 0xcf, 0x01, 0x7f, 0xc6, 0xa9, 0x31, 0xfe, 0x3b, 0x2b, 0xf8, 0x33, 0x0c,
+ 0xfc, 0x1c, 0x64, 0xf1, 0x0d, 0xe8, 0xe2, 0x6b, 0x36, 0x7c, 0x9d, 0x0d,
+ 0xff, 0x67, 0xc3, 0xdf, 0xd9, 0xf0, 0x8b, 0x36, 0x7c, 0x1e, 0xf6, 0x74,
+ 0x0e, 0x36, 0xe9, 0xac, 0x9d, 0x34, 0x58, 0x9f, 0x92, 0x31, 0xf6, 0x9d,
+ 0xbb, 0x65, 0xde, 0x1d, 0x92, 0x71, 0xf7, 0xa7, 0x64, 0x2c, 0x7b, 0x00,
+ 0xb1, 0xec, 0x66, 0x1a, 0xed, 0xe1, 0x9c, 0xa4, 0x05, 0xcf, 0x75, 0x78,
+ 0x22, 0x6e, 0xed, 0x49, 0x48, 0xbd, 0xfc, 0x0c, 0x62, 0x5c, 0xd8, 0xff,
+ 0x1e, 0xe4, 0x37, 0x19, 0xc4, 0x6a, 0x56, 0x1f, 0xc7, 0xe5, 0xb0, 0x65,
+ 0xef, 0x37, 0x39, 0x76, 0xfe, 0x2e, 0x19, 0x03, 0xbb, 0xed, 0x56, 0xc0,
+ 0xa4, 0xd1, 0xd7, 0x8a, 0x6f, 0x7e, 0x07, 0xb2, 0xdf, 0x86, 0xf6, 0xce,
+ 0x3a, 0x18, 0xe4, 0xb3, 0x56, 0x16, 0x7d, 0x11, 0xc0, 0xb4, 0x61, 0x9d,
+ 0x0e, 0xb4, 0xf7, 0xa0, 0x7d, 0x8b, 0xb3, 0x8e, 0xf1, 0x2b, 0x68, 0xa7,
+ 0xea, 0xbe, 0xd9, 0x8a, 0xbe, 0x4c, 0x5d, 0xdf, 0x9b, 0xe8, 0x4b, 0xa2,
+ 0x6f, 0x51, 0x7e, 0x97, 0x47, 0x3b, 0x52, 0x07, 0xb3, 0x88, 0x3e, 0xc6,
+ 0xf1, 0x5b, 0x78, 0xde, 0x47, 0xa3, 0x19, 0x8e, 0x03, 0xdc, 0xb1, 0xdc,
+ 0x7a, 0x6a, 0xe3, 0xdc, 0xf7, 0x43, 0x21, 0x3b, 0xf3, 0xd2, 0x46, 0xa7,
+ 0x27, 0xd8, 0x4f, 0x8c, 0x20, 0xee, 0xe1, 0x71, 0xe1, 0x9c, 0x3c, 0xfd,
+ 0x1f, 0x00, 0xf6, 0x61, 0x8c, 0x21, 0x56, 0xb7, 0xcb, 0x4d, 0x8d, 0xc7,
+ 0x1f, 0xc5, 0xf8, 0x5f, 0xca, 0x6f, 0x2b, 0x73, 0x03, 0xfe, 0x1b, 0x75,
+ 0x7d, 0x6a, 0xb0, 0xb6, 0xbd, 0xd6, 0xf3, 0xbe, 0x4d, 0x5f, 0xfa, 0xfd,
+ 0x48, 0x1d, 0xfc, 0xef, 0x6e, 0xa8, 0x6d, 0x3f, 0xc5, 0xdf, 0x20, 0x87,
+ 0x70, 0xdb, 0x09, 0xc8, 0x1d, 0xdb, 0xa4, 0xfa, 0x79, 0x3e, 0x6b, 0xd4,
+ 0xf6, 0x6d, 0x32, 0x6b, 0xdb, 0x1c, 0x27, 0x31, 0x5c, 0x08, 0xf2, 0xde,
+ 0xa1, 0xec, 0xb2, 0x7f, 0x13, 0xe3, 0x61, 0xe5, 0x5e, 0xdb, 0x8b, 0x67,
+ 0x48, 0xe6, 0x46, 0xe1, 0x4a, 0xcc, 0x3b, 0x5f, 0x0a, 0x40, 0xae, 0x3e,
+ 0x0f, 0x9e, 0x73, 0xdc, 0x53, 0xd5, 0xf1, 0xf7, 0x68, 0x39, 0x1d, 0x67,
+ 0x1f, 0xc0, 0x31, 0xfe, 0x36, 0x11, 0x1f, 0xfb, 0xe2, 0x4f, 0x70, 0x0c,
+ 0xf6, 0xb4, 0xe3, 0x5b, 0x2c, 0xf8, 0x43, 0xb4, 0x4b, 0x7e, 0xc7, 0x6e,
+ 0x22, 0x9f, 0xc8, 0x16, 0xd8, 0x9f, 0xb1, 0x0f, 0x89, 0xc0, 0x4e, 0xb3,
+ 0x1f, 0xfd, 0x24, 0x7d, 0xc6, 0x5d, 0xcd, 0x6c, 0xfb, 0x34, 0xeb, 0x05,
+ 0xc4, 0x0b, 0x1c, 0xe7, 0xb1, 0xed, 0xc6, 0x7b, 0xd1, 0x8d, 0x57, 0xee,
+ 0xd7, 0xc8, 0xaa, 0xfa, 0x11, 0x67, 0x8f, 0x5b, 0x59, 0x37, 0x56, 0xb1,
+ 0xef, 0xc6, 0xb6, 0xed, 0xc7, 0x75, 0xb6, 0xe1, 0xb2, 0xb0, 0x0d, 0x0f,
+ 0x6a, 0x7e, 0xeb, 0xf7, 0x9b, 0x1d, 0x79, 0x6d, 0x6c, 0x1b, 0xee, 0xad,
+ 0xd8, 0x06, 0x57, 0x5e, 0xbd, 0x79, 0xeb, 0x0f, 0xc0, 0x1b, 0x0b, 0xbc,
+ 0xa9, 0xaf, 0xd5, 0x70, 0x8e, 0xe2, 0x87, 0x1f, 0xe2, 0x18, 0x91, 0x73,
+ 0xd9, 0x18, 0xe5, 0x62, 0x45, 0xc4, 0x6a, 0x91, 0xd9, 0xd9, 0x4a, 0x8e,
+ 0xf5, 0x35, 0x69, 0xbb, 0x6b, 0xe2, 0x22, 0x7a, 0xbc, 0x78, 0x09, 0xf8,
+ 0x73, 0xbc, 0xa5, 0x49, 0x1b, 0xc1, 0xfd, 0xe3, 0x12, 0x47, 0x7e, 0xe7,
+ 0x3a, 0x1e, 0x7c, 0x69, 0xf1, 0x47, 0xe0, 0x15, 0xc7, 0x7d, 0x51, 0x27,
+ 0xde, 0xab, 0x89, 0xa9, 0xd7, 0xf8, 0xc9, 0xe2, 0x78, 0x89, 0x61, 0x74,
+ 0x19, 0x2f, 0x05, 0x64, 0x5e, 0x63, 0xc8, 0x3c, 0x87, 0x63, 0x6d, 0xae,
+ 0xb1, 0xd6, 0xc7, 0x50, 0x0b, 0x43, 0xc1, 0x6d, 0xcc, 0x13, 0x8e, 0xa1,
+ 0xda, 0x28, 0x39, 0xe3, 0xc4, 0x50, 0x4e, 0x9d, 0xcd, 0xcd, 0x71, 0x5c,
+ 0x5c, 0xd9, 0x0f, 0xef, 0xc0, 0x3e, 0x45, 0x9e, 0x14, 0x74, 0xea, 0x7f,
+ 0x1a, 0xec, 0xf6, 0x51, 0xf4, 0x8f, 0xba, 0xfd, 0x9e, 0x5c, 0xc3, 0xc5,
+ 0x85, 0x7d, 0xbd, 0x1b, 0xd3, 0xed, 0x96, 0x31, 0x1d, 0x62, 0x18, 0xdb,
+ 0xc9, 0xbb, 0xf6, 0x16, 0x33, 0xe8, 0xe3, 0x75, 0x11, 0x1b, 0x12, 0xc7,
+ 0x49, 0x90, 0xaf, 0xfd, 0x91, 0x50, 0x58, 0xad, 0xc7, 0xab, 0x75, 0xa1,
+ 0x16, 0xaf, 0x41, 0xf1, 0xdd, 0xf8, 0x92, 0xef, 0x48, 0xc4, 0x92, 0xe3,
+ 0xf6, 0x10, 0xe8, 0xc5, 0xf8, 0xb9, 0xba, 0xe1, 0xc6, 0xc9, 0x8c, 0xd3,
+ 0x3f, 0x82, 0xc6, 0xbb, 0x15, 0xfe, 0x7e, 0xcc, 0xde, 0x2f, 0xe8, 0x96,
+ 0x15, 0xb8, 0x0e, 0x7b, 0x70, 0x1d, 0x91, 0xb8, 0xb2, 0x2e, 0xb0, 0x7e,
+ 0x78, 0x6b, 0x9a, 0xa6, 0xd8, 0x1b, 0x70, 0x0e, 0xf3, 0xb9, 0xb9, 0x6a,
+ 0x2d, 0x0c, 0xf9, 0xb6, 0xc1, 0x1f, 0x02, 0xd7, 0xac, 0x88, 0x43, 0x03,
+ 0x0b, 0xf5, 0x34, 0x1c, 0xc7, 0x5a, 0x88, 0xdb, 0x81, 0x8f, 0xcb, 0xf3,
+ 0x26, 0x89, 0xcf, 0x37, 0xc5, 0xdc, 0x63, 0xa2, 0x06, 0xea, 0xd3, 0x39,
+ 0x77, 0xc9, 0x0a, 0xde, 0x69, 0x92, 0x77, 0x8f, 0x56, 0xf0, 0x73, 0x78,
+ 0x1c, 0x90, 0x74, 0xe5, 0xdc, 0x95, 0x75, 0x5a, 0xf0, 0xa7, 0x9d, 0x73,
+ 0xd3, 0x41, 0x6a, 0x14, 0x23, 0x2f, 0x0c, 0xa9, 0xdb, 0x1c, 0x3a, 0x3a,
+ 0x31, 0xf2, 0xda, 0xba, 0x18, 0xf9, 0xb6, 0x20, 0xc7, 0x5a, 0xc3, 0x50,
+ 0x82, 0x79, 0xf8, 0xba, 0x97, 0x6d, 0xc8, 0x36, 0x70, 0x3d, 0x5f, 0x53,
+ 0xbb, 0xec, 0x59, 0xa6, 0xd6, 0x1c, 0x20, 0xdf, 0x0c, 0xfb, 0x0e, 0x0b,
+ 0x79, 0x06, 0x91, 0x36, 0xc9, 0x3a, 0xcb, 0xbe, 0xbd, 0x1a, 0x67, 0xcf,
+ 0x51, 0xa3, 0x18, 0xfb, 0x46, 0xfd, 0xfa, 0x79, 0xbf, 0xdf, 0x3a, 0xac,
+ 0x3b, 0x36, 0x73, 0x25, 0xbf, 0xee, 0xc2, 0xed, 0x41, 0x9c, 0xad, 0x50,
+ 0x93, 0x55, 0xc0, 0xfe, 0xde, 0xf0, 0x37, 0x5b, 0xae, 0x2e, 0x06, 0x68,
+ 0xfd, 0xcc, 0x2d, 0x42, 0x1f, 0x8d, 0xc9, 0xaa, 0x3e, 0x8e, 0x82, 0x37,
+ 0x19, 0xa7, 0x06, 0x60, 0xae, 0xa7, 0xeb, 0xd7, 0x0b, 0xc6, 0xed, 0x37,
+ 0xfd, 0xaa, 0xe5, 0xca, 0xc0, 0xf5, 0xf2, 0x91, 0x4f, 0xd5, 0xd1, 0xba,
+ 0x51, 0x4d, 0xf8, 0x2c, 0xe8, 0x1a, 0x47, 0xde, 0x1d, 0x79, 0x81, 0x10,
+ 0x3b, 0x39, 0x79, 0x78, 0x1a, 0xb9, 0x77, 0xe4, 0x02, 0xe7, 0xe3, 0x6e,
+ 0x7e, 0xfe, 0x6a, 0x29, 0x72, 0x36, 0x8f, 0x9c, 0x79, 0x1e, 0x39, 0xf9,
+ 0xcb, 0xc8, 0xc9, 0xcf, 0x97, 0x7a, 0x41, 0xff, 0x1e, 0x99, 0x8f, 0xb3,
+ 0x8e, 0x99, 0x74, 0x11, 0xb9, 0xd3, 0x77, 0x67, 0xd8, 0x46, 0x74, 0xd1,
+ 0x3d, 0xc8, 0x35, 0xbe, 0x3f, 0xa9, 0x68, 0x9d, 0x7d, 0x01, 0x5f, 0xc2,
+ 0xb8, 0x91, 0x38, 0x71, 0x29, 0x4f, 0x1a, 0xc7, 0x8a, 0x23, 0x4d, 0x7e,
+ 0x6b, 0xae, 0x95, 0x5a, 0xf6, 0x2c, 0xcb, 0x93, 0x6a, 0xac, 0xe8, 0xc2,
+ 0x19, 0xd4, 0xd9, 0xf7, 0x87, 0x9c, 0xdb, 0xc4, 0x48, 0xe4, 0xd3, 0xeb,
+ 0xe8, 0xed, 0x93, 0x65, 0xda, 0x19, 0xbb, 0x56, 0xbe, 0x68, 0xad, 0xa3,
+ 0x6c, 0xef, 0x43, 0x32, 0x97, 0x5c, 0x78, 0x28, 0x69, 0xe5, 0x43, 0x3e,
+ 0xf7, 0x7c, 0x62, 0x42, 0x47, 0x84, 0xc8, 0xbf, 0x20, 0xcd, 0x0d, 0x20,
+ 0x71, 0x6e, 0xd9, 0xfe, 0x02, 0x1f, 0x10, 0xb1, 0x6d, 0x9c, 0x33, 0x03,
+ 0xa2, 0xd6, 0xb6, 0xd1, 0xe2, 0x7e, 0x03, 0xfc, 0xbe, 0x8f, 0xe6, 0x90,
+ 0x43, 0x14, 0x44, 0x1e, 0xde, 0x0e, 0x78, 0x37, 0x0f, 0xbf, 0x1f, 0xb9,
+ 0x01, 0xd3, 0xd8, 0x04, 0xfc, 0x6f, 0x03, 0xc6, 0x6b, 0x43, 0x9f, 0x6b,
+ 0x22, 0xf1, 0x3d, 0x8f, 0xb7, 0x13, 0xd7, 0x65, 0xab, 0xf3, 0xf2, 0x9c,
+ 0x3c, 0xf6, 0x61, 0xf9, 0xf6, 0xbe, 0x3e, 0xcf, 0xdc, 0x6d, 0x9e, 0xb9,
+ 0xef, 0xf0, 0xcc, 0xed, 0xc3, 0xb7, 0x2e, 0x3e, 0x41, 0x7c, 0xeb, 0xae,
+ 0xf1, 0xb7, 0x9e, 0x35, 0x5c, 0xdc, 0xdb, 0x3d, 0xb8, 0xbf, 0x8f, 0xf9,
+ 0xb9, 0xcf, 0xf4, 0xf4, 0xf1, 0x9a, 0x1b, 0x68, 0x6e, 0xb0, 0x8d, 0x16,
+ 0x4f, 0x72, 0x5f, 0xd0, 0x83, 0x0b, 0xe3, 0x17, 0x90, 0x63, 0x6d, 0x74,
+ 0xf1, 0x64, 0x8b, 0xc0, 0x9b, 0xfd, 0xf9, 0xc6, 0xca, 0x9a, 0x57, 0xb0,
+ 0xa6, 0x3b, 0x97, 0x89, 0x6f, 0x19, 0x96, 0xf1, 0xe3, 0x31, 0xee, 0xe3,
+ 0xb1, 0x37, 0xcb, 0x5f, 0x33, 0x82, 0xce, 0x9e, 0x0d, 0xc6, 0xcd, 0xfd,
+ 0x56, 0x6b, 0x26, 0x8b, 0xdb, 0x9d, 0x34, 0x1b, 0xd4, 0xc0, 0x37, 0x55,
+ 0xfa, 0x28, 0xae, 0x23, 0xa8, 0x4a, 0xb4, 0x8f, 0xf9, 0xbc, 0x4e, 0xd6,
+ 0xaf, 0x5b, 0x30, 0x6f, 0xd8, 0xcd, 0xd1, 0x88, 0xe5, 0x38, 0x27, 0xec,
+ 0xbe, 0x26, 0xc7, 0xd9, 0xee, 0xb3, 0xdf, 0xc7, 0x53, 0xc8, 0xaa, 0x3c,
+ 0xaf, 0x29, 0xed, 0xa0, 0x83, 0x50, 0xcf, 0x8b, 0xb2, 0x9e, 0xb2, 0xe8,
+ 0xad, 0x99, 0x18, 0x4e, 0x1c, 0xe3, 0x9c, 0xed, 0xac, 0x85, 0xfe, 0xe0,
+ 0xbd, 0x98, 0x00, 0x1e, 0x61, 0x8a, 0xe2, 0xaf, 0x50, 0xca, 0xe3, 0x69,
+ 0xe1, 0xa9, 0xe0, 0xc9, 0xf5, 0x0c, 0x1d, 0x4f, 0xe8, 0x18, 0xec, 0x53,
+ 0xb4, 0xef, 0x92, 0x93, 0x3f, 0x41, 0x37, 0xde, 0x9e, 0x74, 0xea, 0x51,
+ 0x8b, 0xd6, 0x72, 0xf5, 0xa8, 0x3f, 0x67, 0x9e, 0x9c, 0x70, 0xeb, 0x51,
+ 0x8b, 0x24, 0xea, 0x51, 0x27, 0x56, 0xa8, 0x47, 0x25, 0x56, 0x5f, 0x8f,
+ 0xe2, 0xf9, 0x35, 0xda, 0xd7, 0x4f, 0xca, 0x17, 0x64, 0x3d, 0xea, 0x3d,
+ 0x72, 0xea, 0x51, 0x17, 0xa9, 0x71, 0x3d, 0xea, 0x78, 0x5d, 0x3d, 0x2a,
+ 0x28, 0xea, 0x51, 0x3c, 0x8f, 0x53, 0x8f, 0x12, 0xed, 0xbe, 0x88, 0xa7,
+ 0xee, 0x42, 0xf4, 0xee, 0x64, 0x07, 0x68, 0x66, 0xd0, 0xf7, 0x1a, 0xda,
+ 0x34, 0x45, 0xc8, 0xdb, 0x4a, 0x35, 0xd0, 0x07, 0x6e, 0xb8, 0xbe, 0xa2,
+ 0xd0, 0x06, 0xcc, 0x9b, 0xec, 0x7b, 0xd8, 0x53, 0x63, 0x61, 0x9a, 0xff,
+ 0x62, 0xea, 0x2c, 0x07, 0x45, 0x9d, 0xe5, 0x87, 0x6b, 0xbc, 0x75, 0x96,
+ 0x45, 0xba, 0x7e, 0x9d, 0xe5, 0x60, 0x83, 0x3a, 0xcb, 0x5b, 0x54, 0xad,
+ 0xb3, 0xbc, 0x45, 0xd5, 0x3a, 0xcb, 0xc1, 0x12, 0xe7, 0xe2, 0x3e, 0x89,
+ 0x5f, 0x06, 0xed, 0x41, 0xf1, 0xc7, 0xb5, 0x97, 0xc5, 0xca, 0x1e, 0x7e,
+ 0xd9, 0x6a, 0x2f, 0x6c, 0x03, 0x22, 0x17, 0x2e, 0xd7, 0xd4, 0x5e, 0xb8,
+ 0x0d, 0x9d, 0xb1, 0xd7, 0x08, 0x19, 0x99, 0x83, 0x7f, 0x5f, 0x9c, 0x0c,
+ 0x61, 0xce, 0x0e, 0xf8, 0x8c, 0x0e, 0xe4, 0x06, 0x61, 0xb4, 0x15, 0xda,
+ 0x64, 0x0d, 0xa1, 0x8f, 0xc7, 0xd9, 0x0e, 0x43, 0xb7, 0x6c, 0x77, 0x7f,
+ 0x0f, 0x48, 0x1a, 0x44, 0x68, 0xb8, 0x9d, 0xf4, 0x20, 0xfb, 0x8e, 0xc9,
+ 0x3d, 0x74, 0xc8, 0xde, 0x22, 0xf6, 0xbd, 0xc1, 0xaa, 0x95, 0xb9, 0xc1,
+ 0x1b, 0x90, 0xb9, 0xcc, 0xaa, 0x65, 0x8e, 0xe5, 0xcd, 0x39, 0xf7, 0xdd,
+ 0x60, 0xf1, 0xfa, 0x1d, 0x02, 0xa7, 0x77, 0x1b, 0xc8, 0xfb, 0x18, 0xec,
+ 0x8e, 0x33, 0xbf, 0x2e, 0xd7, 0xab, 0x8f, 0x87, 0x9f, 0x6d, 0x66, 0xff,
+ 0xbd, 0x72, 0x3d, 0xb1, 0xde, 0x7f, 0xaf, 0xe4, 0x47, 0x15, 0x61, 0x93,
+ 0xb3, 0x25, 0xae, 0xed, 0x7b, 0xf9, 0x33, 0x8f, 0x9c, 0x00, 0x7d, 0x42,
+ 0x0f, 0x98, 0xae, 0x41, 0xf0, 0x01, 0xeb, 0xd8, 0x4f, 0xc9, 0x5a, 0x16,
+ 0x9e, 0x05, 0x97, 0x7f, 0xad, 0xb0, 0x99, 0xee, 0x18, 0xdb, 0x01, 0x0b,
+ 0xfe, 0x8f, 0xeb, 0x28, 0x7c, 0x8e, 0xca, 0xfd, 0x2e, 0x5f, 0xbb, 0x2e,
+ 0xbc, 0xa7, 0x72, 0xbb, 0x5c, 0xce, 0x8a, 0x7a, 0x2d, 0xa9, 0x9d, 0x7d,
+ 0xd3, 0x2d, 0x6c, 0x6b, 0xb6, 0x58, 0xae, 0xcc, 0x26, 0xf0, 0xce, 0x7c,
+ 0x7d, 0x17, 0x36, 0x9c, 0xcf, 0xaa, 0xbf, 0x23, 0x6a, 0x04, 0x73, 0x36,
+ 0xdb, 0x6b, 0x8e, 0x41, 0x7f, 0x0b, 0xb2, 0xc4, 0xef, 0x51, 0x71, 0x2e,
+ 0x21, 0x6a, 0xf8, 0x83, 0xdc, 0x76, 0xed, 0x4a, 0x94, 0xed, 0x30, 0xf6,
+ 0x5c, 0xa5, 0x31, 0xe2, 0x23, 0xc8, 0x0c, 0xc7, 0xb1, 0x0c, 0xe7, 0xc6,
+ 0x9e, 0x9a, 0xa7, 0x66, 0xab, 0xcb, 0xb8, 0x88, 0x75, 0x39, 0x00, 0x9a,
+ 0xed, 0x10, 0x31, 0xea, 0xb8, 0x5d, 0xa6, 0xea, 0x19, 0x3f, 0xd3, 0xdc,
+ 0x39, 0xe7, 0x3f, 0x66, 0x2f, 0x47, 0xfb, 0xcd, 0x37, 0x48, 0x7b, 0x47,
+ 0x1f, 0x6b, 0xe9, 0xae, 0x23, 0x7e, 0x71, 0xe9, 0xee, 0xfa, 0xa8, 0x49,
+ 0x49, 0x83, 0xa8, 0xac, 0x2b, 0x7e, 0x5a, 0x9e, 0x29, 0xfd, 0x5f, 0xd8,
+ 0xaf, 0xe2, 0xd9, 0xaf, 0xab, 0xbb, 0xfb, 0xe4, 0x7e, 0xc3, 0x75, 0xba,
+ 0x1b, 0x97, 0x75, 0xb9, 0x5f, 0x84, 0xee, 0xba, 0x7b, 0xe2, 0xb5, 0xb7,
+ 0x5c, 0x67, 0xdd, 0x67, 0x48, 0x8d, 0xaf, 0x14, 0x7b, 0xff, 0xb4, 0xf9,
+ 0xe3, 0xc5, 0xde, 0x1f, 0x87, 0x9e, 0x5e, 0xbd, 0x65, 0x1a, 0xb6, 0x89,
+ 0xb8, 0xc2, 0xd1, 0x1f, 0xd8, 0xe3, 0x82, 0x9f, 0x16, 0x1e, 0xd2, 0xe9,
+ 0x9f, 0xee, 0xe4, 0xfa, 0xac, 0x26, 0x73, 0x7c, 0x6e, 0x7f, 0xb1, 0x95,
+ 0x63, 0xab, 0x4d, 0xd6, 0x77, 0x44, 0x6e, 0x95, 0x57, 0x4d, 0x8f, 0x1f,
+ 0x31, 0x30, 0xce, 0x63, 0x61, 0xba, 0x1c, 0xbc, 0x91, 0xb8, 0xbc, 0xcb,
+ 0x58, 0xf4, 0xad, 0x26, 0x2e, 0xbf, 0x55, 0xf7, 0x5b, 0x7f, 0xdd, 0x7a,
+ 0xbd, 0x3a, 0x47, 0x35, 0x2e, 0xe7, 0x7c, 0x3e, 0xe8, 0xd4, 0x18, 0x4c,
+ 0x8e, 0xcf, 0xd7, 0x4a, 0x9e, 0xf0, 0x3b, 0x72, 0x11, 0x1b, 0x79, 0x08,
+ 0x64, 0xfc, 0x55, 0xc8, 0xca, 0x2b, 0x36, 0xf2, 0x0e, 0x1b, 0xf9, 0x88,
+ 0x8d, 0xdc, 0xc3, 0x46, 0xee, 0x61, 0xf7, 0xc8, 0x1c, 0x26, 0x23, 0xeb,
+ 0x56, 0x7c, 0x46, 0xcb, 0xf9, 0x61, 0x5e, 0xc9, 0xd8, 0xe3, 0x7c, 0x1f,
+ 0x41, 0x4d, 0xc6, 0x36, 0xca, 0x78, 0xf0, 0x38, 0xdf, 0x77, 0x28, 0xab,
+ 0x71, 0xae, 0x45, 0x91, 0xaa, 0xc6, 0x6f, 0x87, 0x8f, 0xda, 0x0e, 0xbc,
+ 0x9a, 0x79, 0xdc, 0xa7, 0xc6, 0x5b, 0x99, 0x76, 0x8a, 0x1a, 0x5f, 0x2b,
+ 0xcf, 0x0d, 0x7a, 0x03, 0x0e, 0xfe, 0xdd, 0xdc, 0xd6, 0xd4, 0xf8, 0xdd,
+ 0xec, 0xd3, 0xc2, 0xa4, 0xba, 0xfd, 0xb7, 0x07, 0x98, 0xae, 0xa4, 0xde,
+ 0x16, 0xe0, 0xb8, 0x76, 0xde, 0xf6, 0x8b, 0x3b, 0x05, 0xc9, 0x18, 0xd7,
+ 0xcc, 0xb8, 0x5d, 0xa5, 0xab, 0xba, 0x2c, 0x5d, 0xfd, 0x95, 0xfa, 0x3f,
+ 0xd3, 0xd2, 0xc7, 0x70, 0xa2, 0x36, 0xc6, 0x34, 0x75, 0xe7, 0xe3, 0xf3,
+ 0x66, 0x5e, 0x47, 0xdc, 0x63, 0xc0, 0xf3, 0x60, 0x33, 0xb5, 0x0d, 0x0e,
+ 0xf9, 0x2d, 0xef, 0xba, 0x6c, 0x43, 0x76, 0x90, 0x37, 0xc7, 0x5a, 0x7e,
+ 0xcd, 0xa8, 0x38, 0x1b, 0x49, 0xf6, 0x47, 0x85, 0xec, 0xb0, 0xac, 0x69,
+ 0xe2, 0xce, 0xd5, 0x47, 0xe2, 0x1e, 0x09, 0xcb, 0x19, 0xcb, 0xf2, 0x78,
+ 0x7f, 0x57, 0x58, 0x53, 0x5b, 0xb0, 0x46, 0x98, 0xd2, 0x25, 0x71, 0x56,
+ 0x80, 0x7c, 0xe9, 0xdc, 0x3a, 0x6a, 0xfb, 0x07, 0xbd, 0x9a, 0xc7, 0x46,
+ 0x9d, 0xb3, 0x7a, 0xbb, 0xde, 0xff, 0x8d, 0x8a, 0x73, 0x65, 0xc7, 0x06,
+ 0xb9, 0xe7, 0xc3, 0xab, 0x3b, 0xff, 0xbe, 0xbe, 0x3e, 0xb5, 0xd4, 0xd7,
+ 0x0d, 0x24, 0x0d, 0x98, 0x36, 0x8d, 0xcf, 0xee, 0xe7, 0x4b, 0x7c, 0xaf,
+ 0x25, 0x12, 0xe3, 0xdc, 0x6d, 0x44, 0xdc, 0xf9, 0x50, 0x21, 0x85, 0x3a,
+ 0x8d, 0x19, 0x9c, 0xf3, 0x85, 0x86, 0x7d, 0x71, 0xca, 0x64, 0x27, 0x48,
+ 0x43, 0xac, 0x98, 0xa9, 0xd6, 0x03, 0x1f, 0x5c, 0x43, 0x96, 0x2b, 0x97,
+ 0x51, 0xce, 0x1f, 0x6a, 0xce, 0xed, 0x16, 0xe9, 0xb0, 0x72, 0xa0, 0x74,
+ 0x84, 0x0e, 0x34, 0x8c, 0x29, 0x1b, 0xd7, 0x03, 0x2f, 0xd6, 0xd5, 0x14,
+ 0x16, 0x44, 0x4d, 0x21, 0xb7, 0xc6, 0x6f, 0x3d, 0x19, 0x70, 0xee, 0xb5,
+ 0x34, 0xd6, 0x93, 0x5d, 0x15, 0x3d, 0x71, 0xe1, 0xf8, 0x2c, 0xbe, 0x8d,
+ 0x76, 0x8a, 0xb5, 0x0e, 0x2b, 0x59, 0xbb, 0x95, 0x76, 0x1a, 0x0e, 0xd6,
+ 0xa3, 0x36, 0xe3, 0x75, 0x58, 0x39, 0x68, 0xe7, 0x95, 0xb4, 0xa8, 0x3d,
+ 0x70, 0x8c, 0xbf, 0xe6, 0xda, 0x30, 0x95, 0xe9, 0xed, 0x98, 0xfb, 0x3d,
+ 0xc3, 0x78, 0x6b, 0x8a, 0x2e, 0x9d, 0xf8, 0x2e, 0x51, 0x58, 0xe6, 0x6f,
+ 0xce, 0x7c, 0xb9, 0x29, 0xae, 0x25, 0xde, 0x8f, 0xfd, 0x33, 0xfc, 0x6e,
+ 0x25, 0x39, 0x55, 0x2e, 0xa7, 0x31, 0x3e, 0xd6, 0x7b, 0xaf, 0xc8, 0x8d,
+ 0xd4, 0x38, 0x0d, 0x71, 0x8e, 0xac, 0x2d, 0xc9, 0x91, 0xd3, 0xd0, 0x35,
+ 0xc4, 0x20, 0x76, 0x13, 0xbe, 0x75, 0xe3, 0x91, 0xcf, 0xae, 0x75, 0x64,
+ 0xe4, 0xbb, 0x12, 0x0f, 0x1e, 0xff, 0xfb, 0x80, 0x7b, 0x0f, 0x28, 0x77,
+ 0x2a, 0x8d, 0xfd, 0x37, 0x51, 0xca, 0x74, 0xf2, 0xbb, 0xec, 0x99, 0x23,
+ 0x1b, 0x6a, 0xe1, 0xd1, 0x77, 0xca, 0x85, 0x0f, 0xd6, 0xc1, 0xf3, 0x19,
+ 0xd7, 0x5f, 0xd5, 0xc1, 0x07, 0x3d, 0xf0, 0x66, 0x1d, 0x3c, 0xe2, 0xae,
+ 0x33, 0xdf, 0xa8, 0x83, 0x37, 0x3d, 0xf0, 0xed, 0x75, 0xf0, 0xed, 0x80,
+ 0x7f, 0xa3, 0x0e, 0x1e, 0x7d, 0xa7, 0x90, 0x13, 0x08, 0xda, 0x70, 0x8c,
+ 0x74, 0x48, 0xe6, 0x89, 0x78, 0x2e, 0xb9, 0x1f, 0xc9, 0xf2, 0xd3, 0x01,
+ 0x1a, 0x7b, 0xeb, 0xb5, 0x09, 0xd8, 0xa8, 0xaa, 0x4c, 0x39, 0xfa, 0xea,
+ 0x95, 0x25, 0x96, 0xbd, 0x3c, 0xe4, 0x15, 0x7a, 0x54, 0x80, 0x3e, 0x15,
+ 0x5c, 0x5f, 0xca, 0x77, 0xaa, 0x22, 0xc7, 0x1d, 0x3d, 0x56, 0x68, 0xbd,
+ 0x35, 0x2f, 0x73, 0x91, 0xab, 0x8c, 0x3b, 0xfc, 0x86, 0xeb, 0x3b, 0xe8,
+ 0x84, 0x63, 0x57, 0x58, 0xbf, 0x79, 0x7e, 0x69, 0x5f, 0x4a, 0x2c, 0x87,
+ 0xce, 0x3a, 0xe9, 0x25, 0x32, 0x1b, 0x5e, 0x52, 0x77, 0xf1, 0xd5, 0xd9,
+ 0x77, 0x12, 0xf6, 0x3d, 0xd7, 0xe2, 0xb7, 0x36, 0xac, 0xbd, 0x9e, 0x7d,
+ 0xcf, 0x78, 0xec, 0x7b, 0x38, 0x58, 0xf5, 0xf9, 0x8f, 0x09, 0x9f, 0xdf,
+ 0xd1, 0xc0, 0x66, 0xac, 0xde, 0xe7, 0xef, 0xfd, 0xd8, 0x3e, 0x7f, 0xb9,
+ 0x75, 0x57, 0xe3, 0xf3, 0x1f, 0x69, 0xf9, 0x78, 0x3e, 0x9f, 0xd7, 0xac,
+ 0xaf, 0x65, 0x7a, 0xcf, 0x59, 0x8e, 0xca, 0x18, 0x7b, 0xb7, 0x27, 0xc6,
+ 0x66, 0xfc, 0xbe, 0x27, 0xef, 0x02, 0x9e, 0x5e, 0xeb, 0xc8, 0xdb, 0x51,
+ 0x19, 0xa7, 0x73, 0xec, 0x8d, 0xf7, 0xc2, 0x23, 0x90, 0xd1, 0x7c, 0x8f,
+ 0x8f, 0x54, 0x9a, 0x35, 0x9d, 0xb3, 0xed, 0x9f, 0x6f, 0xae, 0x17, 0xa1,
+ 0xcb, 0xc2, 0x9f, 0x24, 0x3e, 0x81, 0x5a, 0xea, 0x49, 0xc8, 0x8f, 0xbb,
+ 0xaf, 0x95, 0x6a, 0xa9, 0xf5, 0xe7, 0x1f, 0x7c, 0xee, 0x41, 0xca, 0x03,
+ 0x95, 0x73, 0x10, 0xaf, 0x4e, 0xe9, 0x94, 0x9d, 0x21, 0xdd, 0x8c, 0x93,
+ 0xb2, 0x8f, 0x71, 0x8e, 0xfd, 0xb0, 0x52, 0x6f, 0x3f, 0x24, 0x6b, 0x30,
+ 0xea, 0xb2, 0x77, 0x82, 0x7e, 0x02, 0x7c, 0x58, 0xaf, 0x9c, 0x1a, 0x8c,
+ 0xea, 0xdc, 0x09, 0x3a, 0xfe, 0xf3, 0xbb, 0x13, 0xc4, 0xf3, 0x6b, 0xb4,
+ 0xb7, 0xc1, 0x9d, 0x20, 0xdf, 0x2a, 0xef, 0x04, 0xad, 0x17, 0x35, 0x18,
+ 0x9e, 0xc7, 0xa9, 0xc1, 0x70, 0xbb, 0xb3, 0x8f, 0xe5, 0x3a, 0x4c, 0xa3,
+ 0x93, 0xb7, 0x88, 0x7b, 0xa8, 0x9d, 0x7d, 0xb5, 0xf2, 0xbd, 0xef, 0x13,
+ 0x8d, 0xa5, 0x79, 0xbd, 0xa3, 0x0d, 0xef, 0xb6, 0x24, 0x3f, 0xc1, 0x9a,
+ 0xcb, 0x21, 0x51, 0x73, 0xb9, 0xb3, 0xcd, 0x5b, 0x73, 0x51, 0x57, 0xb8,
+ 0xdb, 0x72, 0xa8, 0x41, 0xcd, 0xc5, 0xef, 0xb9, 0xdb, 0xe2, 0xf7, 0xdc,
+ 0x6d, 0x39, 0x24, 0xeb, 0x2b, 0xea, 0x2f, 0xd1, 0xdd, 0x96, 0xe4, 0x8a,
+ 0x77, 0x5b, 0xb6, 0x4a, 0x7d, 0xf5, 0xc2, 0xaf, 0xfe, 0xbc, 0x32, 0x55,
+ 0x67, 0xe7, 0x13, 0xc2, 0xce, 0xdf, 0xd5, 0xea, 0xb7, 0x9e, 0x69, 0xbb,
+ 0x9e, 0x9d, 0xdf, 0x57, 0xd1, 0x53, 0xbe, 0xa3, 0xcd, 0x77, 0xbe, 0x58,
+ 0x16, 0xf9, 0x7c, 0xa6, 0x89, 0x72, 0x03, 0xbf, 0x2a, 0x68, 0xf6, 0x58,
+ 0x6f, 0xed, 0x99, 0x63, 0xf5, 0x5e, 0xa4, 0xee, 0xb9, 0x17, 0x69, 0xa2,
+ 0x5f, 0xaf, 0xab, 0x87, 0x04, 0xe4, 0xdd, 0x7e, 0xf8, 0xc2, 0x19, 0x43,
+ 0xda, 0x5e, 0xc4, 0x70, 0x98, 0xae, 0x50, 0xe4, 0x3b, 0x95, 0x6d, 0xe4,
+ 0x9b, 0x71, 0xce, 0x4b, 0x54, 0x11, 0x63, 0x42, 0x8e, 0x8b, 0x7e, 0xe1,
+ 0x6f, 0xd4, 0xb8, 0x23, 0xb3, 0xe3, 0xf6, 0x05, 0xe0, 0xbf, 0x21, 0x51,
+ 0x6d, 0x9b, 0x95, 0x5a, 0xce, 0x58, 0xe5, 0x0e, 0xbf, 0x09, 0xfb, 0xe0,
+ 0xdc, 0x07, 0xca, 0x98, 0x7c, 0x67, 0xe4, 0x62, 0x5b, 0xf5, 0x3e, 0xd0,
+ 0x67, 0xa4, 0x9c, 0x3a, 0xf7, 0x81, 0x48, 0x4d, 0x40, 0x3e, 0x6e, 0xe4,
+ 0x3e, 0x50, 0xd7, 0x92, 0xfb, 0x40, 0x2b, 0xf3, 0x66, 0xe9, 0x7d, 0xa0,
+ 0xc6, 0xfc, 0xe1, 0xfb, 0x40, 0xff, 0xde, 0xe6, 0xdc, 0x43, 0x5d, 0x89,
+ 0x3f, 0x6e, 0x9c, 0xf4, 0x11, 0xe0, 0xf9, 0x3e, 0x50, 0xe5, 0x1e, 0x90,
+ 0xe7, 0x0e, 0x10, 0xdf, 0x25, 0x59, 0xee, 0x0c, 0xce, 0x7b, 0xff, 0xa4,
+ 0xa7, 0x72, 0xff, 0xe4, 0x7c, 0xc9, 0xf5, 0xed, 0xee, 0xb9, 0x1c, 0xc7,
+ 0x39, 0xbb, 0x44, 0x8e, 0x7a, 0xae, 0x54, 0x5b, 0xc3, 0x60, 0xbe, 0x8f,
+ 0x16, 0xcf, 0x81, 0x3e, 0x6f, 0x89, 0xdc, 0x00, 0x7c, 0xde, 0xe2, 0x23,
+ 0xe6, 0x1d, 0x29, 0xa0, 0x8b, 0x38, 0xcb, 0x75, 0xf8, 0xdd, 0x21, 0x64,
+ 0xc1, 0x91, 0x8b, 0xdd, 0x9e, 0xf3, 0xd0, 0xaa, 0x1c, 0x38, 0x67, 0xba,
+ 0x0e, 0xef, 0x6a, 0x65, 0x46, 0x9c, 0xdd, 0x0c, 0xed, 0xb5, 0x9c, 0xf3,
+ 0xc6, 0xa8, 0x38, 0xb7, 0x6d, 0xaf, 0xb3, 0x5b, 0x3a, 0xe4, 0x06, 0x31,
+ 0x67, 0x8c, 0xeb, 0xd5, 0x8c, 0xfb, 0x66, 0xc1, 0xe3, 0x46, 0x67, 0x71,
+ 0x2b, 0xd7, 0xf1, 0xdc, 0x9a, 0x0a, 0x21, 0x97, 0xd8, 0x9d, 0xce, 0x09,
+ 0xbb, 0xe9, 0xac, 0xdd, 0x29, 0xd6, 0xde, 0x58, 0x77, 0x96, 0xcd, 0x72,
+ 0xb5, 0x5c, 0x4c, 0x70, 0x3d, 0x9a, 0xde, 0xb3, 0x84, 0xa6, 0xb5, 0xba,
+ 0x84, 0xdc, 0xb5, 0x62, 0xe3, 0x3b, 0x2a, 0xba, 0x34, 0x2e, 0xee, 0x21,
+ 0xbb, 0xe7, 0xb5, 0x0e, 0xfd, 0xaa, 0xba, 0xb7, 0x5c, 0x3c, 0x53, 0x4f,
+ 0xbf, 0x4d, 0xff, 0x4b, 0xe8, 0x77, 0x15, 0xf4, 0xe3, 0x77, 0x03, 0xef,
+ 0xef, 0x8a, 0x7a, 0xc0, 0xb9, 0x52, 0xe4, 0x78, 0x9e, 0x38, 0x4e, 0x88,
+ 0xcc, 0x2e, 0x50, 0x0f, 0xe8, 0xc8, 0xff, 0xeb, 0xe2, 0xde, 0x9d, 0x60,
+ 0xfa, 0xb2, 0x7d, 0x8f, 0xbc, 0x70, 0x99, 0xd8, 0xc6, 0xdf, 0x8d, 0x7d,
+ 0x94, 0xcb, 0x2f, 0xc5, 0x5c, 0xfa, 0xb3, 0xee, 0x73, 0x9d, 0xaa, 0x76,
+ 0x5f, 0x7b, 0x57, 0xed, 0x53, 0x1d, 0xf9, 0xcc, 0x34, 0x90, 0xcf, 0x8c,
+ 0xdc, 0xa3, 0x6f, 0xa6, 0x71, 0xbc, 0x9a, 0x9a, 0xfc, 0xef, 0x5e, 0xae,
+ 0x26, 0xb6, 0x8d, 0x22, 0x0a, 0xbf, 0xac, 0xd7, 0x4e, 0xe3, 0xa4, 0x61,
+ 0x93, 0x3a, 0xad, 0x69, 0xd2, 0x60, 0xc7, 0x4b, 0x12, 0x29, 0xa5, 0xa4,
+ 0x52, 0x55, 0x45, 0x60, 0xa9, 0x21, 0x4e, 0xda, 0x0a, 0x71, 0x70, 0x0b,
+ 0x48, 0x51, 0xc5, 0x21, 0x4d, 0xd3, 0x7b, 0x85, 0x84, 0x54, 0xa1, 0x8a,
+ 0x46, 0x4e, 0x02, 0x15, 0x4a, 0xe5, 0x0a, 0x96, 0x72, 0x41, 0xa2, 0xd8,
+ 0x8e, 0x02, 0x52, 0x2a, 0xf7, 0xca, 0x85, 0xba, 0xbf, 0x08, 0x89, 0x03,
+ 0x70, 0x06, 0x29, 0x2a, 0x3f, 0xe2, 0xc0, 0x8d, 0x1b, 0x54, 0x5d, 0xde,
+ 0x37, 0xb3, 0x63, 0xaf, 0x77, 0xd7, 0x8e, 0x03, 0x11, 0x07, 0x27, 0xbb,
+ 0xf6, 0xcc, 0xce, 0xec, 0xcc, 0x37, 0x6f, 0xbe, 0xf7, 0x37, 0xfd, 0xbe,
+ 0x78, 0x8d, 0x5a, 0xdb, 0x5b, 0xf3, 0x55, 0xec, 0xe7, 0xaf, 0x37, 0x18,
+ 0x57, 0xed, 0xba, 0xe4, 0xa9, 0xf5, 0xe3, 0x9a, 0x72, 0xd9, 0x1b, 0xf0,
+ 0xfe, 0xc7, 0x68, 0x51, 0xd8, 0x86, 0x94, 0xad, 0xee, 0xc5, 0x40, 0x9b,
+ 0xd9, 0xff, 0x33, 0x16, 0x03, 0x3e, 0x9b, 0x68, 0xad, 0x6d, 0x8a, 0xed,
+ 0x71, 0xd9, 0x16, 0xde, 0xda, 0xc2, 0xb6, 0x10, 0x3c, 0x16, 0xfd, 0x9e,
+ 0xb1, 0xa8, 0xc9, 0xea, 0xa1, 0x16, 0xed, 0x74, 0x88, 0x21, 0xbf, 0x9d,
+ 0x67, 0x6c, 0x05, 0xca, 0xce, 0x4f, 0x5d, 0x36, 0x3c, 0xe0, 0x73, 0xdc,
+ 0x59, 0xeb, 0xc0, 0x27, 0xb5, 0x9d, 0x1a, 0x51, 0xed, 0x01, 0x8f, 0xc9,
+ 0xc5, 0x45, 0x82, 0xbe, 0x86, 0x36, 0xe3, 0x82, 0xe3, 0xfa, 0x39, 0x14,
+ 0x8f, 0xf1, 0xfa, 0x1b, 0x88, 0xe5, 0x70, 0xda, 0x3f, 0xd9, 0x76, 0xae,
+ 0x9c, 0xe5, 0xbd, 0x42, 0xd4, 0x63, 0xbd, 0xef, 0x52, 0xdb, 0x82, 0xa8,
+ 0x27, 0xe3, 0x20, 0x1c, 0x1d, 0xd0, 0xe1, 0xe2, 0x8d, 0x74, 0x3f, 0xff,
+ 0x9e, 0x13, 0xcc, 0xdd, 0x7f, 0xdd, 0x1d, 0x36, 0x3f, 0x34, 0x64, 0xae,
+ 0xde, 0x56, 0xdc, 0x5d, 0xd9, 0x89, 0x06, 0x85, 0xaf, 0xc1, 0xad, 0x7b,
+ 0x41, 0x76, 0x5d, 0xe0, 0x3d, 0x7c, 0xa8, 0xba, 0x7f, 0xef, 0x84, 0x7d,
+ 0xe8, 0x99, 0x16, 0x62, 0x1d, 0x44, 0x8e, 0xe5, 0x2b, 0x53, 0xc8, 0x45,
+ 0xaa, 0xe6, 0xef, 0x78, 0xf3, 0x3c, 0x20, 0x3f, 0x55, 0x9e, 0x87, 0xca,
+ 0x23, 0xc5, 0x7b, 0x24, 0x02, 0xf2, 0x3c, 0xdc, 0x32, 0x18, 0xf5, 0xea,
+ 0xdf, 0xc3, 0x2d, 0x7f, 0x57, 0x1c, 0xf9, 0x5b, 0xf0, 0xd8, 0xe3, 0x97,
+ 0xf3, 0x6a, 0x2d, 0x20, 0xe7, 0x43, 0xf1, 0x94, 0xde, 0x00, 0x9e, 0x12,
+ 0x9c, 0xeb, 0xa1, 0xa5, 0x2f, 0xf2, 0x5e, 0x7e, 0x08, 0x7b, 0xb9, 0x51,
+ 0x8b, 0xe9, 0x95, 0x72, 0xf0, 0xdc, 0x3a, 0x64, 0xa2, 0xca, 0xb9, 0x81,
+ 0x5c, 0x44, 0x2c, 0x3c, 0xe6, 0xba, 0xe4, 0x60, 0x11, 0xbf, 0xa9, 0x58,
+ 0x52, 0xa5, 0x47, 0xbd, 0x23, 0xf2, 0x0c, 0xbe, 0x1b, 0x3f, 0xcc, 0x1c,
+ 0x18, 0xf2, 0x13, 0x76, 0xa6, 0x43, 0x0e, 0x1f, 0xbe, 0xcc, 0xbf, 0x8d,
+ 0x39, 0xd7, 0x92, 0x8b, 0xca, 0x6b, 0xa5, 0x4b, 0xfd, 0xd0, 0x41, 0xe6,
+ 0x6f, 0x0e, 0x2f, 0xad, 0xb3, 0x41, 0xc4, 0x53, 0xda, 0xdb, 0x74, 0xa1,
+ 0xd8, 0x0c, 0x83, 0xf5, 0xf8, 0x4b, 0x79, 0x38, 0x4f, 0x42, 0x70, 0x9e,
+ 0x9f, 0x3a, 0xc2, 0xe6, 0x44, 0x4f, 0xb3, 0x38, 0x9c, 0x53, 0x55, 0xfc,
+ 0xa9, 0x72, 0xaa, 0x6f, 0x8f, 0x3a, 0x10, 0xa7, 0xe6, 0xc7, 0x04, 0xe6,
+ 0x1f, 0xfa, 0x9c, 0x5a, 0x87, 0xd0, 0xeb, 0x10, 0xf3, 0x87, 0x76, 0x8d,
+ 0x06, 0x6b, 0xb0, 0x66, 0x13, 0x2f, 0x50, 0x2b, 0xb1, 0x7f, 0xc9, 0xd1,
+ 0x0a, 0x9d, 0xed, 0x69, 0xa6, 0xf3, 0x9e, 0x08, 0xd4, 0x79, 0x83, 0x72,
+ 0xa4, 0xcc, 0x80, 0x1c, 0x29, 0x37, 0x0e, 0x75, 0x17, 0x0e, 0xe3, 0x2e,
+ 0x2e, 0x30, 0xc0, 0xdc, 0xb9, 0x8b, 0xf1, 0x04, 0xee, 0x1c, 0xa5, 0xd0,
+ 0x07, 0x6e, 0xee, 0xec, 0xf7, 0x13, 0x49, 0x5c, 0xfe, 0xdb, 0xdc, 0xa9,
+ 0xa0, 0x7e, 0x27, 0x7c, 0xfd, 0x86, 0x1c, 0x9f, 0x6c, 0xc8, 0x13, 0x82,
+ 0x38, 0xfe, 0x4e, 0xf7, 0xd3, 0xbb, 0xf6, 0xd1, 0xa6, 0x09, 0xfd, 0x70,
+ 0x74, 0xb1, 0xba, 0xee, 0x5f, 0xf0, 0xd9, 0xb9, 0xc1, 0x67, 0x43, 0xc2,
+ 0x27, 0xd7, 0x25, 0xf6, 0x90, 0x9d, 0x93, 0x61, 0x9d, 0x1e, 0x19, 0x66,
+ 0xf7, 0xd4, 0xec, 0xfc, 0x88, 0x21, 0xec, 0x73, 0x74, 0x0e, 0xb9, 0xef,
+ 0x14, 0x1a, 0xc6, 0xa5, 0xe2, 0x3b, 0xe9, 0x1b, 0x38, 0x77, 0x04, 0xb2,
+ 0x1b, 0xf2, 0xfc, 0xf4, 0x6c, 0xd8, 0x34, 0x1c, 0x1f, 0x03, 0xfc, 0x08,
+ 0xc0, 0xa9, 0x7a, 0x7e, 0x90, 0x0d, 0x3d, 0x68, 0x0e, 0x87, 0x7c, 0x73,
+ 0x28, 0xf1, 0x06, 0x6e, 0x8f, 0x58, 0xbc, 0x83, 0x9e, 0x38, 0xc5, 0x9d,
+ 0x18, 0x93, 0xee, 0x80, 0x78, 0x41, 0xc4, 0xfa, 0xf9, 0xfa, 0xcb, 0xef,
+ 0x7c, 0x51, 0xf3, 0xaf, 0xad, 0x49, 0x6d, 0xba, 0x3c, 0xad, 0x4d, 0x15,
+ 0x51, 0xee, 0xa2, 0x56, 0xdb, 0x97, 0x36, 0x5d, 0x1c, 0x11, 0x7c, 0x30,
+ 0x79, 0xad, 0x42, 0x78, 0x4f, 0xdb, 0xbe, 0x25, 0xb8, 0xed, 0x80, 0x0f,
+ 0xab, 0x8a, 0x73, 0x18, 0x2d, 0xbc, 0x97, 0xb4, 0xbd, 0xb8, 0xb9, 0x8e,
+ 0x5b, 0xbe, 0x3f, 0x1d, 0x20, 0xdf, 0x9b, 0xd9, 0x0a, 0x91, 0xbf, 0x29,
+ 0xe2, 0xb2, 0xa9, 0x68, 0x21, 0xde, 0xf1, 0x30, 0xe2, 0x7b, 0xe1, 0xd7,
+ 0xa8, 0x62, 0xe1, 0x6e, 0x30, 0x16, 0xaa, 0xf6, 0x60, 0x1d, 0xb9, 0xa3,
+ 0x2c, 0x8b, 0xc3, 0xe9, 0x5e, 0x0a, 0x99, 0x28, 0xff, 0x6c, 0xe2, 0x3e,
+ 0x1d, 0x73, 0x78, 0x09, 0xfc, 0x3c, 0xb2, 0xde, 0x4c, 0x0b, 0x76, 0xe1,
+ 0x60, 0x7f, 0x46, 0x84, 0x65, 0xf3, 0x67, 0xbd, 0xad, 0xf9, 0x33, 0x54,
+ 0x39, 0xd4, 0xed, 0xa2, 0x35, 0x0b, 0x71, 0x92, 0xf0, 0x2f, 0x75, 0x77,
+ 0xb4, 0x9b, 0x41, 0xf2, 0x4f, 0xc5, 0x7e, 0x82, 0x1f, 0xc9, 0xb9, 0xba,
+ 0x41, 0x98, 0x3b, 0x9b, 0xbe, 0x6f, 0x30, 0x57, 0xdb, 0xb1, 0x29, 0x37,
+ 0x9f, 0x2b, 0xc3, 0x33, 0x57, 0xd8, 0x8b, 0x9a, 0xcd, 0x95, 0xf2, 0x43,
+ 0x2a, 0xdf, 0xdc, 0x51, 0xc8, 0x93, 0x45, 0xf7, 0x5c, 0xed, 0x8c, 0x7f,
+ 0x4e, 0xce, 0xd9, 0x4e, 0xfb, 0xe0, 0x1a, 0x8f, 0x43, 0x34, 0xd0, 0x76,
+ 0x12, 0x2c, 0x33, 0xfc, 0x6b, 0xeb, 0x86, 0x5c, 0x5b, 0xcc, 0x2b, 0x9e,
+ 0x6f, 0xb8, 0xb6, 0xb0, 0x0f, 0x5c, 0x70, 0xf6, 0x81, 0xd3, 0x3e, 0x7d,
+ 0x51, 0xd9, 0xbc, 0xff, 0xab, 0xed, 0x0d, 0xcf, 0x7d, 0x22, 0xce, 0xe9,
+ 0xc8, 0x91, 0xdc, 0x47, 0xce, 0x37, 0xe4, 0x61, 0x3d, 0xdb, 0x5c, 0xa7,
+ 0x6a, 0xee, 0x91, 0x73, 0x01, 0x79, 0x99, 0xa5, 0xf3, 0xf9, 0xc7, 0x06,
+ 0x75, 0xf7, 0x53, 0xa4, 0x1a, 0xd3, 0x72, 0x40, 0xf0, 0x61, 0xb7, 0xbe,
+ 0xbc, 0xec, 0xe4, 0x28, 0xe6, 0x5c, 0x63, 0xb0, 0x9c, 0xcf, 0x36, 0x89,
+ 0xa7, 0x6f, 0x25, 0x9e, 0x63, 0xc0, 0x23, 0x37, 0xbd, 0x73, 0x35, 0xa1,
+ 0x65, 0xf2, 0xa8, 0xb3, 0x87, 0xce, 0xea, 0x9f, 0xf0, 0x18, 0x3d, 0xb1,
+ 0x23, 0xe2, 0x9c, 0x11, 0xe0, 0xd2, 0xb6, 0x97, 0xcd, 0x0e, 0x5a, 0x94,
+ 0x7e, 0x46, 0x9a, 0xfa, 0xf8, 0x12, 0x15, 0x85, 0x7f, 0x0b, 0xb9, 0x51,
+ 0xb0, 0x71, 0xc3, 0x47, 0x87, 0xe7, 0xf0, 0xf7, 0x1b, 0x13, 0x8e, 0xcc,
+ 0xfd, 0x93, 0x31, 0x8c, 0x7a, 0x38, 0x0b, 0x01, 0xeb, 0x9d, 0x34, 0xc9,
+ 0x31, 0xb9, 0x1d, 0x71, 0x4e, 0x80, 0x8c, 0xcd, 0xbb, 0x5d, 0xde, 0x8e,
+ 0x4f, 0xa1, 0x55, 0xbd, 0xe4, 0xeb, 0x68, 0xd8, 0xfc, 0x72, 0xcf, 0xf6,
+ 0x7d, 0x0a, 0x2a, 0x77, 0x5f, 0x71, 0x58, 0x75, 0x2d, 0x73, 0x69, 0xc1,
+ 0x99, 0xe7, 0xd7, 0x55, 0xde, 0x6d, 0x77, 0x40, 0xde, 0x6d, 0x88, 0xe6,
+ 0x84, 0xaf, 0x2e, 0x44, 0x39, 0x47, 0x37, 0x93, 0x9c, 0x5a, 0xd9, 0x6a,
+ 0x23, 0x4e, 0xfc, 0x29, 0xee, 0xdd, 0x39, 0xf9, 0x7c, 0x5f, 0x04, 0xcf,
+ 0x46, 0x4e, 0xb5, 0x2d, 0x62, 0xf1, 0x33, 0xa2, 0x5c, 0xa7, 0xa7, 0x1c,
+ 0xdf, 0x17, 0xd5, 0x33, 0x3b, 0xb9, 0x7c, 0x8a, 0x64, 0x0e, 0x7d, 0x27,
+ 0xcd, 0x15, 0x9b, 0xf5, 0x6b, 0x1f, 0xe2, 0x81, 0xe3, 0xf0, 0x95, 0x0a,
+ 0xbf, 0x95, 0xa1, 0xfa, 0x80, 0x3e, 0xb5, 0x57, 0xfb, 0x04, 0xf9, 0x14,
+ 0x12, 0x7e, 0x05, 0xbe, 0x76, 0xda, 0x99, 0x23, 0x77, 0xbf, 0xc2, 0xdc,
+ 0x2f, 0x3c, 0xa7, 0xd3, 0x55, 0xb6, 0xd3, 0x55, 0xb6, 0x36, 0x5e, 0x3a,
+ 0xeb, 0x54, 0x0b, 0xe5, 0x1f, 0x59, 0x2f, 0xfd, 0x56, 0xd8, 0xe6, 0xe6,
+ 0xb3, 0x06, 0x2d, 0xac, 0xf7, 0xf2, 0x27, 0xc6, 0x1f, 0x94, 0xdb, 0xcb,
+ 0xff, 0xdd, 0x9c, 0xa2, 0x5f, 0xc4, 0x02, 0xb6, 0xce, 0x07, 0x83, 0xf1,
+ 0x1f, 0xbc, 0x6e, 0x13, 0x01, 0xeb, 0xb6, 0xf9, 0xbe, 0x22, 0xf7, 0x93,
+ 0xe4, 0x95, 0x8a, 0x23, 0xaf, 0x36, 0x69, 0xd0, 0x27, 0xa7, 0x82, 0xd6,
+ 0x29, 0xfa, 0x78, 0xca, 0xe9, 0xe3, 0x9b, 0xa2, 0x3f, 0xe3, 0x54, 0xa8,
+ 0xe6, 0x0d, 0x1f, 0xe1, 0xeb, 0x98, 0xb2, 0xd1, 0x35, 0x90, 0xab, 0xdf,
+ 0x6c, 0x43, 0xc6, 0x04, 0x71, 0xb2, 0x03, 0x01, 0xfa, 0x80, 0xee, 0xd2,
+ 0x07, 0xe2, 0x55, 0x7d, 0x60, 0x45, 0xe8, 0x09, 0xbb, 0x1c, 0x1d, 0x34,
+ 0xd8, 0x16, 0x97, 0xcb, 0xe3, 0xcc, 0x1b, 0xd8, 0xf8, 0xa4, 0x1d, 0x7d,
+ 0xda, 0xaa, 0x9e, 0x99, 0xc3, 0xba, 0x65, 0x8d, 0x4b, 0xfb, 0xe5, 0x09,
+ 0xce, 0xac, 0xa8, 0xcc, 0x3e, 0x30, 0xa3, 0xa4, 0xa5, 0x93, 0xf1, 0xa9,
+ 0x50, 0x84, 0x16, 0xac, 0x28, 0x15, 0xac, 0x14, 0x73, 0x70, 0xf0, 0xe3,
+ 0xd0, 0x80, 0x46, 0x11, 0x96, 0x35, 0x11, 0x2a, 0x95, 0x94, 0x4e, 0x76,
+ 0x86, 0xc8, 0x2c, 0xc6, 0xa4, 0x0d, 0x9b, 0x71, 0x9a, 0x1f, 0x33, 0xe6,
+ 0x49, 0x43, 0xcc, 0x8b, 0x93, 0xa3, 0x0e, 0x0c, 0x8a, 0x38, 0x4b, 0xfd,
+ 0xe5, 0x91, 0x28, 0xb5, 0xa7, 0xa5, 0xcd, 0x68, 0x86, 0xdb, 0xf8, 0xc2,
+ 0x8a, 0xd1, 0x95, 0x7c, 0xd2, 0x38, 0xc1, 0xed, 0x64, 0xac, 0x64, 0x62,
+ 0x92, 0x9f, 0x5d, 0x2c, 0x45, 0x28, 0x67, 0x45, 0xa8, 0x50, 0x4a, 0x19,
+ 0x43, 0x6d, 0xa2, 0xcd, 0x18, 0xda, 0x7c, 0x49, 0x1f, 0x33, 0x4e, 0x92,
+ 0xbb, 0xcd, 0xaf, 0x9c, 0x36, 0xbd, 0x6d, 0xfd, 0x61, 0xe3, 0xfe, 0x44,
+ 0xa8, 0x32, 0x7b, 0x9f, 0xf1, 0x92, 0x5b, 0x9d, 0x60, 0xd9, 0x14, 0x13,
+ 0x67, 0xdb, 0x68, 0xe9, 0x34, 0xcb, 0x1d, 0x9c, 0x6d, 0x61, 0xd0, 0x62,
+ 0x39, 0x4e, 0xef, 0x57, 0xed, 0x07, 0x12, 0x43, 0x39, 0x91, 0x43, 0x84,
+ 0x33, 0x17, 0x2a, 0xb3, 0xbf, 0x9b, 0x5e, 0x7f, 0x3f, 0xeb, 0x5b, 0x1f,
+ 0xc5, 0x28, 0x72, 0x15, 0x71, 0xdd, 0x36, 0x5d, 0x1b, 0x4f, 0x5e, 0xd9,
+ 0x14, 0x79, 0x68, 0x09, 0x5a, 0x33, 0xa5, 0x3c, 0xcd, 0x71, 0xf9, 0x15,
+ 0x94, 0x5b, 0x4b, 0xd0, 0x3d, 0x91, 0x8f, 0xd6, 0x4e, 0x77, 0xf4, 0x18,
+ 0x85, 0x6e, 0x9a, 0xc6, 0xbc, 0xf0, 0x0b, 0x57, 0x66, 0x87, 0x86, 0x0d,
+ 0xd2, 0xae, 0xa2, 0x1e, 0xff, 0xbf, 0x89, 0xfb, 0x28, 0x61, 0x7e, 0x66,
+ 0xac, 0x31, 0x5e, 0x49, 0xc3, 0xf1, 0x12, 0x64, 0xf3, 0x41, 0x89, 0xa5,
+ 0x39, 0x23, 0x42, 0xd0, 0x5f, 0x61, 0x7b, 0xeb, 0x35, 0x27, 0x7b, 0xa4,
+ 0xfe, 0xe4, 0x3b, 0x9b, 0x43, 0x9f, 0x19, 0x71, 0x9f, 0xcf, 0x51, 0x7b,
+ 0x66, 0xc6, 0x92, 0xef, 0xb9, 0x52, 0xee, 0xa5, 0x25, 0x6e, 0x7b, 0x64,
+ 0xf8, 0x8c, 0x73, 0xa6, 0x0f, 0xff, 0xd9, 0x8b, 0x7b, 0x85, 0xb7, 0x7d,
+ 0x7d, 0x14, 0xc5, 0x3d, 0x0d, 0xe8, 0x3c, 0xc7, 0xb0, 0xe9, 0x87, 0xc5,
+ 0xb8, 0xa7, 0xe2, 0x98, 0xcb, 0xb9, 0xb8, 0x3a, 0x97, 0x08, 0x65, 0xba,
+ 0xe9, 0x91, 0xd5, 0x45, 0x3f, 0x8b, 0xf3, 0x47, 0xf8, 0xba, 0x84, 0x9c,
+ 0xa3, 0x36, 0xca, 0x64, 0xbb, 0x69, 0xb3, 0x14, 0x66, 0x71, 0x05, 0xec,
+ 0x44, 0xb9, 0x4c, 0x81, 0xa6, 0xd6, 0x5f, 0xeb, 0x83, 0x1f, 0x66, 0x52,
+ 0xab, 0x61, 0xe9, 0x51, 0x00, 0x96, 0x7e, 0xa9, 0xc3, 0xd2, 0xd1, 0xbe,
+ 0xe6, 0x58, 0xea, 0x77, 0x62, 0xd6, 0xa3, 0x14, 0x71, 0x70, 0xf4, 0x39,
+ 0xe3, 0xe8, 0x3d, 0xc6, 0xd1, 0xf1, 0x06, 0x38, 0xd2, 0x3c, 0x38, 0x3a,
+ 0x51, 0x87, 0xa3, 0x6c, 0x5f, 0x33, 0x1c, 0x1d, 0x0f, 0xa1, 0xff, 0xcd,
+ 0xd6, 0x32, 0xfa, 0xb0, 0x9f, 0x39, 0xbd, 0x49, 0xa5, 0xd5, 0xe4, 0xf8,
+ 0x24, 0x55, 0x90, 0x73, 0x92, 0x58, 0xa2, 0xb4, 0xe0, 0x76, 0x05, 0x81,
+ 0xbf, 0x2c, 0x8f, 0xc9, 0xae, 0x06, 0xe7, 0xaa, 0x24, 0x9c, 0x79, 0x93,
+ 0x73, 0x99, 0xc9, 0x57, 0x66, 0x1f, 0x32, 0x36, 0xee, 0x6d, 0xe8, 0x3a,
+ 0x7e, 0x0b, 0xb1, 0x8c, 0xbc, 0xbb, 0x81, 0x73, 0x5b, 0xe2, 0x74, 0xdf,
+ 0x1a, 0xa0, 0x7b, 0xd6, 0x7e, 0xba, 0x6b, 0x0d, 0xd2, 0x03, 0x0b, 0x6d,
+ 0x60, 0x0e, 0xf8, 0x5e, 0xcc, 0x81, 0x46, 0x33, 0x31, 0x2e, 0x53, 0xda,
+ 0x4f, 0x95, 0x92, 0xc2, 0x35, 0xb0, 0x03, 0x0c, 0x35, 0xc6, 0x4e, 0xa6,
+ 0x0e, 0x3b, 0xb2, 0x0e, 0x30, 0xb3, 0xe4, 0xb7, 0xad, 0xed, 0x32, 0xf8,
+ 0x5d, 0x0d, 0xc6, 0x56, 0x58, 0xc4, 0x91, 0x24, 0x47, 0x67, 0x42, 0x90,
+ 0x59, 0xb7, 0x18, 0x53, 0x3c, 0x17, 0x3c, 0x7e, 0xda, 0xf5, 0x41, 0x96,
+ 0x39, 0x4f, 0x09, 0x1b, 0xf4, 0x94, 0xa9, 0xc7, 0x33, 0x64, 0x5f, 0xd6,
+ 0xcc, 0x31, 0x91, 0xeb, 0xb6, 0x54, 0xf6, 0x9e, 0x31, 0x91, 0xe1, 0xb1,
+ 0x57, 0x78, 0xf4, 0xca, 0xa1, 0x76, 0xaa, 0x38, 0x31, 0x4c, 0x85, 0x55,
+ 0xdb, 0x7e, 0xc8, 0xfc, 0x7f, 0xcd, 0x84, 0xcc, 0xfe, 0xdb, 0xae, 0xc4,
+ 0x74, 0x5a, 0x36, 0x55, 0xdf, 0xee, 0x08, 0x7c, 0x31, 0x47, 0xa4, 0x77,
+ 0x37, 0xaa, 0xaf, 0xc4, 0xbf, 0xe3, 0xbb, 0xbf, 0x04, 0x97, 0x59, 0xab,
+ 0x96, 0x85, 0xed, 0xf8, 0xd2, 0xd8, 0xc2, 0x2a, 0xce, 0x7e, 0x7b, 0xfc,
+ 0xea, 0xf9, 0xd5, 0x5c, 0x1f, 0x4b, 0xd8, 0x94, 0x4e, 0x76, 0x68, 0x79,
+ 0x3c, 0xf7, 0x5c, 0x98, 0x86, 0x19, 0x97, 0x38, 0x83, 0x6b, 0x6c, 0x34,
+ 0x2c, 0xce, 0x38, 0xd9, 0xcd, 0x78, 0xc8, 0x0a, 0x3b, 0xfd, 0xd4, 0x91,
+ 0x09, 0x9a, 0x2c, 0xa7, 0xf9, 0x53, 0x3f, 0x7e, 0xb5, 0xb9, 0xe3, 0xe1,
+ 0x48, 0xe3, 0x37, 0x37, 0xff, 0xa8, 0xd5, 0x9d, 0xe6, 0xba, 0x33, 0x5b,
+ 0xd6, 0x55, 0xe7, 0x12, 0xfd, 0x03, 0x69, 0xae, 0x1b, 0xa3, 0xbc, 0x57,
+ 0x00, 0x00, 0x00 };
static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = {
@@ -989,952 +687,368 @@ static u32 bnx2_RXP_b06FwBssAddr = 0x08005900;
static int bnx2_RXP_b06FwBssLen = 0x13a4;
static u32 bnx2_RXP_b06FwSbssAddr = 0x080058e0;
static int bnx2_RXP_b06FwSbssLen = 0x1c;
-static u32 bnx2_RXP_b06FwText[(0x588c/4) + 1] = {
- 0x0a000c61, 0x00000000, 0x00000000, 0x0000000d, 0x72787020, 0x322e362e,
- 0x31000000, 0x02060103, 0x00000000, 0x0000000d, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d,
- 0x3c020800, 0x244258e0, 0x3c030800, 0x24636ca4, 0xac400000, 0x0043202b,
- 0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800,
- 0x26103184, 0x3c1c0800, 0x279c58e0, 0x0e00104a, 0x00000000, 0x0000000d,
- 0x27bdffe8, 0xafb00010, 0xafbf0014, 0x0e000f1d, 0x00808021, 0x1440000d,
- 0x00000000, 0x8f820010, 0x10400005, 0x00000000, 0x9743011c, 0x9742011e,
- 0x0a000c89, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825,
- 0xaf830004, 0x8f840008, 0x3c020020, 0x34424000, 0x00821824, 0x54620004,
- 0x3c020020, 0x8f820014, 0x0a000c9a, 0x34421000, 0x34428000, 0x00821824,
- 0x14620004, 0x00000000, 0x8f820014, 0x34428000, 0xaf820014, 0x8f820008,
- 0x9743010c, 0x00403021, 0x30421000, 0x10400010, 0x3069ffff, 0x30c20020,
- 0x1440000e, 0x24070005, 0x3c021000, 0x00c21024, 0x10400009, 0x3c030dff,
- 0x3463ffff, 0x3c020e00, 0x00c21024, 0x0062182b, 0x50600004, 0x24070001,
- 0x0a000cb2, 0x3c020800, 0x24070001, 0x3c020800, 0x8c430034, 0x1460001d,
- 0x00405821, 0x8f820014, 0x30424000, 0x1440001a, 0x3c020001, 0x3c021f01,
- 0x00c24024, 0x3c031000, 0x15030015, 0x3c020001, 0x31220200, 0x14400012,
- 0x3c020001, 0x9744010e, 0x24020003, 0xa342018b, 0x97850016, 0x24020002,
- 0x34e30002, 0xaf400180, 0xa742018c, 0xa7430188, 0x24840004, 0x30a5bfff,
- 0xa744018e, 0xa74501a6, 0xaf4801b8, 0x0a000f19, 0x00001021, 0x3c020001,
- 0x00c21024, 0x1040002f, 0x00000000, 0x9742010e, 0x3c038000, 0x3046ffff,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9784000a,
- 0x8f850004, 0x8f870014, 0x24020080, 0x24030002, 0xaf420180, 0x24020003,
- 0xa743018c, 0xa746018e, 0xa7420188, 0x30e28000, 0xa7440190, 0x1040000c,
- 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000,
- 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00e21024, 0xaf820014,
- 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff,
- 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19,
- 0x00001021, 0x8f820014, 0x30434000, 0x10600016, 0x00404021, 0x3c020f00,
- 0x00c21024, 0x14400012, 0x00000000, 0x93420116, 0x34424000, 0x03421821,
- 0x94650002, 0x2ca21389, 0x1040000b, 0x3c020800, 0x24425900, 0x00051942,
- 0x00031880, 0x00621821, 0x30a5001f, 0x8c640000, 0x24020001, 0x00a21004,
- 0x00822024, 0x02048025, 0x12000030, 0x3c021000, 0x9742010e, 0x34e80002,
- 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020180,
- 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000,
- 0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
- 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
- 0x00e21024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
- 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
- 0xaf4201b8, 0x0a000f19, 0x00001021, 0x00c21024, 0x104000c0, 0x3c020800,
- 0x8c430030, 0x10600037, 0x31024000, 0x10400035, 0x3c030f00, 0x00c31824,
- 0x3c020100, 0x0043102b, 0x14400031, 0x3c030800, 0x9742010e, 0x34e80002,
- 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020080,
- 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000,
- 0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
- 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
- 0x00e21024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
- 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
- 0xaf4201b8, 0x0a000f19, 0x00001021, 0x3c030800, 0x8c620024, 0x30420008,
- 0x10400035, 0x34ea0002, 0x3c020f00, 0x00c21024, 0x14400032, 0x8d620034,
- 0x31220200, 0x1040002f, 0x8d620034, 0x9742010e, 0x30e8fffb, 0x3c038000,
- 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
- 0xa342018b, 0x9784000a, 0x8f850004, 0x8f870014, 0x24020180, 0x24030002,
- 0xaf420180, 0xa743018c, 0xa746018e, 0xa7480188, 0x30e28000, 0xa7440190,
- 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
- 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00e21024,
- 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
- 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
- 0x8d620034, 0x8f860008, 0x10400012, 0x30c20100, 0x10400010, 0x3c020f00,
- 0x00c21024, 0x3c030200, 0x1043000c, 0x3c020800, 0x8c430038, 0x8f840004,
- 0x3c020800, 0x2442003c, 0x2463ffff, 0x00832024, 0x00822021, 0x90830000,
- 0x24630004, 0x0a000de1, 0x000329c0, 0x00000000, 0x00061602, 0x3042000f,
- 0x000229c0, 0x3c04fc00, 0x00441021, 0x3c030300, 0x0062182b, 0x50600001,
- 0x24050800, 0x9742010e, 0x3148ffff, 0x3c038000, 0x24420004, 0x3046ffff,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
- 0x8f840004, 0x8f870014, 0x24020002, 0xaf450180, 0xa742018c, 0xa746018e,
- 0xa7480188, 0x30e28000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116,
- 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004,
- 0x3c02ffff, 0x34427fff, 0x00e21024, 0xaf820014, 0x97820016, 0x9743010c,
- 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
- 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x8f424000,
- 0x30420100, 0x104000d5, 0x3c020800, 0x8c440024, 0x24030001, 0x1483002f,
- 0x00405021, 0x9742010e, 0x34e70002, 0x3c038000, 0x24420004, 0x3045ffff,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
- 0x8f840004, 0x8f860014, 0x24020002, 0xaf400180, 0xa742018c, 0xa745018e,
- 0xa7470188, 0x30c28000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116,
- 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004,
- 0x3c02ffff, 0x34427fff, 0x00c21024, 0xaf820014, 0x97820016, 0x9743010c,
- 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6,
- 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x30820001,
- 0x1040002e, 0x30eb0004, 0x9742010e, 0x30e9fffb, 0x3c038000, 0x24420004,
- 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b,
- 0x9783000a, 0x8f840004, 0x8f860014, 0x24020002, 0xaf400180, 0xa742018c,
- 0xa745018e, 0xa7470188, 0x30c28000, 0xa7430190, 0x1040000c, 0xaf4401a8,
- 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff,
- 0x14600004, 0x3c02ffff, 0x34427fff, 0x00c21024, 0xaf820014, 0x97820016,
- 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825,
- 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x3127ffff, 0x8d420024,
- 0x30420004, 0x10400030, 0x8d420024, 0x9742010e, 0x30e9fffb, 0x3c038000,
- 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003,
- 0xa342018b, 0x9784000a, 0x8f850004, 0x8f880014, 0x24020100, 0x24030002,
- 0xaf420180, 0xa743018c, 0xa746018e, 0xa7470188, 0x31028000, 0xa7440190,
- 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
- 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x01021024,
- 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
- 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
- 0x3127ffff, 0x8d420024, 0x30420008, 0x1040002d, 0x00000000, 0x9742010e,
- 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x24020003, 0xa342018b, 0x9784000a, 0x8f850004, 0x8f880014, 0x24020180,
- 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0xa7470188, 0x31028000,
- 0xa7440190, 0x1040000c, 0xaf4501a8, 0x93420116, 0x304200fc, 0x005a1021,
- 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff,
- 0x01021024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff,
- 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000,
- 0xaf4201b8, 0x15600041, 0x00001021, 0x27440180, 0x3c038000, 0x8f4201b8,
- 0x00431024, 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008, 0xa083000b,
- 0xa4800010, 0x3c021000, 0xaf4201b8, 0x0a000f19, 0x00001021, 0x3c030800,
- 0x8c620024, 0x30420001, 0x1040002e, 0x00001021, 0x9742010e, 0x34e70002,
- 0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x24020003, 0xa342018b, 0x9783000a, 0x8f840004, 0x8f860014, 0x24020002,
- 0xaf400180, 0xa742018c, 0xa745018e, 0xa7470188, 0x30c28000, 0xa7430190,
- 0x1040000c, 0xaf4401a8, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004,
- 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00c21024,
- 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00,
- 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8,
- 0x00001021, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x8f4b0070,
- 0x93420112, 0x8f840008, 0x00022882, 0x30820100, 0x14400003, 0x24a30003,
- 0x03e00008, 0x00001021, 0x30824000, 0x10400010, 0x27424000, 0x00031880,
- 0x00431021, 0x8c470000, 0x24a30004, 0x00031880, 0x27424000, 0x00431021,
- 0x8c490000, 0x93430116, 0x27424000, 0x306300fc, 0x00431021, 0x8c4a0000,
- 0x0a000f45, 0x3c030800, 0x30822000, 0x1040ffea, 0x00031880, 0x27424000,
- 0x00431021, 0x8c470000, 0x24a30004, 0x00031880, 0x27424000, 0x00431021,
- 0x8c490000, 0x00005021, 0x3c030800, 0x24680100, 0x00071602, 0x00021080,
- 0x00481021, 0x8c460000, 0x00071b82, 0x306303fc, 0x01031821, 0x8c640400,
- 0x00071182, 0x304203fc, 0x01021021, 0x8c450800, 0x30e300ff, 0x00031880,
- 0x01031821, 0x00091602, 0x00021080, 0x01021021, 0x00c43026, 0x8c640c00,
- 0x8c431000, 0x00c53026, 0x00091382, 0x304203fc, 0x01021021, 0x8c451400,
- 0x312200ff, 0x00021080, 0x01021021, 0x00c43026, 0x00c33026, 0x00091982,
- 0x306303fc, 0x01031821, 0x8c641800, 0x8c431c00, 0x00c53026, 0x00c43026,
- 0x11400015, 0x00c33026, 0x000a1602, 0x00021080, 0x01021021, 0x8c432000,
- 0x000a1382, 0x304203fc, 0x01021021, 0x8c452400, 0x314200ff, 0x00021080,
- 0x01021021, 0x00c33026, 0x000a1982, 0x306303fc, 0x01031821, 0x8c642800,
- 0x8c432c00, 0x00c53026, 0x00c43026, 0x00c33026, 0x8f430070, 0x3c050800,
- 0x8ca43100, 0x2c820020, 0x10400008, 0x006b5823, 0x3c020800, 0x24423104,
- 0x00041880, 0x00621821, 0x24820001, 0xac6b0000, 0xaca23100, 0xaf860004,
- 0x03e00008, 0x24020001, 0x27bdffe8, 0xafbf0010, 0x8f460128, 0x8f840010,
- 0xaf460020, 0x8f450104, 0x8f420100, 0x24030800, 0xaf850008, 0xaf820014,
- 0xaf4301b8, 0x1080000a, 0x3c020800, 0x8c430034, 0x10600007, 0x30a22000,
- 0x10400005, 0x34a30100, 0x8f82000c, 0xaf830008, 0x24420001, 0xaf82000c,
- 0x3c020800, 0x8c4300c0, 0x10600006, 0x3c030800, 0x8c6200c4, 0x24040001,
- 0x24420001, 0x0a000fd5, 0xac6200c4, 0x8f820008, 0x3c030010, 0x00431024,
- 0x14400009, 0x3c02001f, 0x3c030800, 0x8c620020, 0x00002021, 0x24420001,
- 0x0e000c78, 0xac620020, 0x0a000fd5, 0x00402021, 0x3442ff00, 0x14c20009,
- 0x2403bfff, 0x3c030800, 0x8c620020, 0x24040001, 0x24420001, 0x0e000c78,
- 0xac620020, 0x0a000fd5, 0x00402021, 0x8f820014, 0x00431024, 0x14400006,
- 0x00000000, 0xaf400048, 0x0e0011a9, 0xaf400040, 0x0a000fd5, 0x00402021,
- 0x0e001563, 0x00000000, 0x00402021, 0x10800005, 0x3c024000, 0x8f430124,
- 0x3c026020, 0xac430014, 0x3c024000, 0xaf420138, 0x00000000, 0x8fbf0010,
- 0x03e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0xafb00010,
- 0x8f420140, 0xaf420020, 0x8f430148, 0x3c027000, 0x00621824, 0x3c023000,
- 0x10620021, 0x0043102b, 0x14400006, 0x3c024000, 0x3c022000, 0x10620009,
- 0x3c024000, 0x0a001040, 0x00000000, 0x10620045, 0x3c025000, 0x10620047,
- 0x3c024000, 0x0a001040, 0x00000000, 0x27440180, 0x3c038000, 0x8f4201b8,
- 0x00431024, 0x1440fffd, 0x00000000, 0x8f420148, 0x24030002, 0xa083000b,
- 0x00021402, 0xa4820008, 0x8f430148, 0xa4830010, 0x8f420144, 0x3c031000,
- 0xac820024, 0xaf4301b8, 0x0a001040, 0x3c024000, 0x8f420148, 0x24030002,
- 0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003,
- 0x10400005, 0x24020003, 0x0600001d, 0x36053000, 0x0a001027, 0x3c038000,
- 0x12020007, 0x00000000, 0x0a001034, 0x00000000, 0x0e00112c, 0x00000000,
- 0x0a001025, 0x00402021, 0x0e00113e, 0x00000000, 0x00402021, 0x36053000,
- 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008,
- 0xa222000b, 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8,
- 0x0a001040, 0x3c024000, 0x0000000d, 0x00000000, 0x240002bf, 0x0a001040,
- 0x3c024000, 0x0e001441, 0x00000000, 0x0a001040, 0x3c024000, 0x0e0015ea,
- 0x00000000, 0x3c024000, 0xaf420178, 0x00000000, 0x8fbf0018, 0x8fb10014,
- 0x8fb00010, 0x03e00008, 0x27bd0020, 0x24020800, 0x03e00008, 0xaf4201b8,
- 0x27bdffe8, 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000,
- 0x2403ff7f, 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000,
- 0x3c020008, 0xaf430008, 0x8e040808, 0x0342d825, 0x8e020808, 0x3c030800,
- 0xac600020, 0x3084fff0, 0x2c840001, 0x3042fff0, 0x38420010, 0x2c420001,
- 0xaf840010, 0xaf820000, 0x0e00160c, 0x00000000, 0x0e001561, 0x00000000,
- 0x3c020400, 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c,
- 0x8e021980, 0x34420200, 0xae021980, 0x8f500000, 0x32020003, 0x1040fffd,
- 0x32020001, 0x10400004, 0x32020002, 0x0e000f92, 0x00000000, 0x32020002,
- 0x1040fff6, 0x00000000, 0x0e000fe0, 0x00000000, 0x0a001071, 0x00000000,
- 0x27bdffe8, 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000,
- 0x2403ff7f, 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000,
- 0x3c020008, 0xaf430008, 0x8e040808, 0x0342d825, 0x8e020808, 0x3c030800,
- 0xac600020, 0x3084fff0, 0x2c840001, 0x3042fff0, 0x38420010, 0x2c420001,
- 0xaf840010, 0xaf820000, 0x0e00160c, 0x00000000, 0x0e001561, 0x00000000,
- 0x3c020400, 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c,
- 0x8e021980, 0x8fbf0014, 0x34420200, 0xae021980, 0x8fb00010, 0x03e00008,
- 0x27bd0018, 0x00804821, 0x30a5ffff, 0x30c6ffff, 0x30e7ffff, 0x3c038000,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x9783000a,
- 0x8f840004, 0x8f880014, 0xaf490180, 0xa745018c, 0xa746018e, 0xa7470188,
- 0x31028000, 0xa7430190, 0x1040000c, 0xaf4401a8, 0x93420116, 0x304200fc,
- 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff,
- 0x34427fff, 0x01021024, 0xaf820014, 0x97820016, 0x9743010c, 0x8f440104,
- 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac,
- 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00000000, 0x27440180, 0x3c038000,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008,
- 0xa083000b, 0xa4800010, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00000000,
- 0x27440180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000,
- 0x8f420148, 0x24030002, 0xa083000b, 0x00021402, 0xa4820008, 0x8f430148,
- 0xa4830010, 0x8f420144, 0x3c031000, 0xac820024, 0x03e00008, 0xaf4301b8,
- 0x27bdffe0, 0xafbf0018, 0xafb10014, 0xafb00010, 0x8f420148, 0x24030002,
- 0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003,
- 0x10400005, 0x24020003, 0x0600001d, 0x36053000, 0x0a001117, 0x3c038000,
- 0x12020007, 0x00000000, 0x0a001124, 0x00000000, 0x0e00112c, 0x00000000,
- 0x0a001115, 0x00402021, 0x0e00113e, 0x00000000, 0x00402021, 0x36053000,
- 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008,
- 0xa222000b, 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8,
- 0x0a001128, 0x8fbf0018, 0x0000000d, 0x00000000, 0x240002bf, 0x8fbf0018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3084ffff, 0x2c821389,
- 0x1040000d, 0x00001021, 0x3c030800, 0x24635900, 0x00042942, 0x00052880,
- 0x00a32821, 0x3086001f, 0x8ca40000, 0x24030001, 0x00c31804, 0x00832025,
- 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x3084ffff, 0x2c821389,
- 0x1040000e, 0x00001021, 0x3c030800, 0x24635900, 0x00042942, 0x00052880,
- 0x00a32821, 0x3086001f, 0x24030001, 0x8ca40000, 0x00c31804, 0x00031827,
- 0x00832024, 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x9482000c,
- 0x24870014, 0x00021302, 0x00021080, 0x00824021, 0x00e8182b, 0x1060004f,
- 0x00000000, 0x90e30000, 0x2c620009, 0x10400047, 0x3c020800, 0x24425890,
- 0x00031880, 0x00621821, 0x8c640000, 0x00800008, 0x00000000, 0x0a0011a4,
- 0x24e70001, 0x90e30001, 0x2402000a, 0x54620024, 0x01003821, 0x01071023,
- 0x2c42000a, 0x54400020, 0x01003821, 0x3c050800, 0x8ca26c98, 0x24e70002,
- 0x34420100, 0xaca26c98, 0x90e30000, 0x90e20001, 0x90e40002, 0x90e60003,
- 0x24e70004, 0x24a56c98, 0x00031e00, 0x00021400, 0x00621825, 0x00042200,
- 0x00641825, 0x00661825, 0xaca30004, 0x90e20000, 0x90e30001, 0x90e40002,
- 0x90e60003, 0x24e70004, 0x00021600, 0x00031c00, 0x00431025, 0x00042200,
- 0x00441025, 0x00461025, 0x0a0011a4, 0xaca20008, 0x90e30001, 0x24020004,
- 0x1062000e, 0x00601021, 0x0a00119e, 0x01001021, 0x90e30001, 0x24020003,
- 0x10620008, 0x00601021, 0x0a00119e, 0x01001021, 0x90e30001, 0x24020002,
- 0x14620003, 0x01001021, 0x00601021, 0x00e21021, 0x0a0011a4, 0x00403821,
- 0x90e20001, 0x0a0011a4, 0x00e23821, 0x01003821, 0x00e8102b, 0x5440ffb4,
- 0x90e30000, 0x03e00008, 0x24020001, 0x27bdff90, 0x3c030800, 0xafbf006c,
- 0xafbe0068, 0xafb70064, 0xafb60060, 0xafb5005c, 0xafb40058, 0xafb30054,
- 0xafb20050, 0xafb1004c, 0xafb00048, 0xac606c98, 0x93620023, 0x30420010,
- 0x1440027c, 0x24020001, 0x93420116, 0x93630005, 0x34424000, 0x30630001,
- 0x14600005, 0x0342b021, 0x0e0015e0, 0x00000000, 0x0a001436, 0x8fbf006c,
- 0x93420112, 0x8f430104, 0x3c040020, 0x34424000, 0x00641824, 0x10600012,
- 0x03422821, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x00000000, 0x8f420128, 0xaca20000, 0x8f640040, 0x24030008, 0x240240c1,
- 0xa4a20008, 0x24020002, 0xa0a2000b, 0x3c021000, 0x0a0011f1, 0xa0a3000a,
- 0x8f420104, 0x3c030040, 0x00431024, 0x1040001d, 0x3c038000, 0x27450180,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000,
- 0x8f640040, 0x24030010, 0x240240c1, 0xa4a20008, 0x24020002, 0xa0a3000a,
- 0x24030008, 0xa0a2000b, 0x3c021000, 0xa4a30010, 0xa0a00012, 0xa0a00013,
- 0xaca00014, 0xaca00024, 0xaca00028, 0xaca0002c, 0xaca40018, 0x0e0015e0,
- 0xaf4201b8, 0x0a001436, 0x8fbf006c, 0x8f820000, 0x10400016, 0x00000000,
- 0x8f420104, 0x3c030001, 0x00431024, 0x10400011, 0x00000000, 0x8ca3000c,
- 0x8f620030, 0x1462022d, 0x24020001, 0x8ca30010, 0x8f62002c, 0x14620229,
- 0x24020001, 0x9763003a, 0x96c20000, 0x14430225, 0x24020001, 0x97630038,
- 0x96c20002, 0x14430221, 0x24020001, 0xaf400048, 0xaf400054, 0xaf400040,
- 0x8f740040, 0x8f650048, 0x00b43023, 0x04c10004, 0x00000000, 0x0000000d,
- 0x00000000, 0x240001af, 0x9742011a, 0x3052ffff, 0x12400004, 0x8ed30004,
- 0x02721021, 0x0a001228, 0x2451ffff, 0x02608821, 0x92d7000d, 0xa7a00020,
- 0xa3a0001a, 0xafa00028, 0x9362003f, 0x32e30004, 0x1060003a, 0x305000ff,
- 0x24040012, 0x16040006, 0x24020001, 0x3c040800, 0x8c830028, 0x24630001,
- 0x0a001328, 0xac830028, 0x8f620044, 0x16620010, 0x27a60010, 0x27450180,
- 0x3c038000, 0x2402001a, 0xa7a20020, 0x24020020, 0xafb40028, 0xa3b00022,
- 0xa3a40023, 0xa3a2001a, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000,
- 0x0a00130d, 0x00000000, 0x8f620044, 0x02621023, 0x0440001a, 0x02651023,
- 0x044100d9, 0x24020001, 0x3c020800, 0x8c4300d8, 0x10600004, 0x24020001,
- 0xa7a20020, 0x0a00125e, 0xafb40028, 0x2402001a, 0xa7a20020, 0x24020020,
- 0xafb40028, 0xa3b00022, 0xa3a40023, 0xa3a2001a, 0x27a60010, 0x27450180,
- 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d,
- 0x00000000, 0x0a001328, 0x24020001, 0x0293f023, 0x1bc00016, 0x025e102a,
- 0x54400007, 0x32f700fe, 0x57d2000f, 0x027e9821, 0x32e20001, 0x5440000c,
- 0x027e9821, 0x32f700fe, 0x0240f021, 0x3c040800, 0x8c8300c8, 0x00009021,
- 0x24020001, 0xa7a20020, 0xafb40028, 0x24630001, 0x0a001282, 0xac8300c8,
- 0x025e1023, 0x0a001282, 0x3052ffff, 0x0000f021, 0x24a2ffff, 0x02221823,
- 0x1860001f, 0x0072102a, 0x54400019, 0x00a08821, 0x97a20020, 0x3c040800,
- 0x8c8300cc, 0xafb40028, 0x34420001, 0x24630001, 0xa7a20020, 0x02741026,
- 0x2c420001, 0xac8300cc, 0x2cc30001, 0x00431024, 0x1440000a, 0x02401821,
- 0x27a60010, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd,
- 0x00000000, 0x0a00130d, 0x00000000, 0x00a08821, 0x02431023, 0x3052ffff,
- 0x0a0012ae, 0x32f700f6, 0x02741023, 0x18400008, 0x97a20020, 0x3c040800,
- 0x8c8300d4, 0xafb30028, 0x34420400, 0x24630001, 0xa7a20020, 0xac8300d4,
- 0x32e20002, 0x1040001c, 0x32e20010, 0x8f620044, 0x1662000d, 0x27a60010,
- 0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001, 0xa7a20020,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d, 0x00000000,
- 0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001, 0xa7a20020,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a00130d, 0x00000000,
- 0x54400003, 0x8ed50008, 0x0a001328, 0x24020001, 0x8f630054, 0x26a2ffff,
- 0x00431023, 0x18400011, 0x27a60010, 0x97a20020, 0x3c040800, 0x8c8300d0,
- 0x27450180, 0x3c078000, 0xafb40028, 0x34420001, 0x24630001, 0xa7a20020,
- 0xac8300d0, 0x8f4201b8, 0x00471024, 0x1440fffd, 0x00000000, 0x0a00130d,
- 0x00000000, 0x32e20020, 0x10400011, 0x00000000, 0x96c20012, 0x0052102b,
- 0x10400008, 0x97a20020, 0x96d20012, 0x12400003, 0x02721021, 0x0a0012f2,
- 0x2451ffff, 0x02608821, 0x97a20020, 0x93a3001a, 0x34420008, 0x34630004,
- 0xa7a20020, 0xa3a3001a, 0x8f420104, 0x3c030080, 0x00431024, 0x10400037,
- 0x3a03000a, 0x0e001151, 0x02c02021, 0x24030002, 0x1443002b, 0x3c030800,
- 0x27a60010, 0x97a20020, 0x27450180, 0x3c038000, 0xafb40028, 0x34420001,
- 0xa7a20020, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128,
- 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, 0x90c4000a,
- 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, 0x90c30012,
- 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, 0x8cc20024,
- 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc4002c, 0x24020001, 0x3c031000,
- 0xaca4002c, 0xaf4301b8, 0xaf400044, 0xaf400050, 0x0a001436, 0x8fbf006c,
- 0x8c626c98, 0x30420100, 0x10400003, 0x24636c98, 0x8c620004, 0xaf62017c,
- 0x3a03000a, 0x2c630001, 0x3a02000c, 0x2c420001, 0x00621825, 0x14600003,
- 0x2402000e, 0x56020030, 0x00009021, 0x52400008, 0x96c4000e, 0x12400004,
- 0xa7b20040, 0x02721021, 0x0a001343, 0x2451ffff, 0x02608821, 0x96c4000e,
- 0x93630035, 0x8f62004c, 0x00642004, 0x00952021, 0x00821023, 0x18400015,
- 0x00000000, 0x8f620018, 0x02621023, 0x1c400015, 0x97a20020, 0x8f620018,
- 0x1662001c, 0x00000000, 0x8f62001c, 0x02a21023, 0x1c40000e, 0x97a20020,
- 0x8f62001c, 0x16a20015, 0x00000000, 0x8f620058, 0x00821023, 0x18400011,
- 0x97a20020, 0x0a001364, 0xafb10028, 0x8f620058, 0x00821023, 0x0441000b,
- 0x97a20020, 0xafb10028, 0xafb30034, 0xafb50038, 0xafa4003c, 0x34420020,
- 0x0a00136d, 0xa7a20020, 0x02809821, 0x02608821, 0x8f640058, 0x8f62004c,
- 0x02a21023, 0x18400009, 0x00000000, 0x8f620054, 0x02a21023, 0x1c400005,
- 0x97a20020, 0xafb10028, 0xafb50024, 0x0a001385, 0x34420040, 0x9742011a,
- 0x1440000c, 0x24020014, 0x8f620058, 0x14820009, 0x24020014, 0x8f63004c,
- 0x8f620054, 0x10620004, 0x97a20020, 0xafb10028, 0x34420080, 0xa7a20020,
- 0x24020014, 0x1202000a, 0x2a020015, 0x10400005, 0x2402000c, 0x12020006,
- 0x32e20001, 0x0a0013c6, 0x00000000, 0x24020016, 0x16020035, 0x32e20001,
- 0x8f620084, 0x24420001, 0x16a20031, 0x32e20001, 0x24020014, 0x12020021,
- 0x2a020015, 0x10400005, 0x2402000c, 0x12020008, 0x32e20001, 0x0a0013c6,
- 0x00000000, 0x24020016, 0x1202000c, 0x32e20001, 0x0a0013c6, 0x00000000,
- 0x97a30020, 0x2402000e, 0xafb10028, 0xa3b00022, 0xa3a20023, 0xafb50024,
- 0x34630054, 0x0a0013c5, 0xa7a30020, 0x97a20020, 0x93a4001a, 0x24030010,
- 0xafb10028, 0xa3b00022, 0xa3a30023, 0xafb50024, 0x3442005d, 0x34840002,
- 0xa7a20020, 0x0a0013c5, 0xa3a4001a, 0x97a20020, 0x24030012, 0xa3a30023,
- 0x93a3001a, 0xafb10028, 0xa3b00022, 0xafb50024, 0x3042fffe, 0x3442005c,
- 0x34630002, 0xa7a20020, 0xa3a3001a, 0x32e20001, 0x10400030, 0x2402000c,
- 0x12020013, 0x2a02000d, 0x10400005, 0x2402000a, 0x12020008, 0x97a20020,
- 0x0a0013f8, 0x32e20009, 0x2402000e, 0x1202001b, 0x32e20009, 0x0a0013f9,
- 0x0002102b, 0x93a4001a, 0x24030008, 0xafb10028, 0xa3b00022, 0xa3a30023,
- 0x0a0013f4, 0x34420013, 0x97a30020, 0x30620004, 0x14400005, 0x93a2001a,
- 0x3463001b, 0xa7a30020, 0x0a0013e7, 0x24030016, 0x3463001b, 0xa7a30020,
- 0x24030010, 0xafb10028, 0xa3b00022, 0xa3a30023, 0x34420002, 0x0a0013f7,
- 0xa3a2001a, 0x97a20020, 0x93a4001a, 0x24030010, 0xafb10028, 0xa3b00022,
- 0xa3a30023, 0x3442001b, 0x34840002, 0xa7a20020, 0xa3a4001a, 0x32e20009,
- 0x0002102b, 0x00021023, 0x30420007, 0x12400015, 0x34450003, 0x8f820018,
- 0x24030800, 0x27440180, 0x24420001, 0xaf820018, 0x24020004, 0xaf4301b8,
- 0xa4850008, 0xa082000b, 0x93430120, 0x00003021, 0x3c021000, 0xa492000e,
- 0xac950024, 0xac930028, 0x007e1821, 0xa483000c, 0xaf4201b8, 0x0a001413,
- 0x97a20020, 0x24060001, 0x97a20020, 0x10400020, 0x27450180, 0x3c038000,
- 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000,
- 0x8fa30028, 0x240240c1, 0xa4a20008, 0xaca30018, 0x93a4001a, 0x24020002,
- 0xa0a2000b, 0xa0a4000a, 0x97a20020, 0xa4a20010, 0x93a30022, 0xa0a30012,
- 0x93a20023, 0xa0a20013, 0x8fa30024, 0xaca30014, 0x8fa20034, 0xaca20024,
- 0x8fa30038, 0xaca30028, 0x8fa2003c, 0x3c031000, 0xaca2002c, 0xaf4301b8,
- 0x00c01021, 0x8fbf006c, 0x8fbe0068, 0x8fb70064, 0x8fb60060, 0x8fb5005c,
- 0x8fb40058, 0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x03e00008,
- 0x27bd0070, 0x8f470140, 0x8f460148, 0x3c028000, 0x00c24024, 0x00062c02,
- 0x30a300ff, 0x24020019, 0x106200e7, 0x27440180, 0x2862001a, 0x1040001f,
- 0x24020008, 0x106200be, 0x28620009, 0x1040000d, 0x24020001, 0x10620046,
- 0x28620002, 0x50400005, 0x24020006, 0x1060002e, 0x00a01821, 0x0a00155e,
- 0x00000000, 0x1062005b, 0x00a01821, 0x0a00155e, 0x00000000, 0x2402000b,
- 0x10620084, 0x2862000c, 0x10400005, 0x24020009, 0x106200bc, 0x00061c02,
- 0x0a00155e, 0x00000000, 0x2402000e, 0x106200b7, 0x00061c02, 0x0a00155e,
- 0x00000000, 0x28620021, 0x10400009, 0x2862001f, 0x104000c1, 0x2402001b,
- 0x106200bf, 0x2402001c, 0x1062009a, 0x00061c02, 0x0a00155e, 0x00000000,
- 0x240200c2, 0x106200ca, 0x286200c3, 0x10400005, 0x24020080, 0x1062005a,
- 0x00a01821, 0x0a00155e, 0x00000000, 0x240200c9, 0x106200cd, 0x30c5ffff,
- 0x0a00155e, 0x00000000, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd,
- 0x24020001, 0xa4830008, 0x24030002, 0xac870000, 0xac800004, 0xa082000a,
- 0xa083000b, 0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, 0xac830024,
- 0x3c036000, 0xaf4201b8, 0x03e00008, 0xac600808, 0x11000009, 0x00a01821,
- 0x3c020800, 0x24030002, 0xa0436c88, 0x24426c88, 0xac470008, 0x8f430144,
- 0x03e00008, 0xac430004, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd,
- 0x24020002, 0xac800000, 0xac870004, 0xa4830008, 0xa082000a, 0xa082000b,
- 0xa4860010, 0xac800024, 0x8f420144, 0x3c031000, 0xac820028, 0x3c026000,
- 0xaf4301b8, 0x03e00008, 0xac400808, 0x3c080800, 0x3c058000, 0x8f4201b8,
- 0x00451024, 0x1440fffd, 0x00000000, 0xac870000, 0x91026c88, 0x00002821,
- 0x10400002, 0x25076c88, 0x8ce50008, 0xac850004, 0xa4830008, 0x91036c88,
- 0x24020002, 0xa082000b, 0xa4860010, 0x34630001, 0xa083000a, 0x8f420144,
- 0xac820024, 0x91036c88, 0x10600002, 0x00001021, 0x8ce20004, 0xac820028,
- 0x3c021000, 0xaf4201b8, 0x3c026000, 0xa1006c88, 0x03e00008, 0xac400808,
- 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xa082000b,
- 0xa4830008, 0xa4860010, 0x8f420144, 0x3c031000, 0xa4820012, 0x03e00008,
- 0xaf4301b8, 0x30c2ffff, 0x14400028, 0x00061c02, 0x93620005, 0x30420004,
- 0x14400020, 0x3c029000, 0x34420001, 0x00e21025, 0xaf420020, 0x3c038000,
- 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000,
- 0x34630001, 0x00e31825, 0x34420004, 0xa3620005, 0xaf430020, 0x93620005,
- 0x30420004, 0x14400003, 0x3c038000, 0x0000000d, 0x3c038000, 0x8f4201b8,
- 0x00431024, 0x1440fffd, 0x24020005, 0x3c031000, 0xac870000, 0xa082000b,
- 0xaf4301b8, 0x0a00150d, 0x00061c02, 0x0000000d, 0x03e00008, 0x00000000,
- 0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001,
- 0xa4830008, 0x24030002, 0xac870000, 0xac800004, 0xa082000a, 0xa083000b,
- 0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, 0xac830024, 0x03e00008,
- 0xaf4201b8, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002,
- 0xac800000, 0xac870004, 0xa4830008, 0xa082000a, 0xa082000b, 0xa4860010,
- 0xac800024, 0x8f420144, 0x3c031000, 0xac820028, 0x03e00008, 0xaf4301b8,
- 0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001,
- 0xa4830008, 0x24030002, 0xa082000a, 0x3c021000, 0xac870000, 0xac800004,
- 0xa083000b, 0xa4860010, 0xac800024, 0xac800028, 0x03e00008, 0xaf4201b8,
- 0x00a01821, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002,
- 0xac870000, 0xac800004, 0xa4830008, 0xa080000a, 0x0a001518, 0xa082000b,
- 0x8f440144, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002,
- 0x240340c9, 0xaf470180, 0xa342018b, 0x3c021000, 0xa7430188, 0xaf4401a4,
- 0xaf4501a8, 0xaf4001ac, 0x03e00008, 0xaf4201b8, 0x0000000d, 0x03e00008,
- 0x00000000, 0x03e00008, 0x00000000, 0x8f420100, 0x3042003e, 0x14400011,
- 0x24020001, 0xaf400048, 0x8f420100, 0x304207c0, 0x10400005, 0x00000000,
- 0xaf40004c, 0xaf400050, 0x03e00008, 0x24020001, 0xaf400054, 0xaf400040,
- 0x8f420100, 0x30423800, 0x54400001, 0xaf400044, 0x24020001, 0x03e00008,
- 0x00000000, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002,
- 0x240340c9, 0xaf440180, 0xa342018b, 0x3c021000, 0xa7430188, 0xaf4501a4,
- 0xaf4601a8, 0xaf4701ac, 0x03e00008, 0xaf4201b8, 0x3c029000, 0x34420001,
- 0x00822025, 0xaf440020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd,
- 0x00000000, 0x03e00008, 0x00000000, 0x3c028000, 0x34420001, 0x00822025,
- 0x03e00008, 0xaf440020, 0x308600ff, 0x27450180, 0x3c038000, 0x8f4201b8,
- 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8f640040,
- 0x24030008, 0x240240c1, 0xa4a20008, 0x24020002, 0xa0a2000b, 0x3c021000,
- 0xa0a6000a, 0xa4a30010, 0xa0a00012, 0xa0a00013, 0xaca00014, 0xaca00024,
- 0xaca00028, 0xaca0002c, 0xaca40018, 0x03e00008, 0xaf4201b8, 0x24020001,
- 0xacc40000, 0x03e00008, 0xa4e50000, 0x24020001, 0xaf400044, 0x03e00008,
- 0xaf400050, 0x00803021, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024,
- 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1,
- 0xa4a20008, 0xaca30018, 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a,
- 0x94c20010, 0xa4a20010, 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013,
- 0x8cc30014, 0xaca30014, 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028,
- 0x8cc2002c, 0x3c031000, 0xaca2002c, 0x24020001, 0xaf4301b8, 0xaf400044,
- 0x03e00008, 0xaf400050, 0x27bdffe8, 0xafbf0010, 0x0e001047, 0x00000000,
- 0x00002021, 0x0e000c78, 0xaf400180, 0x8fbf0010, 0x03e00008, 0x27bd0018,
- 0x8f460148, 0x27450180, 0x3c038000, 0x00061402, 0x304700ff, 0x8f4201b8,
- 0x00431024, 0x1440fffd, 0x00000000, 0x8f440140, 0x00061202, 0x304200ff,
- 0x00061c02, 0xaca20004, 0x24020002, 0xa4a30008, 0x30c300ff, 0xa0a2000b,
- 0xaca30024, 0x10e0000a, 0xaca40000, 0x28e20004, 0x14400005, 0x24020001,
- 0x24020005, 0x54e20005, 0xa0a0000a, 0x24020001, 0x0a001609, 0xa0a2000a,
- 0xa0a0000a, 0x3c021000, 0x03e00008, 0xaf4201b8, 0x03e00008, 0x00001021,
- 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000,
- 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a00161f, 0x00a01021,
- 0xac860000, 0x00000000, 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa,
- 0x24a5ffff, 0x03e00008, 0x00000000, 0x00000000 };
+static u8 bnx2_RXP_b06FwText[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x07, 0x87, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x5d, 0x6c,
+ 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x71, 0x49, 0x91, 0xd4, 0x70, 0xb9,
+ 0x62, 0x57, 0x12, 0x65, 0xed, 0x8a, 0x43, 0x71, 0x6d, 0x31, 0xce, 0x50,
+ 0x58, 0xdb, 0x82, 0xb1, 0x48, 0xc7, 0xb3, 0xa4, 0xc8, 0x24, 0x02, 0x42,
+ 0x1b, 0x42, 0xab, 0xa4, 0xa9, 0xc1, 0x90, 0x72, 0x91, 0x22, 0x2c, 0xa0,
+ 0x1a, 0x79, 0xf0, 0x43, 0x10, 0x2f, 0x56, 0x3f, 0xa6, 0xd1, 0x8d, 0x96,
+ 0xb6, 0x1c, 0x53, 0x08, 0x82, 0x82, 0xe5, 0x52, 0x52, 0x0b, 0x2c, 0xb4,
+ 0x96, 0xed, 0x36, 0x7e, 0xa8, 0x23, 0x9a, 0x92, 0x8d, 0xa6, 0x68, 0x81,
+ 0x22, 0xad, 0xd1, 0xf4, 0x4d, 0x95, 0x9a, 0x4a, 0x75, 0x5f, 0xd4, 0xa2,
+ 0x48, 0xda, 0x46, 0xcd, 0xf4, 0xfb, 0xee, 0xcc, 0x88, 0xd4, 0x9a, 0xb2,
+ 0x2c, 0x3b, 0x0d, 0x62, 0x74, 0x0e, 0x30, 0xd8, 0xb9, 0x7f, 0xe7, 0xef,
+ 0x9e, 0x73, 0xee, 0x39, 0x77, 0x28, 0x7d, 0xa5, 0x43, 0xda, 0x25, 0x84,
+ 0x4e, 0x3c, 0x99, 0xc3, 0xcf, 0x3c, 0xfd, 0xe0, 0xc3, 0x0f, 0xee, 0xc1,
+ 0xeb, 0xb0, 0xa1, 0x6d, 0xd0, 0xa3, 0xfe, 0x18, 0x62, 0x88, 0x21, 0x86,
+ 0x18, 0x62, 0x88, 0x21, 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0x18, 0x62,
+ 0x88, 0x21, 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0x18, 0x62, 0x88, 0x21,
+ 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0x18,
+ 0x62, 0x88, 0x21, 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0x18, 0x62, 0x88,
+ 0x21, 0x86, 0x18, 0x62, 0x88, 0x21, 0x86, 0xff, 0xef, 0x60, 0x88, 0x58,
+ 0xfc, 0xed, 0x0c, 0x1f, 0x49, 0xe8, 0x85, 0xcb, 0x07, 0x3d, 0x5b, 0x12,
+ 0x46, 0x61, 0x69, 0x66, 0xda, 0x16, 0x71, 0xeb, 0xbb, 0x33, 0x45, 0xf9,
+ 0x1f, 0xbf, 0x94, 0x32, 0x85, 0xfd, 0xdb, 0x0b, 0x37, 0x9f, 0x7d, 0xf3,
+ 0x91, 0xec, 0x8d, 0x05, 0x43, 0x12, 0x56, 0xe1, 0xe8, 0xb0, 0xb5, 0x4b,
+ 0x12, 0x7d, 0x58, 0xf3, 0xdd, 0xc1, 0xcf, 0x59, 0xd2, 0x15, 0xe1, 0xba,
+ 0xee, 0xbf, 0x39, 0x68, 0xc9, 0x2b, 0x8d, 0x94, 0x5c, 0x68, 0x6c, 0xdf,
+ 0x24, 0x5d, 0xd9, 0x52, 0x09, 0xfd, 0x6e, 0x8a, 0xe3, 0x96, 0x94, 0xab,
+ 0x2d, 0xe2, 0x2a, 0xba, 0x7d, 0x5a, 0x71, 0xfe, 0x3e, 0xcd, 0x9b, 0x7f,
+ 0x9e, 0xff, 0x1e, 0x24, 0xa5, 0xcb, 0x7d, 0x68, 0xf7, 0xa1, 0xcd, 0xf7,
+ 0x81, 0xf4, 0x94, 0x98, 0x72, 0xa4, 0x91, 0x90, 0xa3, 0xd5, 0x8c, 0xe8,
+ 0x05, 0x71, 0xbd, 0xbc, 0x9d, 0x2e, 0xa3, 0x6f, 0xea, 0x00, 0xdb, 0x29,
+ 0xe0, 0xf9, 0x0e, 0xd7, 0x59, 0x5e, 0x5e, 0x4a, 0xb7, 0xc6, 0x14, 0x0d,
+ 0x8e, 0xb1, 0x0f, 0xbf, 0x58, 0x5f, 0xae, 0x76, 0x00, 0x6f, 0xd6, 0x71,
+ 0x41, 0xdc, 0x73, 0x2c, 0xd0, 0xf6, 0xfd, 0xdf, 0x75, 0x32, 0xb2, 0xe2,
+ 0x74, 0x81, 0xa7, 0x16, 0x69, 0xb5, 0xc5, 0xd2, 0x0b, 0xb6, 0xb5, 0x22,
+ 0x6d, 0x1c, 0xeb, 0x34, 0x0a, 0xbe, 0x3f, 0x9d, 0x97, 0xae, 0xa0, 0x6f,
+ 0xb7, 0xe2, 0x63, 0x72, 0x42, 0xc3, 0xbc, 0x57, 0x49, 0x0f, 0x3a, 0xe2,
+ 0x3b, 0x7f, 0xf3, 0x52, 0xac, 0x6c, 0x97, 0xc9, 0x54, 0xf6, 0xa0, 0x1b,
+ 0xd0, 0x74, 0x3d, 0x67, 0x2b, 0x70, 0x6a, 0xe0, 0x4f, 0xdb, 0x81, 0xf5,
+ 0xee, 0x0a, 0x68, 0x1a, 0x85, 0xcd, 0x62, 0x6c, 0x66, 0x9f, 0xe8, 0x3b,
+ 0x87, 0x93, 0xe1, 0x78, 0x97, 0x36, 0x32, 0x6f, 0x88, 0x6e, 0xff, 0x81,
+ 0xe6, 0xd5, 0x7a, 0xe5, 0xd8, 0xbc, 0x8e, 0x77, 0x5d, 0xae, 0xe6, 0x4b,
+ 0x9a, 0xdb, 0xa8, 0x68, 0xde, 0xd9, 0x59, 0xad, 0x78, 0xd6, 0x94, 0xa3,
+ 0xb6, 0x7f, 0xe1, 0xb4, 0x73, 0x42, 0x1b, 0x39, 0x7b, 0x46, 0x1b, 0x3d,
+ 0xfb, 0x86, 0x36, 0xde, 0xd8, 0xb2, 0x49, 0xda, 0xb3, 0xd0, 0x1e, 0x71,
+ 0x90, 0xbf, 0x4f, 0x87, 0xba, 0xec, 0xa2, 0xde, 0x4a, 0xe4, 0x7d, 0x9f,
+ 0xf3, 0x86, 0xe6, 0x55, 0x6d, 0x8b, 0xfb, 0xe6, 0xa6, 0x22, 0x1a, 0xed,
+ 0x72, 0x74, 0xde, 0x94, 0x63, 0xd5, 0x94, 0x3c, 0x57, 0x2d, 0x29, 0x5a,
+ 0x86, 0x5d, 0xd2, 0xbc, 0x06, 0xc7, 0x2b, 0xa0, 0x75, 0x42, 0xdb, 0x07,
+ 0x9a, 0xde, 0x59, 0x29, 0x5d, 0x71, 0xe6, 0x40, 0xaf, 0x03, 0x78, 0xff,
+ 0x58, 0x1b, 0x6d, 0xf4, 0x6a, 0xde, 0xc9, 0x9b, 0xe2, 0x39, 0x59, 0xeb,
+ 0x4b, 0x62, 0xba, 0xb0, 0x01, 0xc8, 0x0c, 0xfd, 0x38, 0xd0, 0x49, 0xca,
+ 0xf7, 0xf5, 0x82, 0xff, 0x2c, 0x74, 0x6f, 0x5d, 0xa1, 0xfc, 0x8d, 0x5e,
+ 0x29, 0xcf, 0x53, 0xd7, 0xa6, 0x36, 0x52, 0xf5, 0x2f, 0x78, 0x8e, 0xf4,
+ 0x19, 0xe2, 0xfb, 0x47, 0x9d, 0x81, 0xf4, 0x21, 0x39, 0x03, 0xdc, 0x75,
+ 0xad, 0xd8, 0xa0, 0xae, 0xc1, 0xdf, 0x2d, 0x39, 0x02, 0xbd, 0x15, 0x9d,
+ 0x5e, 0x99, 0xb4, 0xb2, 0x2e, 0xf6, 0x68, 0x53, 0x20, 0x57, 0x32, 0xb4,
+ 0x17, 0xd2, 0xe7, 0xde, 0x67, 0xd3, 0x9e, 0xa1, 0xcb, 0x53, 0x2f, 0x3d,
+ 0xdf, 0xb3, 0x38, 0xb4, 0x91, 0x32, 0x43, 0xff, 0xf2, 0x45, 0xcf, 0xf6,
+ 0xb6, 0xb4, 0x48, 0x29, 0x6d, 0x48, 0x16, 0xfb, 0xb4, 0x43, 0x4e, 0x3b,
+ 0x22, 0x87, 0x2a, 0xd0, 0x8d, 0x6d, 0x5a, 0x8b, 0x62, 0x67, 0xca, 0x32,
+ 0x50, 0x32, 0x75, 0x74, 0x26, 0x49, 0x97, 0x3a, 0xd2, 0xe5, 0x7a, 0x9e,
+ 0x7a, 0xa2, 0x3d, 0x7f, 0x28, 0x5d, 0x69, 0xab, 0xba, 0x5a, 0xd5, 0xd3,
+ 0xf8, 0x2f, 0x5d, 0x4f, 0xd4, 0xc9, 0x72, 0x28, 0xb7, 0x03, 0xdc, 0x8f,
+ 0x40, 0x5f, 0xe2, 0xea, 0xc3, 0x0f, 0xb1, 0x6f, 0x93, 0x51, 0xb0, 0xd3,
+ 0x17, 0x61, 0x14, 0x7a, 0x61, 0x37, 0x64, 0x19, 0xa6, 0xee, 0xe0, 0xc3,
+ 0x1f, 0x49, 0x5e, 0xf9, 0xd5, 0x90, 0x97, 0xfc, 0xdb, 0x32, 0x55, 0x49,
+ 0x80, 0x06, 0x65, 0xd4, 0xe5, 0xbd, 0x7c, 0x64, 0x1b, 0x7b, 0x20, 0x5f,
+ 0x5e, 0xa6, 0xbe, 0x45, 0x7f, 0xa2, 0xfd, 0xf3, 0x9d, 0xb2, 0xfe, 0xcc,
+ 0xbf, 0xee, 0x7c, 0x92, 0xf6, 0x96, 0x7c, 0x27, 0xe4, 0x78, 0x35, 0xc9,
+ 0x3d, 0xd4, 0x56, 0x54, 0x6c, 0x8a, 0x64, 0x14, 0xdd, 0x28, 0x74, 0x48,
+ 0x51, 0xed, 0xf7, 0x5e, 0xd0, 0x43, 0x2c, 0xa8, 0xf2, 0xbd, 0xa0, 0x64,
+ 0x9b, 0xb6, 0xed, 0xcc, 0x11, 0xc9, 0xc2, 0xbe, 0x45, 0x8e, 0xcc, 0x99,
+ 0x32, 0x6d, 0xff, 0x63, 0xa7, 0xb4, 0x2f, 0xdf, 0x6f, 0xa8, 0xb8, 0xae,
+ 0xf7, 0x6e, 0x90, 0x4d, 0xe0, 0x77, 0xf9, 0x7e, 0x5d, 0xe4, 0xa6, 0x59,
+ 0xc8, 0x5a, 0x23, 0x08, 0xf6, 0x46, 0x81, 0xb1, 0x4c, 0x43, 0x2c, 0x93,
+ 0x44, 0x8b, 0x4d, 0x7d, 0xf9, 0xfe, 0xf8, 0xf0, 0xdd, 0xf5, 0x75, 0x64,
+ 0x9e, 0xb4, 0xa9, 0x2f, 0xc6, 0xa8, 0x12, 0xf4, 0xc1, 0xf8, 0x74, 0xbb,
+ 0xae, 0x8a, 0xa1, 0xae, 0x46, 0xfe, 0xef, 0xed, 0xc2, 0xf5, 0xaa, 0xa2,
+ 0x79, 0xce, 0xbb, 0xa1, 0x2f, 0xd8, 0x32, 0x02, 0x7f, 0x37, 0xec, 0x4f,
+ 0xcb, 0x91, 0x54, 0x76, 0xc2, 0x95, 0xc0, 0xe6, 0xaf, 0xad, 0xb1, 0xf9,
+ 0xd1, 0xbb, 0xc8, 0x75, 0x3c, 0x94, 0xcb, 0x0d, 0xe5, 0x1a, 0x85, 0x5c,
+ 0x63, 0x90, 0x6b, 0xe5, 0x23, 0xc8, 0xb5, 0xf2, 0x91, 0xe5, 0xd2, 0xa4,
+ 0xec, 0x3c, 0x08, 0x5a, 0xa6, 0xfc, 0xab, 0x13, 0xd8, 0xf2, 0xbf, 0x38,
+ 0x9f, 0x14, 0x19, 0x7c, 0x7f, 0x70, 0xd8, 0x16, 0xef, 0x5b, 0xe0, 0xd5,
+ 0x71, 0x40, 0x8b, 0xef, 0xef, 0x97, 0xe1, 0x6e, 0xfe, 0x38, 0x8b, 0x7d,
+ 0x5d, 0xcf, 0x1f, 0x29, 0x87, 0x3e, 0x7c, 0xef, 0xfe, 0xa8, 0x6b, 0x1f,
+ 0x55, 0x0e, 0xc6, 0x9c, 0x4f, 0x35, 0x9d, 0xab, 0x1f, 0x56, 0x86, 0xf5,
+ 0x63, 0xca, 0x2f, 0x4f, 0x86, 0xc7, 0x64, 0x72, 0x33, 0xed, 0xa9, 0xa4,
+ 0x8d, 0x0c, 0x92, 0xef, 0xb5, 0xfc, 0x4a, 0x26, 0xe0, 0x0d, 0x39, 0xd1,
+ 0xd2, 0x46, 0x39, 0xb2, 0x60, 0x49, 0x69, 0xe9, 0x4e, 0x71, 0x57, 0x03,
+ 0x6f, 0xb4, 0x47, 0xf6, 0x7d, 0xd2, 0x7c, 0x2a, 0xc8, 0x2b, 0x2e, 0x54,
+ 0x91, 0x83, 0x56, 0x13, 0x72, 0xd9, 0x48, 0xcb, 0x9b, 0x83, 0x87, 0xe5,
+ 0xf3, 0xd5, 0x24, 0xe8, 0x31, 0x9f, 0x2c, 0xe7, 0x10, 0x17, 0xb5, 0xb2,
+ 0x63, 0x08, 0x79, 0xaf, 0xd9, 0x9c, 0x13, 0xc4, 0x96, 0x72, 0x10, 0x83,
+ 0x5d, 0x6f, 0x50, 0xe5, 0x14, 0x90, 0x4f, 0x64, 0x0c, 0xb1, 0xb7, 0x66,
+ 0xb3, 0xcd, 0xfe, 0xa0, 0xef, 0xb3, 0x95, 0x5e, 0xad, 0xc8, 0xbc, 0x64,
+ 0xf0, 0xa6, 0x4c, 0x3b, 0x41, 0xdf, 0xe7, 0x2a, 0xa3, 0x9b, 0x98, 0x1f,
+ 0x1a, 0x05, 0xc9, 0x94, 0x9d, 0xf7, 0x7c, 0xd7, 0xba, 0x7d, 0xcd, 0xfa,
+ 0x78, 0xb2, 0x13, 0x81, 0xce, 0x45, 0xfb, 0xaa, 0xad, 0xf7, 0xb6, 0x4a,
+ 0x09, 0x27, 0x5d, 0xd6, 0x1a, 0x47, 0xe7, 0xbe, 0x4a, 0x79, 0x5b, 0xab,
+ 0xdc, 0x34, 0x80, 0x3f, 0x6d, 0x68, 0x62, 0x1e, 0xaa, 0x94, 0xbb, 0xd9,
+ 0xa6, 0xbe, 0x74, 0x4d, 0x12, 0xa3, 0x15, 0x5f, 0xae, 0x3a, 0x41, 0xee,
+ 0x63, 0x68, 0x7a, 0x6f, 0x5b, 0xb8, 0x56, 0xd7, 0x76, 0x39, 0x97, 0x44,
+ 0x3a, 0x0e, 0x55, 0xc4, 0x2a, 0x56, 0x76, 0x39, 0x6f, 0x4b, 0xb9, 0xa7,
+ 0x6d, 0x75, 0x5d, 0x8a, 0xeb, 0x76, 0x0e, 0xaf, 0x9d, 0xbb, 0xcb, 0xb9,
+ 0x28, 0xe5, 0x2d, 0x6d, 0xab, 0xb4, 0xd2, 0x58, 0xdb, 0x17, 0xac, 0xe5,
+ 0xf8, 0x66, 0x71, 0xbb, 0x39, 0x47, 0xef, 0x6d, 0xbf, 0x45, 0x43, 0x32,
+ 0xc5, 0x4a, 0xb9, 0xa7, 0x7d, 0x15, 0xaf, 0x4d, 0xbc, 0xde, 0x1a, 0xbc,
+ 0xc4, 0xd9, 0xbe, 0x8a, 0x33, 0x07, 0x9c, 0x43, 0xab, 0x38, 0x39, 0x7e,
+ 0x58, 0x8a, 0x38, 0xd3, 0x5a, 0x0a, 0x32, 0xbc, 0x54, 0xc9, 0x48, 0x79,
+ 0x28, 0x01, 0xdd, 0xf7, 0x1f, 0xfc, 0x9a, 0xaa, 0x43, 0xcc, 0x61, 0x0f,
+ 0xba, 0x32, 0x55, 0x5e, 0x87, 0xd8, 0x08, 0xdb, 0xf8, 0x5a, 0x5d, 0x86,
+ 0x17, 0xeb, 0xa6, 0x1c, 0x6f, 0x70, 0xbf, 0x98, 0xe3, 0x05, 0x75, 0xc6,
+ 0x85, 0x46, 0x4e, 0xdb, 0x87, 0xbd, 0x66, 0x9d, 0xb0, 0xaf, 0x61, 0x6a,
+ 0xa3, 0x3c, 0x1f, 0x80, 0x97, 0x76, 0x7e, 0xac, 0x41, 0xdb, 0x79, 0x03,
+ 0xb6, 0x41, 0xce, 0xa3, 0x9c, 0xbd, 0x95, 0xb9, 0x53, 0x66, 0xd1, 0x51,
+ 0x75, 0x88, 0x56, 0xcb, 0x77, 0x20, 0x07, 0x4d, 0xa0, 0xd6, 0x80, 0xcd,
+ 0xdb, 0x78, 0x6f, 0x70, 0xde, 0x32, 0xe6, 0x6d, 0xe0, 0x3c, 0xec, 0xcd,
+ 0x25, 0xe5, 0x0f, 0xa6, 0xcd, 0xf1, 0x77, 0xb1, 0xc7, 0x68, 0xd7, 0x59,
+ 0x57, 0x58, 0x02, 0x5f, 0xc1, 0x3e, 0xa2, 0x6e, 0x48, 0xed, 0x60, 0x7e,
+ 0x8f, 0xb9, 0x19, 0xcc, 0xcd, 0x66, 0x18, 0xcf, 0x3d, 0xfb, 0x99, 0x0e,
+ 0xe9, 0x42, 0xbb, 0xce, 0x35, 0xd9, 0x0c, 0x72, 0x5b, 0xdf, 0xcb, 0xb7,
+ 0xc9, 0x4a, 0xca, 0xbf, 0x60, 0xd8, 0xd1, 0xdc, 0x08, 0x6f, 0xf3, 0x5c,
+ 0xe6, 0xc5, 0xc4, 0xbd, 0x21, 0xcc, 0x83, 0xc7, 0xc5, 0x6d, 0xfc, 0x49,
+ 0xb7, 0x74, 0xb9, 0xf8, 0x8d, 0xe6, 0x4c, 0x6f, 0x0e, 0x6a, 0x2e, 0xbe,
+ 0xb7, 0x50, 0x3e, 0x17, 0xe7, 0xa1, 0x56, 0xac, 0x66, 0x26, 0x59, 0x1f,
+ 0x15, 0xeb, 0x6c, 0xef, 0x85, 0x3f, 0x04, 0x75, 0xd7, 0x85, 0x5b, 0xbe,
+ 0x70, 0x19, 0x7a, 0x4b, 0x43, 0x6f, 0x29, 0x39, 0xdf, 0x60, 0x9d, 0xe6,
+ 0x42, 0x5f, 0x19, 0xf1, 0x1a, 0xe3, 0x58, 0x2b, 0x87, 0x81, 0x03, 0x3a,
+ 0x17, 0x47, 0x2f, 0x64, 0x65, 0xca, 0xda, 0x1d, 0xf1, 0x00, 0x5c, 0x88,
+ 0x1f, 0x85, 0x36, 0xf4, 0xf1, 0x1d, 0x9a, 0x53, 0xff, 0x86, 0x7f, 0x94,
+ 0xed, 0x09, 0xbd, 0x30, 0xd6, 0xd4, 0xbf, 0x6e, 0xfc, 0xa1, 0x1c, 0x68,
+ 0x33, 0x06, 0x31, 0xfe, 0xe8, 0xa8, 0xf3, 0x18, 0x8b, 0x48, 0xd7, 0x92,
+ 0x23, 0x4b, 0x23, 0xdc, 0x37, 0x8b, 0xf1, 0xa7, 0x5c, 0xe7, 0x9e, 0x29,
+ 0x5c, 0xc0, 0x19, 0xad, 0xf1, 0xfd, 0x11, 0x87, 0x6b, 0x7c, 0x99, 0x70,
+ 0x3a, 0xc4, 0x48, 0x96, 0xb4, 0xc7, 0x07, 0x11, 0x7b, 0x1e, 0xe0, 0x3e,
+ 0x32, 0x06, 0x6d, 0x17, 0xb0, 0xea, 0xb4, 0x3c, 0x3c, 0xc8, 0x75, 0xa0,
+ 0xdd, 0x2a, 0x7a, 0x92, 0x34, 0xf3, 0x21, 0x4f, 0x43, 0xdd, 0x81, 0xbe,
+ 0x06, 0xac, 0x40, 0x7f, 0x9f, 0xe9, 0x5e, 0xd5, 0x1f, 0xd7, 0x35, 0xf3,
+ 0xcb, 0x18, 0x96, 0x90, 0x81, 0x33, 0x1b, 0x65, 0xe7, 0xa2, 0x25, 0xf6,
+ 0x99, 0x55, 0xfe, 0x76, 0x9e, 0x5b, 0xcb, 0x5f, 0xf4, 0x7f, 0x15, 0x5c,
+ 0xd0, 0xc5, 0x8e, 0xfa, 0x1e, 0x4b, 0x05, 0xb8, 0xa3, 0xf6, 0x7b, 0xe1,
+ 0x5e, 0xf1, 0xfd, 0x99, 0x70, 0x4f, 0xb0, 0x07, 0x88, 0x95, 0xe7, 0x6f,
+ 0xc5, 0xa9, 0x0c, 0xf6, 0x06, 0xb6, 0xa7, 0xe2, 0x11, 0xe3, 0x18, 0xed,
+ 0xbb, 0x63, 0xd2, 0x2c, 0xb0, 0x8e, 0xe6, 0x3e, 0xc9, 0x44, 0xb9, 0x22,
+ 0xa5, 0xad, 0x85, 0x67, 0x7d, 0xd8, 0xcf, 0xa4, 0xa5, 0x6c, 0xaf, 0x63,
+ 0xaf, 0x97, 0x37, 0xa0, 0x1b, 0x8c, 0xc1, 0x26, 0xf5, 0x42, 0x42, 0x8a,
+ 0x8d, 0x44, 0xc2, 0x3c, 0x31, 0xf0, 0x23, 0xcf, 0x48, 0x24, 0xf4, 0x13,
+ 0x81, 0x9d, 0x4d, 0xd6, 0x6f, 0x20, 0x56, 0x6a, 0x72, 0x74, 0xe8, 0x86,
+ 0xcf, 0x1a, 0xd8, 0xdb, 0x0b, 0x9b, 0x1b, 0x82, 0xcf, 0x80, 0x8f, 0x72,
+ 0xa3, 0xa3, 0x37, 0xe0, 0xed, 0x2b, 0x11, 0x8f, 0xa6, 0x8e, 0xdc, 0xd3,
+ 0xcb, 0xfb, 0xbe, 0x51, 0xd8, 0x90, 0x98, 0xce, 0x8f, 0x6f, 0xd1, 0xcf,
+ 0xed, 0xdf, 0x62, 0x9c, 0x2b, 0x6d, 0x01, 0x3e, 0xdd, 0xcb, 0xe3, 0xf7,
+ 0x9c, 0xc8, 0x44, 0x15, 0x3a, 0xdf, 0x03, 0x3d, 0x59, 0xf0, 0xc5, 0x3d,
+ 0xa6, 0xca, 0xd1, 0xf5, 0x3d, 0x2f, 0x6e, 0x0a, 0x70, 0xf0, 0xfd, 0x27,
+ 0x7e, 0x70, 0x86, 0x5e, 0x0e, 0xfb, 0x7e, 0x3f, 0xdc, 0x87, 0x5f, 0x45,
+ 0xb9, 0x78, 0x5e, 0x44, 0xb2, 0xad, 0x3d, 0x37, 0xb2, 0xe3, 0x25, 0x9c,
+ 0x33, 0xa7, 0x1d, 0xdf, 0x7f, 0x07, 0xcf, 0x35, 0xa7, 0xd9, 0x46, 0xde,
+ 0x7f, 0xf6, 0x31, 0x07, 0xf8, 0x2c, 0xce, 0xbd, 0xd1, 0xa6, 0xb3, 0xff,
+ 0x5e, 0xcf, 0xbd, 0x7b, 0x3f, 0xfb, 0xc9, 0xf3, 0x1d, 0x7d, 0xef, 0x03,
+ 0xce, 0xfe, 0x0f, 0x5c, 0x77, 0x0f, 0x3e, 0x1b, 0xd8, 0x6d, 0xb1, 0xd1,
+ 0x1c, 0x5f, 0xee, 0xd5, 0x7f, 0x7f, 0xad, 0xfb, 0x76, 0xff, 0xb5, 0xbb,
+ 0x6f, 0xf7, 0xdf, 0xcd, 0xdd, 0xbf, 0x18, 0xff, 0xcd, 0x01, 0x0f, 0x7d,
+ 0x70, 0xad, 0xff, 0xae, 0xe7, 0x93, 0xd4, 0xf7, 0xf3, 0x3d, 0xe5, 0xa1,
+ 0xce, 0x30, 0x1f, 0x52, 0xe7, 0xf5, 0x17, 0xa7, 0x6d, 0xef, 0x7e, 0x53,
+ 0x4a, 0xb9, 0x16, 0xc9, 0xe6, 0x6a, 0xb2, 0x43, 0x8e, 0x3b, 0x22, 0x4b,
+ 0xaa, 0x16, 0x31, 0x51, 0x8b, 0x0f, 0xa0, 0x3e, 0x0b, 0xf4, 0xba, 0xa4,
+ 0xf4, 0xf2, 0x02, 0x78, 0x89, 0xf0, 0x74, 0xdd, 0x05, 0x0f, 0x71, 0x10,
+ 0x17, 0xf1, 0x0c, 0xe2, 0x7c, 0xb7, 0xd7, 0xc1, 0x85, 0x73, 0xea, 0x25,
+ 0xd4, 0x64, 0xb6, 0xde, 0xa3, 0x07, 0x67, 0xb2, 0x5b, 0x96, 0xdd, 0xe9,
+ 0xeb, 0xf2, 0x05, 0x9e, 0x59, 0x0a, 0xae, 0xce, 0x21, 0x56, 0x0f, 0x8d,
+ 0x85, 0x75, 0xd2, 0xdc, 0x41, 0xcf, 0x8e, 0xee, 0x49, 0x78, 0x47, 0x92,
+ 0x90, 0x92, 0x9a, 0xb5, 0x04, 0x1d, 0x68, 0x72, 0x0d, 0x67, 0xd0, 0xd5,
+ 0xb9, 0x76, 0xe0, 0x45, 0xee, 0x77, 0x20, 0xbb, 0x57, 0xb4, 0x7e, 0xab,
+ 0x55, 0x6b, 0x87, 0x2f, 0x65, 0xc4, 0x55, 0x6d, 0x9e, 0xd3, 0xa7, 0x66,
+ 0x16, 0x2b, 0xc8, 0x03, 0x6d, 0x9c, 0xaf, 0x79, 0xbc, 0xd7, 0x49, 0x43,
+ 0x93, 0x2b, 0x73, 0xba, 0xfc, 0xd3, 0x9c, 0x21, 0xff, 0x8c, 0x3a, 0xf4,
+ 0x9a, 0x7d, 0x6a, 0xe6, 0xb4, 0x2d, 0xf7, 0x81, 0xd5, 0xf0, 0x0e, 0x4f,
+ 0x76, 0x9a, 0x42, 0x5b, 0x1d, 0x48, 0xff, 0x8e, 0x20, 0xff, 0xc1, 0x9a,
+ 0x2b, 0x73, 0xa4, 0xb5, 0x76, 0x8d, 0xf4, 0x22, 0x1f, 0x83, 0x5d, 0x0f,
+ 0x30, 0x27, 0xe2, 0x7c, 0xd4, 0xab, 0x03, 0xd6, 0x3e, 0xc5, 0x5b, 0x42,
+ 0x16, 0xeb, 0x9c, 0x6f, 0x82, 0xb7, 0x2e, 0x9c, 0x31, 0x59, 0x6b, 0x52,
+ 0xfe, 0xb0, 0x5b, 0xe5, 0xaa, 0x1a, 0xfb, 0x0d, 0xb5, 0xc7, 0xef, 0xef,
+ 0xe7, 0xde, 0x1b, 0x32, 0x95, 0x62, 0x9b, 0x63, 0x59, 0xd4, 0x9c, 0xc4,
+ 0x97, 0xdd, 0xeb, 0x0a, 0x79, 0x0e, 0xde, 0xaf, 0x08, 0x65, 0xdb, 0x6d,
+ 0x5d, 0x97, 0xd7, 0x7d, 0xf7, 0x00, 0xe5, 0x89, 0x72, 0x8b, 0x39, 0x9f,
+ 0xb1, 0xd8, 0x28, 0xcc, 0xc0, 0x8e, 0xbf, 0x2a, 0xdf, 0x6f, 0x1c, 0x92,
+ 0xef, 0x35, 0x26, 0xe5, 0xcf, 0x1a, 0x5f, 0x96, 0x3f, 0x6d, 0x1c, 0x94,
+ 0xd7, 0x1b, 0x07, 0xe4, 0xb5, 0xc6, 0x84, 0xbc, 0xda, 0xd8, 0x0f, 0x1b,
+ 0x1f, 0x87, 0x8d, 0x9f, 0x9a, 0x99, 0xac, 0xf7, 0xcb, 0xd4, 0x49, 0xc4,
+ 0x20, 0xe7, 0x1b, 0xba, 0xba, 0xe3, 0xb3, 0xe9, 0xe7, 0x2d, 0x32, 0xad,
+ 0xee, 0xaf, 0x34, 0xe4, 0x89, 0x2d, 0xbc, 0x2b, 0x7c, 0xc5, 0x33, 0x2e,
+ 0x87, 0xf1, 0xe8, 0xe1, 0x94, 0xb4, 0x03, 0xbf, 0xca, 0x4b, 0x4d, 0x9e,
+ 0xdb, 0x62, 0x86, 0xf7, 0x9c, 0x87, 0x24, 0xc9, 0xfb, 0xb0, 0x9c, 0x67,
+ 0xa0, 0xde, 0x5e, 0xd7, 0x27, 0x73, 0xb4, 0x65, 0xe8, 0xc6, 0x95, 0x43,
+ 0xb0, 0x53, 0xc3, 0x7e, 0xcb, 0xa5, 0x1e, 0x16, 0x97, 0x28, 0xf7, 0x46,
+ 0x59, 0x5c, 0xa0, 0x6f, 0xff, 0x1b, 0x64, 0x6c, 0x97, 0xda, 0x82, 0x89,
+ 0xb9, 0x6e, 0x98, 0xab, 0x6c, 0xa7, 0x3d, 0x00, 0x1f, 0xf1, 0x7e, 0x10,
+ 0x4e, 0xab, 0x09, 0x27, 0xf1, 0x24, 0x54, 0x0c, 0x08, 0x70, 0x5b, 0x52,
+ 0x5b, 0x4a, 0xca, 0xc2, 0x42, 0x0f, 0x9e, 0x94, 0x2c, 0xd4, 0x6d, 0x3c,
+ 0x39, 0x3c, 0x43, 0x78, 0xd2, 0xb0, 0x53, 0xca, 0xc8, 0xd8, 0x12, 0xc9,
+ 0x88, 0x78, 0x5c, 0xed, 0x0d, 0x6b, 0x2a, 0xf2, 0xa3, 0x85, 0xfc, 0x74,
+ 0x87, 0x7d, 0x1d, 0x52, 0xab, 0x38, 0x32, 0x55, 0xfd, 0x94, 0x3e, 0xa5,
+ 0x74, 0x07, 0xfc, 0x95, 0x21, 0xb4, 0xef, 0x0f, 0xdb, 0x8f, 0xca, 0xf4,
+ 0xbc, 0xc8, 0xca, 0xcb, 0x03, 0x7a, 0x51, 0xb5, 0xf7, 0xa2, 0xad, 0xa3,
+ 0x9d, 0x0d, 0xdb, 0xcc, 0x8f, 0x0e, 0xe0, 0x71, 0xd5, 0xf3, 0xf5, 0xea,
+ 0xb8, 0x3c, 0x55, 0xed, 0x77, 0x5e, 0x87, 0xcd, 0xbd, 0x65, 0x46, 0xf7,
+ 0xd2, 0x04, 0x24, 0x79, 0xf6, 0x56, 0x75, 0xf7, 0xf1, 0x04, 0xe2, 0xad,
+ 0x9b, 0x34, 0xe5, 0x6f, 0x4f, 0x64, 0xad, 0xa7, 0xf5, 0x5c, 0x52, 0xda,
+ 0x7d, 0xff, 0x71, 0x3b, 0x3b, 0x3b, 0xa9, 0x77, 0xca, 0xdf, 0xbf, 0x98,
+ 0x91, 0x85, 0xb3, 0x5b, 0x65, 0xa1, 0x06, 0x99, 0x1a, 0xbf, 0x8e, 0x7d,
+ 0x35, 0xe5, 0xea, 0x9e, 0x47, 0xb1, 0x27, 0x8c, 0x5d, 0x49, 0xe4, 0x6c,
+ 0x1b, 0xc4, 0xec, 0x25, 0x5d, 0x49, 0x98, 0x85, 0x9c, 0x1c, 0x81, 0xdf,
+ 0x4f, 0xdb, 0xb9, 0x1e, 0x69, 0xc7, 0x7b, 0x7d, 0x04, 0x7c, 0x5b, 0x32,
+ 0xd5, 0x6b, 0xc9, 0x99, 0xc1, 0x68, 0xff, 0xb6, 0x62, 0x6e, 0x46, 0x16,
+ 0xcf, 0x66, 0xf0, 0x9b, 0x83, 0xfd, 0xec, 0x94, 0x57, 0x6a, 0xfd, 0xb2,
+ 0x54, 0xdb, 0x2a, 0x8b, 0xb5, 0xe6, 0x7d, 0xe8, 0xec, 0x09, 0xe2, 0x1d,
+ 0xf1, 0xf4, 0x5b, 0x53, 0xfa, 0x56, 0x71, 0xcd, 0x7e, 0xeb, 0x29, 0xfd,
+ 0x1f, 0xe4, 0x31, 0x33, 0xa0, 0xa9, 0x17, 0x7e, 0xa4, 0xee, 0x84, 0x26,
+ 0x79, 0xf6, 0x2a, 0xbc, 0x4f, 0x26, 0x49, 0xfb, 0xf5, 0xc6, 0x07, 0xd1,
+ 0x59, 0xcb, 0xcf, 0x9d, 0x68, 0x52, 0x06, 0xe2, 0xec, 0xbf, 0x71, 0x52,
+ 0xef, 0x95, 0xe5, 0x6d, 0x0f, 0x58, 0x4f, 0xea, 0xad, 0x88, 0x01, 0x3f,
+ 0x97, 0x9f, 0xee, 0xd9, 0x24, 0x3f, 0xfc, 0xcd, 0xec, 0xa9, 0x6f, 0x22,
+ 0xd9, 0xbf, 0xb2, 0xa7, 0x83, 0x71, 0x01, 0xef, 0xec, 0xcf, 0xde, 0x70,
+ 0x75, 0xea, 0xe1, 0x2f, 0xa0, 0x87, 0xec, 0x9c, 0xba, 0x9b, 0x56, 0x3c,
+ 0x90, 0x3e, 0xf5, 0x52, 0x06, 0x6f, 0x18, 0xab, 0xf7, 0x03, 0x57, 0x59,
+ 0xe9, 0xf9, 0x09, 0x27, 0x7b, 0x03, 0xe9, 0xb0, 0xbf, 0x68, 0xf7, 0xa7,
+ 0x77, 0xea, 0x3b, 0x64, 0x32, 0xfd, 0x80, 0xf5, 0xb4, 0x6c, 0x21, 0xce,
+ 0xd9, 0x05, 0xc1, 0xda, 0x79, 0xe2, 0xfb, 0x2b, 0xe0, 0x0b, 0x70, 0x28,
+ 0xff, 0x51, 0x38, 0x77, 0x59, 0x5f, 0xd7, 0x79, 0xc6, 0x63, 0x0c, 0x71,
+ 0xe1, 0xe2, 0x10, 0x65, 0x40, 0x82, 0x95, 0xca, 0xa6, 0x5d, 0xfd, 0xc3,
+ 0xc8, 0x47, 0xfc, 0xfd, 0x56, 0x51, 0x27, 0x0f, 0xe7, 0xc0, 0xcb, 0x4f,
+ 0xc0, 0x7f, 0x3f, 0x70, 0xa2, 0xf6, 0x48, 0x47, 0x74, 0xff, 0x4e, 0xd1,
+ 0x7d, 0xad, 0x21, 0xe6, 0x2a, 0x5d, 0xf4, 0xd5, 0x75, 0xc8, 0xdd, 0x07,
+ 0x7b, 0xb5, 0xf0, 0xcb, 0xbd, 0xe9, 0x0c, 0xf7, 0x98, 0xeb, 0x22, 0xba,
+ 0x11, 0xbf, 0x5c, 0x73, 0x27, 0x1e, 0xee, 0x75, 0x3e, 0xea, 0xd4, 0x03,
+ 0x09, 0x79, 0xf7, 0x44, 0xb4, 0x37, 0x07, 0x64, 0xba, 0x0a, 0xdd, 0xed,
+ 0xea, 0x0f, 0xfc, 0x27, 0x1d, 0xf1, 0x40, 0xde, 0xff, 0x06, 0xbc, 0x07,
+ 0xb8, 0x5b, 0x0b, 0xcd, 0xba, 0xc3, 0x58, 0x3d, 0xa0, 0x31, 0xb6, 0x0e,
+ 0x4f, 0x57, 0xf6, 0x44, 0xbe, 0x98, 0x84, 0x5f, 0xed, 0xb6, 0x9e, 0x10,
+ 0xd6, 0x63, 0xc4, 0x9b, 0x94, 0x1f, 0xbe, 0x0c, 0x1e, 0x92, 0xf4, 0x93,
+ 0x7f, 0x5f, 0xe3, 0x27, 0x1c, 0xdb, 0x2a, 0x35, 0xd4, 0xd4, 0x5e, 0xde,
+ 0x94, 0x69, 0x25, 0x03, 0xda, 0x35, 0xfa, 0x77, 0x29, 0xf4, 0xef, 0x47,
+ 0x80, 0xa3, 0x5d, 0x8c, 0x47, 0x1f, 0xc7, 0x59, 0x9d, 0xcd, 0x2c, 0xeb,
+ 0xcc, 0x03, 0x76, 0x4b, 0x51, 0xdd, 0x4f, 0xdf, 0x8b, 0xee, 0xa2, 0xd8,
+ 0x94, 0x96, 0x8b, 0x95, 0x28, 0x2e, 0xa5, 0x71, 0x9e, 0xb4, 0xcb, 0xa5,
+ 0xb9, 0x28, 0xe6, 0xb5, 0xcb, 0x12, 0xf2, 0x9a, 0x95, 0x97, 0x2c, 0x8c,
+ 0x25, 0xe5, 0xe2, 0x5c, 0x12, 0x31, 0xab, 0x47, 0x56, 0xe6, 0x7a, 0x30,
+ 0x96, 0xc2, 0xba, 0x14, 0xe6, 0xdb, 0xb2, 0x52, 0xb1, 0x81, 0x27, 0x87,
+ 0x76, 0x0e, 0xed, 0x21, 0xb9, 0xa4, 0xbe, 0x17, 0x30, 0x2f, 0x18, 0x42,
+ 0xdc, 0x62, 0x5e, 0x30, 0x82, 0x18, 0x32, 0x81, 0x27, 0x8a, 0x5d, 0xa7,
+ 0x66, 0xa6, 0x2a, 0xbc, 0x73, 0x84, 0x0e, 0xac, 0x53, 0x33, 0xd3, 0xb6,
+ 0x89, 0xba, 0xed, 0x1b, 0xda, 0x54, 0x83, 0x72, 0x41, 0xb7, 0x43, 0x1d,
+ 0xa2, 0x3f, 0x4a, 0x9b, 0xe4, 0x79, 0x67, 0x20, 0xc6, 0x77, 0x01, 0x9f,
+ 0x23, 0xfa, 0x6f, 0xd0, 0x17, 0xa0, 0xc3, 0x27, 0xba, 0xe4, 0xd2, 0xcb,
+ 0x8c, 0x35, 0xae, 0xbc, 0x7a, 0x96, 0x3a, 0x2c, 0xf6, 0xac, 0xea, 0x90,
+ 0x63, 0x0f, 0xe1, 0x8c, 0xd8, 0x0f, 0x7b, 0x32, 0x33, 0x87, 0x90, 0xcb,
+ 0x7c, 0x1b, 0xf6, 0x59, 0x66, 0xcd, 0x9d, 0x0e, 0x6a, 0x84, 0x20, 0x06,
+ 0xa0, 0xdd, 0x47, 0x5d, 0xb1, 0xdd, 0x07, 0xbb, 0xe3, 0x58, 0x9f, 0x1a,
+ 0x5b, 0x04, 0x8e, 0x60, 0x8c, 0xed, 0xcd, 0xb2, 0xa8, 0xc6, 0x0e, 0xaa,
+ 0xb1, 0xb2, 0xb2, 0x0f, 0x8e, 0x1d, 0x52, 0xb1, 0xe9, 0x7c, 0x23, 0xea,
+ 0xdf, 0x88, 0x58, 0xc2, 0x7e, 0xf6, 0xe5, 0x61, 0xeb, 0x7b, 0x71, 0xae,
+ 0x15, 0x64, 0xa9, 0x81, 0x3a, 0x30, 0xff, 0x7b, 0x98, 0xcb, 0x3d, 0xc8,
+ 0x9e, 0x2a, 0xe9, 0xe4, 0xf1, 0x20, 0xce, 0x83, 0xfd, 0x21, 0xad, 0xb6,
+ 0x90, 0xaf, 0x03, 0x61, 0xbb, 0x25, 0xa4, 0x4d, 0x3c, 0x36, 0x70, 0x1c,
+ 0xc3, 0x5a, 0x17, 0x38, 0x18, 0x63, 0x11, 0x23, 0x52, 0x29, 0xe8, 0x82,
+ 0x34, 0xdb, 0xa4, 0xac, 0xde, 0xf7, 0xc3, 0x76, 0xb9, 0x16, 0x3a, 0xb4,
+ 0xa2, 0x75, 0xa5, 0x70, 0xcf, 0x53, 0xea, 0x9c, 0xd1, 0x93, 0x9b, 0xc3,
+ 0x9c, 0x10, 0x7a, 0x45, 0x9c, 0xd5, 0x93, 0x8c, 0x37, 0xef, 0x84, 0x76,
+ 0xda, 0x8b, 0xbe, 0x87, 0x44, 0xef, 0x65, 0xdf, 0x51, 0xe0, 0x61, 0xed,
+ 0x3c, 0x0c, 0x99, 0xd9, 0xe6, 0xfa, 0x6c, 0xd3, 0xfa, 0xc4, 0x3a, 0xeb,
+ 0x3b, 0x9a, 0xfa, 0x32, 0x52, 0x9b, 0xef, 0x52, 0xf1, 0xf2, 0x7c, 0x18,
+ 0x2f, 0x17, 0x6b, 0x94, 0x05, 0x7e, 0x96, 0x7f, 0x5b, 0xe9, 0xa2, 0x76,
+ 0x36, 0xb0, 0xf5, 0xa5, 0x93, 0x3c, 0x17, 0x57, 0xe7, 0xd5, 0xd4, 0xbc,
+ 0xdf, 0x06, 0xff, 0xba, 0x1c, 0x55, 0x32, 0x70, 0x3e, 0xe6, 0xd5, 0x02,
+ 0xbf, 0x31, 0x6c, 0xce, 0xa1, 0x8f, 0x44, 0x6b, 0x38, 0xff, 0xe7, 0xa8,
+ 0x55, 0xbe, 0xac, 0xd6, 0xac, 0xfa, 0x0c, 0xf9, 0x71, 0x42, 0x9e, 0x7b,
+ 0xc0, 0x5f, 0x67, 0x28, 0x43, 0x7b, 0x28, 0x03, 0xf1, 0xfd, 0x27, 0x70,
+ 0xb7, 0x61, 0x1e, 0x79, 0xdd, 0x86, 0x3e, 0xbe, 0xff, 0x17, 0xfa, 0x76,
+ 0x23, 0xff, 0x23, 0x6f, 0x89, 0x26, 0xde, 0xfe, 0x03, 0x63, 0x3d, 0x4a,
+ 0xb7, 0x35, 0xd4, 0x26, 0x53, 0xbc, 0xef, 0x48, 0xe1, 0x1c, 0x38, 0xb9,
+ 0x4d, 0xd1, 0xad, 0x9d, 0xbd, 0x86, 0xf1, 0x5e, 0xac, 0x89, 0xda, 0xcd,
+ 0xb2, 0xe9, 0x58, 0xfb, 0x53, 0x25, 0xcf, 0x62, 0xed, 0x4e, 0xf2, 0x6f,
+ 0x5b, 0x23, 0x3b, 0xe5, 0x26, 0x4f, 0xe4, 0xa7, 0x1f, 0x4f, 0x2b, 0x72,
+ 0x21, 0xd8, 0x6d, 0xd2, 0x90, 0xd1, 0x7c, 0x9a, 0xdf, 0xf9, 0x12, 0xbc,
+ 0x17, 0x1d, 0x19, 0xe4, 0x9e, 0xa1, 0xdd, 0x60, 0x4e, 0x47, 0x7f, 0x4b,
+ 0xc8, 0x31, 0xd4, 0x24, 0xe5, 0x85, 0x8c, 0x56, 0x3c, 0x99, 0x45, 0x16,
+ 0xad, 0xbe, 0xd5, 0xc9, 0x8b, 0x4b, 0xb6, 0x7c, 0x1b, 0x7e, 0x7a, 0xb2,
+ 0x9e, 0x4d, 0x7f, 0x13, 0xf9, 0xc1, 0x91, 0x25, 0xe6, 0x13, 0x3d, 0x29,
+ 0x65, 0x9b, 0xf3, 0x9a, 0x6c, 0x60, 0x4c, 0x9b, 0x47, 0x7e, 0x6a, 0xdd,
+ 0x2d, 0x47, 0x82, 0x9f, 0x57, 0xd7, 0xc6, 0x0c, 0xca, 0xb1, 0x36, 0x66,
+ 0x10, 0x0f, 0x63, 0xc6, 0x4e, 0xec, 0x13, 0x63, 0x06, 0xf6, 0xff, 0x24,
+ 0x63, 0x86, 0x8d, 0x75, 0x8c, 0x19, 0x79, 0x59, 0xac, 0x32, 0x66, 0xec,
+ 0x45, 0x9b, 0x31, 0xa3, 0x80, 0x76, 0x10, 0x2f, 0x16, 0x55, 0xbc, 0xc8,
+ 0x5a, 0xcb, 0xc2, 0x38, 0x81, 0x3c, 0xb1, 0x8a, 0x3c, 0xb1, 0x8a, 0x3c,
+ 0xb1, 0x8a, 0x3c, 0xb1, 0x8a, 0x3c, 0x11, 0xb6, 0xfe, 0x5a, 0x15, 0x79,
+ 0x22, 0xfc, 0xe7, 0x3c, 0x72, 0x92, 0xa0, 0xa6, 0x38, 0x8c, 0x9a, 0xc2,
+ 0xd5, 0xc6, 0xaa, 0xe3, 0xda, 0xbe, 0x2a, 0x6a, 0x43, 0xf5, 0x9d, 0x58,
+ 0x1f, 0xda, 0x80, 0xba, 0xa8, 0xe6, 0x6c, 0x01, 0x5f, 0xd7, 0xe0, 0x1b,
+ 0xd4, 0xd3, 0x56, 0x99, 0xca, 0xed, 0x80, 0x7c, 0xd8, 0x7f, 0xfb, 0xfb,
+ 0xe8, 0x43, 0x3e, 0x9f, 0x63, 0x0d, 0xc2, 0x78, 0xb5, 0x0f, 0x6d, 0x1d,
+ 0x6d, 0xec, 0xe9, 0x04, 0x7c, 0xc4, 0x7e, 0x90, 0xf9, 0x62, 0x7a, 0x41,
+ 0x9e, 0xdc, 0x1c, 0xd8, 0xf4, 0x6f, 0x31, 0x27, 0x5e, 0xd3, 0xde, 0x88,
+ 0x39, 0xf0, 0x17, 0xd8, 0x97, 0x5a, 0x03, 0x5c, 0xba, 0xfd, 0xe7, 0xc4,
+ 0xd1, 0xb7, 0xe1, 0xd6, 0x1c, 0xda, 0xd5, 0xf7, 0x9a, 0xfa, 0xb2, 0x98,
+ 0xcf, 0xef, 0xe2, 0x3b, 0xf0, 0xfb, 0x16, 0x7e, 0x61, 0x77, 0xf6, 0x05,
+ 0xcc, 0xe9, 0xc3, 0xef, 0x77, 0x9a, 0xe6, 0x42, 0x0a, 0xfb, 0x2f, 0xd1,
+ 0x77, 0x31, 0xa4, 0xc1, 0x6f, 0x89, 0x5f, 0x6a, 0xe2, 0xe3, 0x07, 0xe8,
+ 0xfb, 0x6b, 0xf4, 0xf9, 0xfe, 0xdb, 0x4e, 0xd4, 0x27, 0xa5, 0x96, 0x70,
+ 0xef, 0x46, 0xd5, 0xde, 0x69, 0xca, 0xe6, 0x8f, 0x2c, 0xe9, 0xaa, 0x0e,
+ 0x7a, 0xae, 0x8e, 0xea, 0x08, 0x71, 0xbe, 0xbc, 0x10, 0xd4, 0xad, 0xc7,
+ 0x51, 0x73, 0x16, 0xab, 0xb4, 0x91, 0x1c, 0xfa, 0x6d, 0x9c, 0x69, 0x32,
+ 0x69, 0xdc, 0xaa, 0x63, 0x13, 0x89, 0xc9, 0x7a, 0x9b, 0x48, 0x37, 0x69,
+ 0x32, 0x4f, 0x22, 0x8e, 0xd9, 0x99, 0xe2, 0xc2, 0xec, 0x8c, 0x07, 0x9c,
+ 0x63, 0x75, 0xae, 0xe5, 0x3c, 0x93, 0xf7, 0x63, 0x4d, 0x74, 0x69, 0x13,
+ 0x60, 0x06, 0xf4, 0x9e, 0xab, 0x93, 0x7e, 0x40, 0xb3, 0xac, 0x68, 0xda,
+ 0xe8, 0x8f, 0xea, 0xc7, 0x1c, 0x6a, 0x5d, 0x99, 0x64, 0xed, 0x5c, 0x0c,
+ 0x69, 0xba, 0x75, 0x49, 0x24, 0x0a, 0xcd, 0xf8, 0x82, 0x8c, 0xf3, 0xb9,
+ 0xfa, 0xec, 0x8c, 0xfe, 0x42, 0x36, 0xc7, 0x3b, 0x11, 0xd7, 0x9a, 0x9d,
+ 0x69, 0x1d, 0x48, 0xc8, 0x8f, 0x91, 0xbb, 0x1d, 0x53, 0x34, 0x66, 0x67,
+ 0x8c, 0x17, 0x02, 0x5b, 0x0c, 0xe8, 0xe0, 0x3c, 0xc9, 0xb7, 0x43, 0x4e,
+ 0xd2, 0x62, 0x4d, 0x1d, 0x8c, 0x4f, 0xaa, 0x7a, 0xd1, 0x94, 0x2b, 0x15,
+ 0x45, 0x3b, 0xac, 0xdb, 0xc9, 0xc3, 0xec, 0x8c, 0xfc, 0xd1, 0x2d, 0x1e,
+ 0xd6, 0x91, 0x87, 0x78, 0x49, 0x27, 0xd0, 0x5b, 0xc0, 0x7f, 0x12, 0xf5,
+ 0x7b, 0x54, 0xab, 0xfb, 0xfe, 0x8a, 0x93, 0x43, 0x5c, 0xe0, 0x3e, 0xb6,
+ 0xa8, 0x3c, 0xd7, 0x73, 0x32, 0xbc, 0xef, 0x9b, 0xe3, 0xdf, 0x39, 0x78,
+ 0xf9, 0x01, 0xd4, 0x4d, 0xbc, 0x1b, 0xa4, 0x7f, 0xe1, 0xf7, 0x36, 0xff,
+ 0xe2, 0x7c, 0xf6, 0x93, 0xe7, 0x81, 0xf4, 0x55, 0xf0, 0xe7, 0xe5, 0xd1,
+ 0x87, 0x58, 0x51, 0x6c, 0x44, 0xb8, 0x78, 0xc7, 0xce, 0x39, 0x2a, 0xff,
+ 0x6e, 0xf2, 0xd1, 0x96, 0xf0, 0xdc, 0xa5, 0x8e, 0xc8, 0x27, 0xf9, 0xe9,
+ 0x84, 0x4d, 0x90, 0x17, 0xce, 0x8f, 0xee, 0x25, 0xd8, 0xfe, 0xb8, 0x36,
+ 0x12, 0xdd, 0xa9, 0x7d, 0x9c, 0x3d, 0x8f, 0x74, 0x76, 0x37, 0x7e, 0x88,
+ 0x83, 0xb4, 0x23, 0xbe, 0x22, 0x9e, 0x88, 0x8f, 0xfc, 0x44, 0xbc, 0x28,
+ 0x1b, 0x5d, 0x97, 0x9f, 0x60, 0x5d, 0xc0, 0x4f, 0x69, 0x21, 0x0d, 0x9d,
+ 0x90, 0xa7, 0x11, 0x6d, 0xa4, 0xba, 0xde, 0x1d, 0xc7, 0x0f, 0x5c, 0xc6,
+ 0xd5, 0xb1, 0x06, 0xef, 0xa1, 0x48, 0x97, 0x7f, 0x3b, 0xb2, 0xa4, 0x8d,
+ 0x34, 0xf8, 0x9d, 0xa9, 0xae, 0xb9, 0x8d, 0x88, 0xde, 0x5a, 0x9d, 0x46,
+ 0xbf, 0xbc, 0x2b, 0xff, 0x0c, 0xf6, 0xa9, 0x3b, 0xf8, 0xbb, 0x14, 0x55,
+ 0x47, 0xb1, 0x6f, 0xb9, 0xd5, 0x73, 0xa2, 0xbf, 0xd3, 0xd9, 0x1f, 0xe6,
+ 0x43, 0x51, 0x6d, 0x1c, 0xd5, 0x59, 0xea, 0x9e, 0x7d, 0xaf, 0xe7, 0x68,
+ 0xc8, 0x4f, 0x99, 0x33, 0x05, 0x3a, 0x08, 0xf1, 0xde, 0x91, 0xcf, 0x91,
+ 0x26, 0x3e, 0x47, 0xc1, 0xe7, 0x3e, 0xf0, 0x39, 0x76, 0x8b, 0xcf, 0x5b,
+ 0xb6, 0x97, 0x29, 0xc3, 0xf6, 0x46, 0xd6, 0xb5, 0xbd, 0x55, 0x3a, 0xab,
+ 0x73, 0x83, 0xfb, 0x9a, 0x91, 0x86, 0x2f, 0xc7, 0x9d, 0x8f, 0x53, 0x37,
+ 0xb7, 0xcb, 0x99, 0x85, 0xbb, 0xd5, 0xb7, 0x11, 0xaf, 0x2a, 0x77, 0x94,
+ 0x4b, 0xf5, 0x80, 0x9f, 0x1f, 0x2f, 0xb1, 0x3d, 0x12, 0xea, 0x8a, 0x3a,
+ 0xcb, 0x3a, 0x25, 0xb9, 0x1b, 0x2f, 0xbf, 0xf8, 0x9c, 0x76, 0xa5, 0x12,
+ 0x9d, 0x4f, 0x5a, 0x78, 0xc6, 0xae, 0xe5, 0x29, 0xfa, 0x6e, 0x32, 0x66,
+ 0x45, 0xf7, 0x67, 0x22, 0xfc, 0xfe, 0xc0, 0xef, 0x75, 0x6b, 0xbf, 0x13,
+ 0xf0, 0x7c, 0x8a, 0x78, 0xd7, 0x53, 0x3c, 0x9f, 0xc6, 0x9c, 0x66, 0x19,
+ 0x5c, 0xd8, 0xa4, 0x9e, 0xe4, 0x98, 0xe7, 0xd0, 0x2f, 0x4c, 0xd0, 0x0c,
+ 0xee, 0xdd, 0x6a, 0x4b, 0xbe, 0x5c, 0x74, 0x36, 0x06, 0xe7, 0x28, 0x64,
+ 0xba, 0x6c, 0xf1, 0xfe, 0x0a, 0x31, 0x8c, 0x67, 0x83, 0xb2, 0xb5, 0x16,
+ 0xf5, 0x5c, 0x39, 0xd0, 0x0e, 0x1d, 0xb3, 0xdd, 0xd6, 0xcb, 0xfb, 0x0a,
+ 0xca, 0xbc, 0xa0, 0xf6, 0x21, 0xd2, 0x71, 0xf4, 0x7d, 0xae, 0x55, 0x96,
+ 0xc3, 0xbb, 0xad, 0xc5, 0x8a, 0xef, 0xbf, 0x83, 0x3c, 0xfc, 0x34, 0x74,
+ 0x5f, 0xae, 0xff, 0xcc, 0x5f, 0x4e, 0xf1, 0x6f, 0xa5, 0x22, 0x9b, 0xd8,
+ 0xd1, 0xcb, 0x7b, 0x20, 0xf8, 0x96, 0x1c, 0xaf, 0x87, 0x65, 0xbf, 0x70,
+ 0x9c, 0x7d, 0xff, 0x0d, 0xbe, 0x7d, 0xff, 0xf4, 0xaa, 0x9d, 0x02, 0xfe,
+ 0x17, 0x33, 0xe1, 0x9b, 0xdd, 0x90, 0x58, 0x00, 0x00, 0x00 };
static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_RXP_b06FwRodata[(0x28/4) + 1] = {
@@ -1943,387 +1057,264 @@ static u32 bnx2_RXP_b06FwRodata[(0x28/4) + 1] = {
static u32 bnx2_RXP_b06FwBss[(0x13a4/4) + 1] = { 0x0 };
static u32 bnx2_RXP_b06FwSbss[(0x1c/4) + 1] = { 0x0 };
-static u32 bnx2_rv2p_proc1[] = {
- 0x00000008, 0xac000001, 0x0000000c, 0x2f800001, 0x00000010, 0x213f0004,
- 0x00000010, 0x20bf002c, 0x00000010, 0x203f0143, 0x00000018, 0x8000fffd,
- 0x00000010, 0xb1b8b017, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
- 0x00000000, 0x2c380000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
- 0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x00000008, 0x02000002,
- 0x00000010, 0x91de0000, 0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08,
- 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000008, 0x2d800150,
- 0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000010, 0x2c620002,
- 0x00000018, 0x80000012, 0x0000000b, 0x2fdf0002, 0x0000000c, 0x1f800002,
- 0x00000000, 0x2c070000, 0x00000018, 0x8000ffe6, 0x00000008, 0x02000002,
- 0x0000000f, 0x42e0001c, 0x00000010, 0x91840a08, 0x00000008, 0x2c8000b0,
- 0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
- 0x00000000, 0x00000000, 0x00000010, 0x91de0000, 0x00000018, 0x80000004,
- 0x0000000c, 0x1f800002, 0x00000000, 0x00000000, 0x00000018, 0x8000ffd9,
- 0x0000000c, 0x29800002, 0x0000000c, 0x1f800002, 0x00000000, 0x2adf0000,
- 0x00000008, 0x2a000005, 0x00000018, 0x8000ffd4, 0x00000008, 0x02240030,
- 0x00000018, 0x00040000, 0x00000018, 0x80000015, 0x00000018, 0x80000017,
- 0x00000018, 0x8000001b, 0x00000018, 0x8000004c, 0x00000018, 0x8000008c,
- 0x00000018, 0x8000000f, 0x00000018, 0x8000000e, 0x00000018, 0x8000000d,
- 0x00000018, 0x8000000c, 0x00000018, 0x800000c2, 0x00000018, 0x8000000a,
- 0x00000018, 0x80000009, 0x00000018, 0x80000008, 0x00000018, 0x800000fd,
- 0x00000018, 0x80000006, 0x00000018, 0x80000005, 0x00000018, 0x800000ff,
- 0x00000018, 0x80000104, 0x00000018, 0x80000002, 0x00000018, 0x80000098,
- 0x00000018, 0x80000000, 0x0000000c, 0x1f800001, 0x00000000, 0x00000000,
- 0x00000018, 0x8000ffba, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
- 0x0000000c, 0x1f800001, 0x00000008, 0x2a000002, 0x00000018, 0x8000ffb5,
- 0x00000010, 0xb1a0b012, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000,
- 0x00000008, 0x2c800000, 0x00000008, 0x2d000000, 0x00000010, 0x91d40000,
- 0x00000008, 0x2d80011c, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
- 0x0000000f, 0x47600008, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
- 0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
- 0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000018, 0x80000013,
- 0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002, 0x00000008, 0x2c800000,
- 0x00000008, 0x2d000000, 0x00000010, 0x91d40000, 0x00000008, 0x2d80011c,
- 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000, 0x00000000, 0x0f580000,
- 0x00000010, 0x91de0000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
- 0x00000000, 0x0b660000, 0x00000000, 0x0d610000, 0x00000000, 0x02620000,
- 0x0000000b, 0x2fdf0002, 0x00000000, 0x309a0000, 0x00000000, 0x31040000,
- 0x00000000, 0x0c961800, 0x00000009, 0x0c99ffff, 0x00000004, 0xcc993400,
- 0x00000010, 0xb1963202, 0x00000008, 0x0f800000, 0x0000000c, 0x29800001,
- 0x00000010, 0x00220002, 0x0000000c, 0x29520001, 0x0000000c, 0x29520000,
- 0x00000008, 0x22000001, 0x0000000c, 0x1f800001, 0x00000000, 0x2adf0000,
- 0x00000008, 0x2a000003, 0x00000018, 0x8000ff83, 0x00000010, 0xb1a0b01d,
- 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
- 0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
- 0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
- 0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000000, 0x00000000,
- 0x00000010, 0x91de0000, 0x0000000f, 0x47600008, 0x00000000, 0x060e0000,
- 0x00000010, 0x001f0000, 0x00000000, 0x0f580000, 0x00000010, 0x91de0000,
- 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000, 0x00000000, 0x0b670000,
- 0x00000000, 0x0d620000, 0x00000000, 0x0ce71800, 0x00000009, 0x0c99ffff,
- 0x00000004, 0xcc993400, 0x00000010, 0xb1963220, 0x00000008, 0x0f800000,
- 0x00000018, 0x8000001e, 0x0000000f, 0x47600008, 0x0000000b, 0x2fdf0002,
- 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008, 0x00000010, 0x91d40000,
- 0x00000008, 0x2d80012c, 0x0000000f, 0x060e0001, 0x00000010, 0x001f0000,
- 0x00000000, 0x0f580000, 0x00000010, 0x91de0000, 0x00000000, 0x0a640000,
- 0x00000000, 0x0ae50000, 0x00000000, 0x0b670000, 0x00000000, 0x0d620000,
- 0x00000000, 0x02630000, 0x0000000f, 0x47620010, 0x00000000, 0x0ce71800,
- 0x0000000b, 0x2fdf0002, 0x00000000, 0x311a0000, 0x00000000, 0x31840000,
- 0x0000000b, 0xc20000ff, 0x00000002, 0x42040000, 0x00000001, 0x31620800,
- 0x0000000f, 0x020e0010, 0x00000002, 0x31620800, 0x00000009, 0x0c99ffff,
- 0x00000004, 0xcc993400, 0x00000010, 0xb1963202, 0x00000008, 0x0f800000,
- 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x0000000c, 0x61420006,
- 0x00000008, 0x22000008, 0x00000000, 0x2adf0000, 0x00000008, 0x2a000004,
- 0x00000018, 0x8000ff42, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
- 0x00000010, 0x91a0b008, 0x00000010, 0x91d40000, 0x0000000c, 0x31620018,
- 0x00000008, 0x2d800001, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
- 0x00000008, 0xac000001, 0x00000018, 0x8000000e, 0x00000000, 0x0380b000,
- 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c004000, 0x00000010, 0x91d40000,
- 0x00000008, 0x2d800101, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
- 0x0000000c, 0x31620018, 0x00000008, 0x2d800001, 0x00000000, 0x00000000,
- 0x00000010, 0x91de0000, 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c000e00,
- 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000008, 0x2a000007,
- 0x00000018, 0x8000ff27, 0x00000010, 0xb1a0b016, 0x0000000b, 0x2fdf0002,
- 0x00000000, 0x03d80000, 0x00000000, 0x2c200000, 0x00000008, 0x2c8000b0,
- 0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800150,
- 0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800000,
- 0x00000008, 0x2d000000, 0x00000008, 0x2d800108, 0x00000008, 0x07000001,
- 0x00000010, 0xb5de1c00, 0x00000010, 0x2c620002, 0x00000018, 0x8000000a,
- 0x0000000b, 0x2fdf0002, 0x00000000, 0x2c070000, 0x0000000c, 0x1f800001,
- 0x00000010, 0x91de0000, 0x00000018, 0x8000ff11, 0x00000008, 0x2c8000b0,
- 0x00000008, 0x2d000008, 0x00000010, 0x91d40000, 0x00000008, 0x2d800108,
- 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000010, 0x91de0000,
- 0x00000000, 0x2adf0000, 0x00000008, 0x2a00000a, 0x00000018, 0x8000ff07,
- 0x00000000, 0x82265600, 0x0000000f, 0x47220008, 0x00000009, 0x070e000f,
- 0x00000008, 0x070e0008, 0x00000008, 0x02800001, 0x00000007, 0x02851c00,
- 0x00000008, 0x82850001, 0x00000000, 0x02840a00, 0x00000007, 0x42851c00,
- 0x00000003, 0xc3aa5200, 0x00000000, 0x03b10e00, 0x00000010, 0x001f0000,
- 0x0000000f, 0x0f280007, 0x00000007, 0x4b071c00, 0x00000000, 0x00000000,
- 0x0000000f, 0x0a960003, 0x00000000, 0x0a955c00, 0x00000000, 0x4a005a00,
- 0x00000000, 0x0c960a00, 0x00000009, 0x0c99ffff, 0x00000008, 0x0d00ffff,
- 0x00000010, 0xb1963202, 0x00000008, 0x0f800005, 0x00000010, 0x00220020,
- 0x00000000, 0x02a70000, 0x00000010, 0xb1850002, 0x00000008, 0x82850200,
- 0x00000000, 0x02000000, 0x00000000, 0x03a60000, 0x00000018, 0x8000004e,
- 0x00000000, 0x072b0000, 0x00000001, 0x878c1c00, 0x00000000, 0x870e1e00,
- 0x00000000, 0x860c1e00, 0x00000000, 0x03061e00, 0x00000010, 0xb18e0003,
- 0x00000018, 0x80000047, 0x00000018, 0x8000fffa, 0x00000010, 0x918c0003,
- 0x00000010, 0xb1870002, 0x00000018, 0x80000043, 0x00000010, 0x91d40000,
- 0x0000000c, 0x29800001, 0x00000000, 0x2a860000, 0x00000000, 0x230c0000,
- 0x00000000, 0x2b070000, 0x00000010, 0xb187000e, 0x00000008, 0x2a000008,
- 0x00000018, 0x8000003b, 0x00000010, 0x91d40000, 0x00000000, 0x28d18c00,
- 0x00000000, 0x2a860000, 0x00000000, 0x230c0000, 0x00000000, 0x2b070000,
- 0x00000018, 0x8000fff8, 0x00000010, 0x91d40000, 0x0000000c, 0x29800001,
- 0x00000000, 0x2aab0000, 0x00000000, 0xa3265600, 0x00000000, 0x2b000000,
- 0x0000000c, 0x1f800001, 0x00000008, 0x2a000008, 0x00000018, 0x8000fec8,
- 0x00000010, 0x91d40000, 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001,
- 0x00000008, 0x2a000009, 0x00000018, 0x8000fec3, 0x00000010, 0x91d40000,
- 0x0000000c, 0x29800001, 0x0000000c, 0x1f800001, 0x00000000, 0x29420000,
- 0x00000008, 0x2a000002, 0x00000018, 0x8000febd, 0x00000018, 0x8000febc,
- 0x00000010, 0xb1bcb016, 0x0000000b, 0x2fdf0002, 0x00000000, 0x03d80000,
- 0x00000000, 0x2c3c0000, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
- 0x00000010, 0x91d40000, 0x00000008, 0x2d800150, 0x00000000, 0x00000000,
- 0x00000010, 0x205f0000, 0x00000008, 0x2c800000, 0x00000008, 0x2d000000,
- 0x00000008, 0x2d800108, 0x00000008, 0x07000001, 0x00000010, 0xb5de1c00,
- 0x00000010, 0x2c620002, 0x00000018, 0x8000000a, 0x0000000b, 0x2fdf0002,
- 0x00000000, 0x2c070000, 0x0000000c, 0x1f800000, 0x00000010, 0x91de0000,
- 0x00000018, 0x8000fea6, 0x00000008, 0x2c8000b0, 0x00000008, 0x2d000008,
- 0x00000010, 0x91d40000, 0x00000008, 0x2d800108, 0x0000000c, 0x29800000,
- 0x0000000c, 0x1f800000, 0x00000010, 0x91de0000, 0x00000000, 0x2adf0000,
- 0x00000008, 0x2a000006, 0x00000018, 0x8000fe9c, 0x00000008, 0x03050004,
- 0x00000006, 0x83040c00, 0x00000008, 0x02850200, 0x00000000, 0x86050c00,
- 0x00000001, 0x860c0e00, 0x00000008, 0x02040004, 0x00000000, 0x02041800,
- 0x00000000, 0x83871800, 0x00000018, 0x00020000 };
+static u8 bnx2_rv2p_proc1[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b,
+ 0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b,
+ 0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82,
+ 0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a,
+ 0xfe, 0x1b, 0xa1, 0x3f, 0xd2, 0x4b, 0x10, 0x7a, 0xb0, 0x58, 0xf1, 0x50,
+ 0x10, 0x2a, 0x68, 0x0f, 0xc9, 0xa1, 0x20, 0x52, 0x11, 0xda, 0x8b, 0x07,
+ 0x2f, 0x42, 0x0f, 0x7a, 0x69, 0xbd, 0xa8, 0xff, 0x82, 0x08, 0x4d, 0x7c,
+ 0x6f, 0x66, 0x9e, 0xee, 0x6e, 0xb2, 0x4d, 0x15, 0xc1, 0x85, 0xf6, 0xe3,
+ 0xbd, 0x9d, 0x79, 0x33, 0xf3, 0xcd, 0x37, 0xfb, 0x62, 0x01, 0x40, 0x04,
+ 0x60, 0xcd, 0x46, 0x2c, 0x8d, 0x26, 0x04, 0x1a, 0x30, 0x7e, 0x52, 0x62,
+ 0x16, 0xde, 0xa6, 0x25, 0x4e, 0x44, 0xc6, 0xd3, 0x49, 0x81, 0x7b, 0x0d,
+ 0x28, 0xc9, 0x75, 0x4f, 0xf5, 0x55, 0xad, 0x53, 0xa0, 0x06, 0xbb, 0xa3,
+ 0x80, 0xcf, 0x47, 0x9d, 0xf0, 0x7c, 0xd6, 0x42, 0x2c, 0x31, 0xc2, 0x48,
+ 0x02, 0x61, 0x7b, 0x51, 0xae, 0xad, 0x48, 0x69, 0xc4, 0x42, 0x3f, 0xd0,
+ 0x68, 0x7f, 0x67, 0xd1, 0x15, 0xff, 0x53, 0xf0, 0x39, 0x2f, 0xd7, 0x56,
+ 0x7c, 0x0e, 0xed, 0xaa, 0xec, 0x2f, 0xfe, 0xd0, 0xfe, 0xba, 0xf0, 0x03,
+ 0x7e, 0x94, 0x5f, 0x02, 0xcf, 0x29, 0x66, 0x65, 0x5e, 0xdd, 0x22, 0xa0,
+ 0xca, 0xc7, 0x46, 0x2c, 0xf5, 0x91, 0xb5, 0x89, 0xef, 0xbf, 0x8a, 0xbc,
+ 0x55, 0xdc, 0x76, 0xf1, 0x82, 0xf9, 0x06, 0xe3, 0x26, 0x91, 0x1f, 0x28,
+ 0xf9, 0xe3, 0x00, 0xc8, 0xfd, 0x4f, 0x8d, 0x5f, 0xfb, 0x83, 0xfe, 0xf7,
+ 0xbb, 0x43, 0xf2, 0xbc, 0x28, 0xc0, 0x90, 0xb4, 0xdb, 0xe6, 0x7c, 0xc6,
+ 0xe0, 0xb4, 0x96, 0xc4, 0xf7, 0x06, 0xfa, 0x1f, 0x11, 0xe7, 0x4a, 0xec,
+ 0x61, 0x3c, 0xce, 0x78, 0x95, 0xb1, 0xc2, 0xe8, 0x32, 0x3a, 0x8c, 0x5d,
+ 0x8c, 0x36, 0xe3, 0x26, 0x63, 0x9c, 0xb1, 0x83, 0xd1, 0x62, 0xdc, 0x63,
+ 0x8c, 0x31, 0x46, 0x19, 0x1b, 0x8c, 0x46, 0x84, 0x50, 0xe3, 0xf5, 0x63,
+ 0x46, 0xe0, 0xba, 0x23, 0x81, 0xba, 0x5f, 0xb3, 0x2e, 0x24, 0x6f, 0xfc,
+ 0x7e, 0x50, 0xd9, 0x31, 0xef, 0x58, 0xf7, 0x3a, 0xdb, 0x75, 0x57, 0x57,
+ 0x02, 0xfa, 0x49, 0xef, 0xab, 0x9b, 0x54, 0x8b, 0x3e, 0xb8, 0x58, 0xcf,
+ 0x9d, 0x82, 0x8b, 0x71, 0x9c, 0x18, 0xed, 0xab, 0xb4, 0x6e, 0xb8, 0x84,
+ 0xf7, 0xe2, 0x84, 0x5f, 0x18, 0xef, 0x77, 0x12, 0x4e, 0x77, 0xc9, 0x7c,
+ 0x0e, 0x8b, 0x80, 0xea, 0x1c, 0x95, 0x4f, 0xbb, 0x3c, 0xc2, 0xe2, 0xa9,
+ 0xbc, 0xda, 0xc5, 0x25, 0x2c, 0x6a, 0xfe, 0xfa, 0x9f, 0x8c, 0x11, 0x1a,
+ 0x39, 0x22, 0x75, 0xc9, 0x16, 0x3d, 0x83, 0x46, 0x63, 0xd9, 0x36, 0xe4,
+ 0xfa, 0xdc, 0xf2, 0x7b, 0xd4, 0xfb, 0xd9, 0xa5, 0x1a, 0xe7, 0xe7, 0x2a,
+ 0x9e, 0x69, 0x0e, 0x32, 0x40, 0xeb, 0x49, 0xe4, 0x1d, 0x04, 0x5a, 0xb8,
+ 0x86, 0x8c, 0xbf, 0x5f, 0xa4, 0x43, 0x9d, 0xfb, 0x31, 0xcb, 0xfd, 0x38,
+ 0x11, 0xd2, 0x8f, 0xb0, 0xb9, 0x68, 0x9e, 0xc7, 0xdb, 0xe9, 0x20, 0x6f,
+ 0x61, 0xf3, 0xa3, 0xf8, 0xa6, 0xdd, 0x3f, 0xe5, 0xf1, 0x01, 0xf3, 0x58,
+ 0x24, 0x1e, 0x93, 0xdf, 0x5a, 0xf2, 0x94, 0xf6, 0xf0, 0x24, 0xeb, 0xec,
+ 0x0d, 0xe9, 0x73, 0x58, 0x7d, 0xd9, 0xbf, 0xee, 0x73, 0x20, 0x3f, 0xb8,
+ 0x8b, 0xdf, 0x9b, 0x04, 0x14, 0x0b, 0x2a, 0x5f, 0x3f, 0xcf, 0xc7, 0xa8,
+ 0xdf, 0x30, 0x97, 0x93, 0xfb, 0x62, 0xfe, 0x36, 0x35, 0x5c, 0x1b, 0xf9,
+ 0x88, 0x04, 0xab, 0x98, 0x23, 0x7f, 0x47, 0xd3, 0x78, 0x7d, 0x50, 0x5d,
+ 0xa8, 0xbe, 0x4b, 0x8c, 0x41, 0x7e, 0x9a, 0xeb, 0xcc, 0x50, 0x3c, 0xd2,
+ 0x81, 0xc1, 0x3a, 0xc8, 0xf3, 0xf7, 0x28, 0xc8, 0x87, 0x55, 0x5d, 0x59,
+ 0xf4, 0xce, 0x75, 0x12, 0x8a, 0x39, 0xd2, 0x55, 0x73, 0x5f, 0x59, 0x6f,
+ 0x6b, 0xea, 0xbb, 0x84, 0xdb, 0xd5, 0x92, 0xee, 0xab, 0xf7, 0x12, 0x64,
+ 0xbd, 0x3c, 0x47, 0x5a, 0xe8, 0xa3, 0x5d, 0x1c, 0xdf, 0x79, 0x0e, 0x64,
+ 0x5b, 0x7d, 0x6f, 0x4c, 0xae, 0xeb, 0x0c, 0xeb, 0xfb, 0x68, 0x93, 0xbe,
+ 0xd5, 0x7d, 0xf5, 0xef, 0x74, 0xce, 0xf5, 0x9b, 0x68, 0x97, 0xda, 0x59,
+ 0xf7, 0xde, 0x4f, 0x71, 0xcf, 0xfd, 0x44, 0x6e, 0xa6, 0xca, 0xbb, 0xcf,
+ 0x7b, 0xaf, 0x1c, 0x0a, 0xe9, 0x83, 0xf7, 0x3e, 0x0a, 0xd6, 0xeb, 0xd7,
+ 0x23, 0xf5, 0x35, 0xce, 0xf5, 0x9b, 0x0d, 0xee, 0xc3, 0x54, 0xff, 0x0c,
+ 0xe9, 0x3f, 0x53, 0x90, 0xfa, 0x71, 0xc1, 0x31, 0xe9, 0x7c, 0x42, 0x71,
+ 0x8e, 0x66, 0x62, 0xde, 0xf3, 0x1a, 0xad, 0xe7, 0x67, 0xd0, 0x2f, 0x3e,
+ 0xa7, 0xf6, 0xf3, 0x48, 0xd8, 0xe4, 0x8b, 0x2d, 0xe2, 0xbd, 0xa6, 0xab,
+ 0xb9, 0x70, 0x91, 0xef, 0x01, 0x97, 0xec, 0xcc, 0x2b, 0x8a, 0x2f, 0xb9,
+ 0xaf, 0xc3, 0x12, 0xcd, 0xc5, 0xad, 0x47, 0x84, 0x37, 0xe1, 0x32, 0x9d,
+ 0xfb, 0xfb, 0xfb, 0x66, 0x21, 0x42, 0x97, 0x57, 0xc7, 0x51, 0xa1, 0x63,
+ 0x9c, 0x63, 0x25, 0x57, 0x78, 0xae, 0x11, 0x9f, 0xf3, 0xa4, 0x73, 0x8d,
+ 0xf3, 0xc3, 0xab, 0x45, 0x3e, 0xab, 0xba, 0xac, 0xf7, 0x9a, 0xd2, 0x1d,
+ 0x0c, 0x9b, 0x38, 0x3f, 0xa9, 0xca, 0x02, 0x2e, 0x7b, 0x1d, 0x46, 0xbb,
+ 0x4c, 0x18, 0xc3, 0xfc, 0x75, 0x78, 0x58, 0x93, 0x7e, 0x05, 0xbe, 0xdf,
+ 0x7e, 0xb0, 0x5e, 0x74, 0xa8, 0xf0, 0xef, 0x8b, 0x05, 0x7c, 0x3f, 0x01,
+ 0xcd, 0xf7, 0x1b, 0xc5, 0x29, 0x0f, 0x11, 0xda, 0xa7, 0xb8, 0xaf, 0xc3,
+ 0xd2, 0xce, 0x11, 0x7e, 0xdc, 0x3f, 0xec, 0xc3, 0x05, 0x8f, 0x3f, 0x42,
+ 0xe5, 0xc3, 0x40, 0x98, 0xbf, 0xb4, 0xff, 0xde, 0xe2, 0x3e, 0xa5, 0xf7,
+ 0x2f, 0xc9, 0x7e, 0xaa, 0xff, 0x19, 0xd7, 0x3f, 0xec, 0xd5, 0xbd, 0x8a,
+ 0xf7, 0xae, 0xbe, 0xff, 0x7d, 0xdc, 0xc1, 0x76, 0x5b, 0xfb, 0xd8, 0xd1,
+ 0xf1, 0xf9, 0x41, 0xef, 0xfd, 0xfd, 0xa6, 0x4e, 0x3c, 0x6d, 0xd4, 0xd5,
+ 0x5c, 0x6d, 0x84, 0xcc, 0xd5, 0xc5, 0xff, 0x3a, 0x57, 0x10, 0x98, 0xab,
+ 0xd5, 0xfa, 0xc1, 0xe6, 0x0a, 0xb8, 0x7e, 0x08, 0x99, 0xab, 0x18, 0xf3,
+ 0xf0, 0x94, 0xcf, 0x33, 0x20, 0xaa, 0xc7, 0xb0, 0x7d, 0xc6, 0x2c, 0xeb,
+ 0x92, 0xf4, 0x68, 0x47, 0xcb, 0xa8, 0x3f, 0xc7, 0x2e, 0x93, 0x9d, 0x41,
+ 0xfb, 0x49, 0x85, 0x0b, 0xb3, 0xf4, 0x7b, 0x4a, 0x83, 0x9f, 0x94, 0x15,
+ 0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 };
-static u32 bnx2_rv2p_proc2[] = {
- 0x00000000, 0x2a000000, 0x00000010, 0xb1d40000, 0x00000008, 0x02540003,
- 0x00000018, 0x00040000, 0x00000018, 0x8000000a, 0x00000018, 0x8000000a,
- 0x00000018, 0x8000000e, 0x00000018, 0x80000056, 0x00000018, 0x800001b9,
- 0x00000018, 0x800001e1, 0x00000018, 0x8000019b, 0x00000018, 0x800001f9,
- 0x00000018, 0x8000019f, 0x00000018, 0x800001a6, 0x00000018, 0x80000000,
- 0x0000000c, 0x29800001, 0x00000000, 0x2a000000, 0x0000000c, 0x29800000,
- 0x00000010, 0x20530000, 0x00000018, 0x8000ffee, 0x0000000c, 0x29800001,
- 0x00000010, 0x91de0000, 0x00000010, 0x001f0000, 0x00000000, 0x2f80aa00,
- 0x00000000, 0x2a000000, 0x00000000, 0x0d610000, 0x00000000, 0x03620000,
- 0x00000000, 0x2c400000, 0x00000000, 0x02638c00, 0x00000000, 0x26460000,
- 0x00000010, 0x00420002, 0x00000008, 0x02040012, 0x00000010, 0xb9060836,
- 0x00000000, 0x0f580000, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
- 0x00000000, 0x0b660000, 0x00000000, 0x0c000000, 0x00000000, 0x0b800000,
- 0x00000010, 0x00420009, 0x00000008, 0x0cc60012, 0x00000008, 0x0f800003,
- 0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000008, 0x27110012,
- 0x00000000, 0x66900000, 0x00000008, 0xa31b0012, 0x00000018, 0x80000008,
- 0x00000000, 0x0cc60000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
- 0x00000010, 0x009f0000, 0x00000000, 0x27110000, 0x00000000, 0x66900000,
- 0x00000000, 0x231b0000, 0x00000010, 0xb197320e, 0x00000000, 0x25960000,
- 0x00000000, 0x021b0000, 0x00000010, 0x001f0000, 0x00000008, 0x0f800003,
- 0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000000, 0x22c50800,
- 0x00000010, 0x009f0000, 0x00000000, 0x27002200, 0x00000000, 0x26802000,
- 0x00000000, 0x231b0000, 0x0000000c, 0x69520001, 0x00000018, 0x8000fff3,
- 0x00000010, 0x01130002, 0x00000010, 0xb1980003, 0x00000010, 0x001f0000,
- 0x00000008, 0x0f800004, 0x00000008, 0x22000003, 0x00000008, 0x2c80000c,
- 0x00000008, 0x2d00000c, 0x00000010, 0x009f0000, 0x00000000, 0x25960000,
- 0x0000000c, 0x29800000, 0x00000000, 0x32140000, 0x00000000, 0x32950000,
- 0x00000000, 0x33160000, 0x00000000, 0x31e32e00, 0x00000008, 0x2d800010,
- 0x00000010, 0x20530000, 0x00000018, 0x8000ffac, 0x00000000, 0x23000000,
- 0x00000000, 0x25e60000, 0x00000008, 0x2200000b, 0x0000000c, 0x69520000,
- 0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000018, 0x8000ffa5,
- 0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
- 0x00000010, 0x001f0000, 0x00000000, 0x02700000, 0x00000000, 0x0d620000,
- 0x00000000, 0xbb630800, 0x00000000, 0x2a000000, 0x00000009, 0x076000ff,
- 0x0000000f, 0x2c0e0007, 0x00000008, 0x2c800000, 0x00000008, 0x2d000064,
- 0x00000008, 0x2d80011c, 0x00000009, 0x06420002, 0x0000000c, 0x61420001,
- 0x00000000, 0x0f400000, 0x00000000, 0x02d08c00, 0x00000000, 0x23000000,
- 0x00000004, 0x826da000, 0x00000000, 0x8304a000, 0x00000000, 0x22c50c00,
- 0x00000000, 0x03760000, 0x00000004, 0x83860a00, 0x00000000, 0x83870c00,
- 0x00000010, 0x91de0000, 0x00000000, 0x037c0000, 0x00000000, 0x837b0c00,
- 0x00000001, 0x83060e00, 0x00000000, 0x83870c00, 0x00000000, 0x82850e00,
- 0x00000010, 0xb1860016, 0x0000000f, 0x47610018, 0x00000000, 0x068e0000,
- 0x0000000f, 0x47670010, 0x0000000f, 0x47e20010, 0x00000000, 0x870e1e00,
- 0x00000010, 0xb70e1a10, 0x00000010, 0x0ce7000e, 0x00000008, 0x22000009,
- 0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
- 0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
- 0x00000018, 0x8000023f, 0x00000000, 0x37ed0000, 0x0000000c, 0x73e7001a,
- 0x00000010, 0x20530000, 0x00000008, 0x22000008, 0x0000000c, 0x61420004,
- 0x00000000, 0x02f60000, 0x00000004, 0x82840a00, 0x00000010, 0xb1840a2b,
- 0x00000010, 0x2d67000a, 0x00000010, 0xb96d0804, 0x00000004, 0xb6ed0a00,
- 0x00000000, 0x37ed0000, 0x00000018, 0x80000029, 0x0000000c, 0x61420000,
- 0x00000000, 0x37040000, 0x00000000, 0x37850000, 0x0000000c, 0x33e7001a,
- 0x00000018, 0x80000024, 0x00000010, 0xb96d0809, 0x00000004, 0xb6ed0a00,
- 0x00000000, 0x036d0000, 0x00000004, 0xb76e0c00, 0x00000010, 0x91ee0c1f,
- 0x0000000c, 0x73e7001a, 0x00000004, 0xb6ef0c00, 0x00000000, 0x37ed0000,
- 0x00000018, 0x8000001b, 0x0000000c, 0x61420000, 0x00000010, 0xb7ee0a05,
- 0x00000010, 0xb96f0815, 0x00000003, 0xb76e0800, 0x00000004, 0xb7ef0a00,
- 0x00000018, 0x80000015, 0x00000010, 0x0ce7000c, 0x00000008, 0x22000009,
- 0x00000000, 0x286d0000, 0x0000000f, 0x65680010, 0x00000003, 0xf66c9400,
- 0x00000010, 0xb972a003, 0x0000000c, 0x73e70019, 0x0000000c, 0x21420004,
- 0x00000018, 0x80000215, 0x00000010, 0x20530000, 0x00000008, 0x22000008,
- 0x0000000c, 0x61420004, 0x00000000, 0x37040000, 0x00000000, 0x37850000,
- 0x00000000, 0x036d0000, 0x00000003, 0xb8f10c00, 0x00000018, 0x80000004,
- 0x00000000, 0x02840000, 0x00000002, 0x21421800, 0x0000000c, 0x61420000,
- 0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff,
- 0x00000000, 0x23000000, 0x00000010, 0xb1840a3d, 0x00000010, 0x01420002,
- 0x00000004, 0xb8f10a00, 0x00000003, 0x83760a00, 0x00000010, 0xb8040c39,
- 0x00000010, 0xb7e6080a, 0x00000000, 0x0a640000, 0x00000000, 0x0ae50000,
- 0x00000009, 0x0c68ffff, 0x00000009, 0x0b67ffff, 0x00000000, 0x0be60000,
- 0x00000000, 0x0c840000, 0x00000010, 0xb197320c, 0x00000008, 0x0f800002,
- 0x00000018, 0x8000000a, 0x00000000, 0x0a6a0000, 0x00000000, 0x0aeb0000,
- 0x00000000, 0x0c000000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0be90000,
- 0x00000000, 0x0c840000, 0x00000010, 0xb1973203, 0x00000008, 0x0f800002,
- 0x00000018, 0x80000001, 0x00000010, 0x001f0000, 0x00000000, 0x0c860000,
- 0x00000000, 0x06980000, 0x00000008, 0x0f800003, 0x00000000, 0x00000000,
- 0x00000010, 0x009f0000, 0x00000010, 0xb1973210, 0x00000000, 0x231b0000,
- 0x00000000, 0x02043600, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
- 0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
- 0x0000000c, 0x29000000, 0x00000018, 0x800001de, 0x00000000, 0x06980000,
- 0x00000010, 0x20530000, 0x00000000, 0x22c58c00, 0x00000010, 0x001f0000,
- 0x00000008, 0x0f800003, 0x00000018, 0x8000fff0, 0x00000000, 0x02043600,
- 0x00000000, 0x231b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
- 0x00000009, 0x2607ffff, 0x00000000, 0x27111a00, 0x00000000, 0x66900000,
- 0x0000000c, 0x29000000, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
- 0x00000000, 0x32140000, 0x00000000, 0x32950000, 0x00000005, 0x73e72c00,
- 0x00000005, 0x74683000, 0x00000000, 0x33170000, 0x00000018, 0x80000138,
- 0x00000010, 0x91c60004, 0x00000008, 0x07000004, 0x00000010, 0xb1c41c02,
- 0x00000010, 0x91840a04, 0x00000018, 0x800001c3, 0x00000010, 0x20530000,
- 0x00000000, 0x22c58c00, 0x00000010, 0xb1840a8e, 0x0000000c, 0x21420006,
- 0x00000010, 0x0ce7001a, 0x0000000f, 0x43680010, 0x00000000, 0x03f30c00,
- 0x00000010, 0x91870850, 0x0000000f, 0x46ec0010, 0x00000010, 0xb68d0c4e,
- 0x00000000, 0x838d0c00, 0x00000000, 0xa3050800, 0x00000001, 0xa3460e00,
- 0x00000000, 0x02048c00, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
- 0x00000010, 0x001f0000, 0x00000008, 0x22000008, 0x00000003, 0x8384a000,
- 0x0000000f, 0x65870010, 0x00000009, 0x2607ffff, 0x00000000, 0x27750c00,
- 0x00000000, 0x66f40000, 0x0000000c, 0x29000000, 0x00000018, 0x800001aa,
- 0x00000000, 0x03068c00, 0x00000003, 0xf4680c00, 0x00000010, 0x20530000,
- 0x00000000, 0x22c58c00, 0x00000018, 0x8000ffe5, 0x00000000, 0x39760000,
- 0x00000000, 0x39840000, 0x0000000c, 0x33e70019, 0x00000010, 0x001f0000,
- 0x00000000, 0x031e0000, 0x00000000, 0x0760fe00, 0x0000000f, 0x0f0e0007,
- 0x00000000, 0x83850800, 0x00000000, 0x0a7d0000, 0x00000000, 0x0afe0000,
- 0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000, 0x00000000, 0x0c000000,
- 0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
- 0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
- 0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
- 0x00000002, 0x33e70e00, 0x00000000, 0x28f30000, 0x00000010, 0x009f0000,
- 0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
- 0x00000008, 0x22000006, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
- 0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
- 0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
- 0x0000000c, 0x29000000, 0x00000018, 0x8000017e, 0x00000003, 0xf4683600,
- 0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
- 0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
- 0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
- 0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
- 0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
- 0x00000000, 0x22c53600, 0x00000018, 0x8000ffac, 0x00000010, 0x001f0000,
- 0x00000000, 0x031e0000, 0x00000000, 0x83850800, 0x00000009, 0x076000ff,
- 0x0000000f, 0x0f0e0007, 0x00000000, 0x0c000000, 0x00000000, 0x0a7d0000,
- 0x00000000, 0x0afe0000, 0x00000000, 0x0b7f0000, 0x00000000, 0x0d7a0000,
- 0x00000000, 0x0bfc0000, 0x00000000, 0x0c970e00, 0x00000008, 0x0f800003,
- 0x0000000f, 0x47670010, 0x00000008, 0x070e0001, 0x0000000b, 0xc38000ff,
- 0x00000002, 0x43870000, 0x00000001, 0x33e70e00, 0x0000000f, 0x038e0010,
- 0x00000002, 0x33e70e00, 0x00000000, 0x39840000, 0x00000003, 0xb9720800,
- 0x00000000, 0x28f30000, 0x0000000f, 0x65680010, 0x00000010, 0x009f0000,
- 0x00000000, 0x02043600, 0x00000010, 0x91840a02, 0x00000002, 0x21421800,
- 0x00000008, 0x22000007, 0x00000000, 0x231b0000, 0x00000000, 0x23ff0000,
- 0x00000000, 0x241b0000, 0x00000003, 0x8384a000, 0x0000000f, 0x65870010,
- 0x00000009, 0x2607ffff, 0x00000000, 0x27110000, 0x00000000, 0x26900000,
- 0x0000000c, 0x29000000, 0x00000018, 0x80000145, 0x00000003, 0xf4683600,
- 0x00000000, 0x3a100000, 0x00000000, 0x3a910000, 0x00000003, 0xf66c2400,
- 0x00000010, 0x001f0000, 0x00000010, 0xb1923604, 0x00000008, 0x0f800004,
- 0x00000000, 0x00000000, 0x00000010, 0x009f0000, 0x00000000, 0x3e170000,
- 0x00000000, 0x3e940000, 0x00000000, 0x3f150000, 0x00000000, 0x3f960000,
- 0x00000010, 0x001f0000, 0x00000000, 0x0f060000, 0x00000010, 0x20530000,
- 0x00000000, 0x22c53600, 0x00000018, 0x8000ff73, 0x00000010, 0x0ce70005,
- 0x00000008, 0x2c80000c, 0x00000008, 0x2d000070, 0x00000008, 0x2d800010,
- 0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000018, 0x8000011d,
- 0x00000000, 0x2c1e0000, 0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010,
- 0x00000008, 0x2d800048, 0x00000000, 0x00000000, 0x00000010, 0x91de0000,
- 0x00000018, 0x8000fe5d, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
- 0x00000010, 0x001f0000, 0x00000000, 0x0f008000, 0x00000008, 0x0f800007,
- 0x00000018, 0x80000006, 0x0000000c, 0x29800001, 0x00000000, 0x2a000000,
- 0x00000010, 0x001f0000, 0x0000000f, 0x0f470007, 0x00000008, 0x0f800008,
- 0x00000018, 0x80000119, 0x00000010, 0x20530000, 0x00000018, 0x8000fe4f,
- 0x0000000c, 0x29800001, 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000,
- 0x00000000, 0x2a000000, 0x00000009, 0x0261ffff, 0x0000000d, 0x70e10001,
- 0x00000018, 0x80000101, 0x00000000, 0x2c400000, 0x00000008, 0x2c8000c4,
- 0x00000008, 0x2d00001c, 0x00000008, 0x2d800001, 0x00000005, 0x70e10800,
- 0x00000010, 0x91de0000, 0x00000018, 0x8000fe41, 0x0000000c, 0x29800001,
- 0x00000010, 0x91de0000, 0x00000000, 0x2fd50000, 0x00000010, 0x001f0000,
- 0x00000000, 0x02700000, 0x00000000, 0x0d620000, 0x00000000, 0xbb630800,
- 0x00000000, 0x2a000000, 0x00000000, 0x0f400000, 0x00000000, 0x2c400000,
- 0x0000000c, 0x73e7001b, 0x00000010, 0x0ce7000e, 0x00000000, 0x286d0000,
- 0x0000000f, 0x65ed0010, 0x00000009, 0x266dffff, 0x00000018, 0x80000069,
- 0x00000008, 0x02000004, 0x00000010, 0x91c40803, 0x00000018, 0x800000f6,
- 0x00000010, 0x20530000, 0x00000018, 0x800000e5, 0x00000008, 0x2c8000b8,
- 0x00000008, 0x2d000010, 0x00000008, 0x2d800048, 0x00000018, 0x80000005,
- 0x00000008, 0x2c8000c4, 0x00000008, 0x2d00001c, 0x00000008, 0x2d800001,
- 0x00000000, 0x00000000, 0x00000010, 0x205f0000, 0x00000008, 0x2c800048,
- 0x00000008, 0x2d000068, 0x00000008, 0x2d800104, 0x00000000, 0x00000000,
- 0x00000010, 0x91de0000, 0x00000000, 0x27f60000, 0x00000010, 0xb87a9e04,
- 0x00000008, 0x2200000d, 0x00000018, 0x800000e2, 0x00000010, 0x20530000,
- 0x00000018, 0x8000fe18, 0x0000000c, 0x29800001, 0x00000010, 0x91de0000,
- 0x00000000, 0x2fd50000, 0x00000010, 0x001f0000, 0x00000000, 0x02700000,
- 0x00000000, 0x0d620000, 0x00000000, 0xbb630800, 0x00000000, 0x2a000000,
- 0x00000010, 0x0e670011, 0x00000000, 0x286d0000, 0x0000000f, 0x65ed0010,
- 0x00000009, 0x266dffff, 0x00000004, 0xb8f1a000, 0x00000000, 0x0f400000,
- 0x0000000c, 0x73e7001c, 0x00000018, 0x80000040, 0x00000008, 0x02000004,
- 0x00000010, 0x91c40802, 0x00000018, 0x800000cd, 0x00000000, 0x2c1e0000,
- 0x00000008, 0x2c8000b8, 0x00000008, 0x2d000010, 0x00000008, 0x2d800048,
- 0x00000010, 0x20530000, 0x00000010, 0x91de0000, 0x00000018, 0x8000fdfe,
- 0x0000000c, 0x29800001, 0x00000000, 0x03550000, 0x00000000, 0x06460000,
- 0x00000000, 0x03d60000, 0x00000000, 0x2a000000, 0x0000000f, 0x0f480007,
- 0x00000010, 0xb18c0027, 0x0000000f, 0x47420008, 0x00000009, 0x070e000f,
- 0x00000008, 0x070e0008, 0x00000010, 0x001f0000, 0x00000008, 0x09000001,
- 0x00000007, 0x09121c00, 0x00000003, 0xcbca9200, 0x00000000, 0x0b97a200,
- 0x00000007, 0x4b171c00, 0x0000000f, 0x0a960003, 0x00000000, 0x0a959c00,
- 0x00000000, 0x4a009a00, 0x00000008, 0x82120001, 0x00000001, 0x0c170800,
- 0x00000000, 0x02180000, 0x00000000, 0x0c971800, 0x00000008, 0x0d00ffff,
- 0x00000008, 0x0f800006, 0x0000000c, 0x29000000, 0x00000008, 0x22000001,
- 0x00000000, 0x22c50c00, 0x00000010, 0x009f0000, 0x00000010, 0xb197320b,
- 0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
- 0x00000018, 0x800000a4, 0x00000000, 0x02180000, 0x00000010, 0x20530000,
- 0x00000000, 0x22c53600, 0x00000010, 0x001f0000, 0x00000008, 0x0f800006,
- 0x00000018, 0x8000fff5, 0x00000010, 0x91870002, 0x00000008, 0x2200000a,
- 0x00000000, 0x231b0000, 0x00000000, 0x27110800, 0x00000000, 0x66900000,
- 0x00000018, 0x80000098, 0x00000008, 0x0200000a, 0x00000010, 0x91c40804,
- 0x00000010, 0x02c20003, 0x00000010, 0x001f0000, 0x00000008, 0x0f800008,
- 0x00000010, 0x20530000, 0x00000018, 0x8000fdc9, 0x00000000, 0x06820000,
- 0x00000010, 0x001f0000, 0x00000010, 0x0ce70028, 0x00000000, 0x03720000,
- 0x00000000, 0xa8760c00, 0x00000000, 0x0cf60000, 0x00000010, 0xb8723224,
- 0x00000000, 0x03440000, 0x00000008, 0x22000010, 0x00000000, 0x03ca0000,
- 0x0000000f, 0x65680010, 0x00000000, 0x0bcf0000, 0x00000000, 0x27f20000,
- 0x00000010, 0xb7ef3203, 0x0000000c, 0x21420004, 0x0000000c, 0x73e70019,
- 0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x8000007e,
- 0x00000004, 0xb9723200, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
- 0x0000000c, 0x61420004, 0x00000000, 0x25070000, 0x00000000, 0x27970000,
- 0x00000000, 0x290e0000, 0x00000010, 0x0ce70010, 0x00000010, 0xb873320f,
- 0x0000000f, 0x436c0010, 0x00000000, 0x03f30c00, 0x00000000, 0x03f30000,
- 0x00000000, 0x83990e00, 0x00000001, 0x83860e00, 0x00000000, 0x83060e00,
- 0x00000003, 0xf66c0c00, 0x00000000, 0x39f30e00, 0x00000000, 0x3af50e00,
- 0x00000000, 0x7a740000, 0x0000000f, 0x43680010, 0x00000001, 0x83860e00,
- 0x00000000, 0x83060e00, 0x00000003, 0xf4680c00, 0x00000000, 0x286d0000,
- 0x00000000, 0x03690000, 0x00000010, 0xb1f60c54, 0x00000000, 0x0a6a0000,
- 0x00000000, 0x0aeb0000, 0x00000009, 0x0b6cffff, 0x00000000, 0x0c000000,
- 0x00000000, 0x0be90000, 0x00000003, 0x8cf6a000, 0x0000000c, 0x09800002,
- 0x00000010, 0x009f0000, 0x00000010, 0xb8173209, 0x00000000, 0x35140000,
- 0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34970000,
- 0x00000004, 0xb8f12e00, 0x00000010, 0x001f0000, 0x00000008, 0x0f800004,
- 0x00000018, 0x8000fff7, 0x00000000, 0x03e90000, 0x00000010, 0xb8f6a01a,
- 0x00000010, 0x20130019, 0x00000010, 0xb1f10e18, 0x00000000, 0x83973200,
- 0x00000000, 0x38700e00, 0x00000000, 0xbb760e00, 0x00000000, 0x37d00000,
- 0x0000000c, 0x73e7001a, 0x00000003, 0xb8f1a000, 0x00000000, 0x32140000,
- 0x00000000, 0x32950000, 0x00000005, 0x73e72c00, 0x00000000, 0x33190000,
- 0x00000005, 0x74680000, 0x00000010, 0x0ce7000d, 0x00000008, 0x22000009,
- 0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x0000000c, 0x73e70019,
- 0x0000000f, 0x65680010, 0x0000000c, 0x21420004, 0x00000018, 0x8000003c,
- 0x00000010, 0x20530000, 0x0000000c, 0x61420004, 0x00000000, 0x290e0000,
- 0x00000018, 0x80000002, 0x00000010, 0x91973206, 0x00000000, 0x35140000,
- 0x00000000, 0x35950000, 0x00000005, 0x766c2c00, 0x00000000, 0x34990000,
- 0x00000004, 0xb8f13200, 0x00000000, 0x83690c00, 0x00000010, 0xb1860013,
- 0x00000000, 0x28e90000, 0x00000008, 0x22000004, 0x00000000, 0x23ec0000,
- 0x00000000, 0x03690000, 0x00000010, 0xb8660c07, 0x00000009, 0x036cffff,
- 0x00000000, 0x326a0000, 0x00000000, 0x32eb0000, 0x00000005, 0x73e70c00,
- 0x00000000, 0x33690000, 0x00000005, 0x74680000, 0x0000000c, 0x73e7001c,
- 0x00000000, 0x03690000, 0x00000010, 0xb1f60c12, 0x00000010, 0xb1d00c11,
- 0x0000000c, 0x21420005, 0x0000000c, 0x33e7001c, 0x00000018, 0x8000000e,
- 0x00000010, 0x2e67000d, 0x00000000, 0x03690000, 0x00000010, 0xb1f60c0b,
- 0x00000010, 0xb1d00c0a, 0x00000000, 0x03440000, 0x00000008, 0x2200000c,
- 0x00000000, 0x07520000, 0x00000000, 0x29000000, 0x00000018, 0x80000015,
- 0x0000000c, 0x33e7001c, 0x00000010, 0x20530000, 0x00000000, 0x22060000,
- 0x00000000, 0x290e0000, 0x00000018, 0x000d0000, 0x00000000, 0x06820000,
- 0x00000010, 0x2de7000d, 0x00000010, 0x0ce7000c, 0x00000000, 0x27f20000,
- 0x00000010, 0xb96d9e0a, 0x00000000, 0xa86d9e00, 0x00000009, 0x0361ffff,
- 0x00000010, 0xb7500c07, 0x00000008, 0x2200000f, 0x0000000f, 0x65680010,
- 0x00000000, 0x29000000, 0x00000018, 0x80000004, 0x0000000c, 0x33e7001b,
- 0x00000010, 0x20530000, 0x00000018, 0x000d0000, 0x00000000, 0x2b820000,
- 0x00000010, 0x20d2002f, 0x00000010, 0x0052002e, 0x00000009, 0x054e0007,
- 0x00000010, 0xb18a002c, 0x00000000, 0x050a8c00, 0x00000008, 0x850a0008,
- 0x00000010, 0x918a0029, 0x00000003, 0xc5008800, 0x00000008, 0xa3460001,
- 0x00000010, 0xb1c60007, 0x00000008, 0x22000001, 0x0000000c, 0x29800000,
- 0x00000010, 0x20530000, 0x00000000, 0x274e8c00, 0x00000000, 0x66cd0000,
- 0x00000000, 0x22c58c00, 0x00000008, 0x22000014, 0x00000003, 0x22c58e00,
- 0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
- 0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
- 0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x0000000c, 0x69520000,
- 0x0000000c, 0x29800000, 0x00000010, 0x20530000, 0x00000003, 0x22c58e00,
- 0x00000003, 0x23c58e00, 0x00000003, 0x22c58e00, 0x00000003, 0x26cd9e00,
- 0x00000003, 0x27cd9e00, 0x00000003, 0x26cd9e00, 0x00000003, 0x274ea000,
- 0x00000003, 0x284ea000, 0x00000003, 0x274ea000, 0x00000000, 0xa2c58c00,
- 0x00000000, 0xa74e8c00, 0x00000000, 0xe6cd0000, 0x0000000f, 0x620a0010,
- 0x00000008, 0x23460001, 0x0000000c, 0x29800000, 0x00000010, 0x20530000,
- 0x0000000c, 0x29520000, 0x00000018, 0x80000002, 0x0000000c, 0x29800000,
- 0x00000018, 0x00570000 };
+static u8 bnx2_rv2p_proc2[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c,
+ 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2,
+ 0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18,
+ 0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda,
+ 0x9a, 0x56, 0x9b, 0x16, 0xfb, 0x81, 0xaf, 0x09, 0x14, 0x6a, 0x4c, 0x25,
+ 0xd6, 0x08, 0xc5, 0x47, 0xa0, 0x11, 0x1f, 0x84, 0xf0, 0xd3, 0x1f, 0x3b,
+ 0x8d, 0x7f, 0x0a, 0x24, 0x6a, 0x88, 0xc4, 0xa8, 0x9f, 0x24, 0x68, 0xa0,
+ 0x21, 0x0a, 0x58, 0x8b, 0x63, 0x4c, 0xb4, 0xf5, 0xec, 0xbd, 0xf6, 0xb9,
+ 0x73, 0xef, 0x6d, 0x8b, 0x1a, 0xf9, 0x70, 0x3e, 0xba, 0x7b, 0xce, 0xd9,
+ 0x67, 0x3f, 0xd6, 0xde, 0x67, 0x9f, 0x7d, 0xae, 0x52, 0xfc, 0xbb, 0xb6,
+ 0x94, 0xc9, 0x37, 0x83, 0x96, 0xfe, 0x1b, 0x51, 0x0f, 0x85, 0xd3, 0x3c,
+ 0x8e, 0x2a, 0xa2, 0x49, 0xa5, 0xb2, 0x5e, 0xea, 0x08, 0x7d, 0x44, 0xe8,
+ 0x70, 0x08, 0xf4, 0xb4, 0xd0, 0x77, 0x84, 0xfe, 0x2e, 0xf4, 0x80, 0xd0,
+ 0x0f, 0x85, 0xea, 0x5f, 0xd6, 0xd6, 0x7f, 0xf4, 0xb0, 0x46, 0x89, 0x7e,
+ 0x1b, 0xd3, 0x35, 0xb0, 0xe3, 0xc1, 0x05, 0xc4, 0x77, 0x61, 0xa2, 0xc0,
+ 0x87, 0xf9, 0x53, 0x7d, 0xa0, 0xd7, 0x60, 0xd7, 0xe1, 0xec, 0x0a, 0xb3,
+ 0x1f, 0x64, 0x43, 0x09, 0xe8, 0xc6, 0x08, 0xe8, 0xea, 0x65, 0x4c, 0x7a,
+ 0x9f, 0x0a, 0x63, 0xdc, 0xb8, 0x94, 0xf6, 0x87, 0x55, 0x83, 0x22, 0x3f,
+ 0x67, 0xaa, 0x68, 0x98, 0xc6, 0xf5, 0x56, 0x6c, 0x18, 0xeb, 0x8f, 0xa5,
+ 0x40, 0x37, 0x25, 0x41, 0xcf, 0x08, 0xdd, 0x52, 0x2c, 0x7a, 0x6c, 0x31,
+ 0xbf, 0x98, 0xf6, 0x25, 0x5c, 0x39, 0xc7, 0x6d, 0xe0, 0x96, 0x95, 0xfd,
+ 0x4a, 0xc1, 0xce, 0x03, 0xb2, 0x3e, 0xa3, 0x0a, 0xb3, 0xaf, 0x6f, 0xc1,
+ 0xb8, 0xfc, 0x20, 0xf9, 0xa7, 0xff, 0xcf, 0x62, 0x7e, 0xfa, 0xfd, 0xf8,
+ 0x15, 0xf6, 0x83, 0x96, 0x2f, 0xa2, 0x75, 0x27, 0xd3, 0x3f, 0x88, 0xf1,
+ 0xde, 0x25, 0x32, 0x1f, 0x36, 0xf8, 0x18, 0x79, 0x41, 0x5c, 0x99, 0x58,
+ 0xc7, 0x2a, 0x7d, 0xf2, 0x2b, 0x15, 0xe4, 0x2f, 0xc8, 0x2e, 0x35, 0xf2,
+ 0x81, 0xfb, 0xfa, 0x16, 0xb2, 0x73, 0x4c, 0xc7, 0x01, 0xb8, 0xcd, 0x0a,
+ 0x95, 0xb2, 0xdc, 0x7d, 0x83, 0x5e, 0x3d, 0x51, 0xad, 0x07, 0xfa, 0x54,
+ 0xa5, 0xc5, 0x20, 0x65, 0x97, 0x81, 0xaa, 0x5a, 0xbf, 0x1f, 0x7b, 0x97,
+ 0x18, 0x7b, 0x30, 0x9e, 0x9d, 0x01, 0xdd, 0x23, 0xf4, 0xaa, 0x3a, 0x26,
+ 0xcb, 0x7f, 0xb8, 0xc1, 0x62, 0x0c, 0xb2, 0xb5, 0xde, 0x7c, 0x38, 0x32,
+ 0x61, 0xf0, 0x52, 0x8b, 0x40, 0xce, 0x2e, 0x21, 0x3e, 0x1d, 0x9c, 0x4a,
+ 0xc8, 0x5d, 0xdf, 0x32, 0x55, 0x1e, 0x7d, 0x30, 0x45, 0x1e, 0x61, 0xff,
+ 0xb7, 0x2b, 0x7c, 0xf9, 0xa4, 0xda, 0x25, 0x4f, 0x36, 0x22, 0x8f, 0xac,
+ 0xa7, 0x3e, 0x91, 0x85, 0x6b, 0x13, 0xfa, 0xcf, 0x84, 0x7a, 0x32, 0x4e,
+ 0x01, 0x8a, 0x2b, 0x87, 0xfd, 0x53, 0xe2, 0xe7, 0x26, 0xed, 0x27, 0xd1,
+ 0x8a, 0x50, 0xb6, 0x36, 0xc1, 0x38, 0x35, 0xc4, 0xa0, 0xaf, 0x61, 0x03,
+ 0xb6, 0xaf, 0x46, 0x5c, 0x7b, 0x4f, 0x86, 0x8d, 0xfd, 0x51, 0xfa, 0x3b,
+ 0xd0, 0xb6, 0x9d, 0x47, 0x03, 0xd1, 0x1d, 0x4c, 0xed, 0x63, 0x95, 0x58,
+ 0xee, 0x8a, 0xf0, 0x7a, 0x72, 0x97, 0xcc, 0xf7, 0xec, 0xf0, 0xdb, 0xfd,
+ 0x02, 0xf2, 0xdb, 0x7e, 0x7e, 0x47, 0x88, 0xa8, 0x13, 0x73, 0xf9, 0x98,
+ 0x3a, 0x3b, 0xb7, 0x13, 0xff, 0x55, 0x6a, 0xd7, 0x20, 0x29, 0x4e, 0xab,
+ 0x0d, 0x6b, 0xb1, 0x6f, 0x77, 0x2c, 0xc5, 0xb8, 0x36, 0xad, 0x05, 0xfd,
+ 0x1e, 0xf3, 0xf3, 0x9d, 0x1e, 0xe2, 0x2f, 0x9d, 0xe7, 0x0c, 0x71, 0x5e,
+ 0xa9, 0x11, 0xce, 0xc7, 0x04, 0x65, 0x06, 0xff, 0xda, 0xaa, 0xc1, 0xdf,
+ 0xbc, 0x99, 0x15, 0xbf, 0xd9, 0x9a, 0xe7, 0x3c, 0x18, 0xe8, 0x18, 0x26,
+ 0x3f, 0xe7, 0xaa, 0x91, 0x4e, 0xa2, 0x51, 0xd5, 0xb0, 0x90, 0xf0, 0x5e,
+ 0x15, 0x36, 0x71, 0x3a, 0x7f, 0x33, 0xcd, 0xcf, 0xd3, 0xeb, 0x26, 0x1e,
+ 0x24, 0xd7, 0x92, 0x78, 0x45, 0x5d, 0x7c, 0xf2, 0x61, 0xf8, 0xdb, 0xcd,
+ 0x76, 0x5f, 0x97, 0xec, 0xe6, 0xfc, 0x4a, 0xaa, 0x26, 0x8e, 0x7f, 0xd4,
+ 0x6a, 0x1b, 0xc6, 0xfa, 0xf9, 0x8f, 0x8d, 0x5c, 0xd2, 0x53, 0x23, 0x75,
+ 0x44, 0xb9, 0x72, 0xa2, 0x37, 0x83, 0xee, 0x34, 0x7a, 0xeb, 0x88, 0x6f,
+ 0xb1, 0x42, 0xfe, 0x26, 0x26, 0xc9, 0x69, 0x03, 0xce, 0xf6, 0x33, 0xec,
+ 0xf7, 0x35, 0xf6, 0x85, 0x3e, 0x63, 0x2f, 0xe6, 0x2f, 0xfa, 0xf4, 0x95,
+ 0x7b, 0xf4, 0x11, 0x7f, 0x51, 0xf2, 0x02, 0xef, 0x9b, 0x63, 0x3d, 0x3b,
+ 0xcc, 0xb8, 0x58, 0xcf, 0x0c, 0x41, 0xfe, 0xc5, 0x21, 0xe2, 0x9f, 0x23,
+ 0x7a, 0xed, 0xff, 0x88, 0xe7, 0x9c, 0x30, 0xe4, 0x4c, 0x8f, 0x5f, 0xc1,
+ 0x6f, 0xe3, 0x17, 0xcb, 0xb5, 0x47, 0x73, 0x69, 0xe6, 0x33, 0xf1, 0xe8,
+ 0x0e, 0x73, 0x02, 0xa6, 0x1b, 0x16, 0xfa, 0x71, 0x33, 0xf6, 0x9c, 0xdf,
+ 0xcc, 0x79, 0x3e, 0xd1, 0x26, 0x75, 0x40, 0x71, 0x9d, 0xb9, 0x5d, 0xe2,
+ 0xa1, 0xf3, 0x3a, 0x04, 0xff, 0x46, 0x73, 0x2c, 0x3f, 0xd9, 0xc5, 0x79,
+ 0xb9, 0xd2, 0x8e, 0xe6, 0x38, 0x5e, 0xd6, 0xd9, 0x21, 0x6c, 0x2b, 0xd4,
+ 0x4f, 0xc8, 0x6b, 0xb6, 0x41, 0x9b, 0xa4, 0x8e, 0x9e, 0x15, 0xda, 0x6d,
+ 0x33, 0x3e, 0xba, 0x8e, 0x59, 0x2c, 0x3f, 0x9b, 0x32, 0xf7, 0x0c, 0xd6,
+ 0x9f, 0x16, 0x39, 0x3f, 0x0a, 0x55, 0x22, 0xa7, 0x55, 0xf6, 0x9f, 0xf3,
+ 0xc9, 0x89, 0x04, 0xe4, 0x84, 0x94, 0xc1, 0xcd, 0x9c, 0xef, 0x5d, 0x52,
+ 0xbf, 0xf7, 0xc5, 0xa6, 0xab, 0xb7, 0x7c, 0x0e, 0xdc, 0xba, 0x5a, 0x8e,
+ 0x3a, 0x53, 0x1f, 0x0d, 0xb3, 0xbf, 0x03, 0xdd, 0x3b, 0x80, 0x53, 0x8f,
+ 0xe0, 0x14, 0x07, 0x4e, 0xf3, 0x0a, 0xf5, 0x59, 0x14, 0xd4, 0x90, 0xfe,
+ 0x53, 0x21, 0xe3, 0xc7, 0xbe, 0x98, 0xaf, 0xfe, 0xf6, 0x9a, 0xfa, 0x5b,
+ 0xa8, 0xd3, 0xc4, 0xff, 0xb3, 0xa9, 0x6f, 0x5a, 0x9f, 0xd1, 0xff, 0x6f,
+ 0xf5, 0x72, 0x9c, 0x92, 0xdd, 0x7d, 0x26, 0xce, 0x98, 0x2e, 0xd4, 0xd9,
+ 0x22, 0x22, 0xcb, 0x46, 0x3a, 0x99, 0x5e, 0xdf, 0xbc, 0x15, 0xf3, 0x65,
+ 0x7c, 0x4e, 0x6e, 0x09, 0x01, 0xaf, 0xa8, 0x3a, 0xde, 0x87, 0xba, 0xae,
+ 0xe2, 0x2c, 0xaf, 0xe2, 0x28, 0xc7, 0x3f, 0xaa, 0xe5, 0x12, 0xdf, 0x67,
+ 0xa1, 0x42, 0x3e, 0x7a, 0xfd, 0xd9, 0xad, 0xf3, 0x84, 0xec, 0x88, 0xe9,
+ 0xbc, 0xa5, 0xb1, 0x3e, 0x47, 0xb6, 0xe4, 0xf9, 0x1a, 0xe6, 0xb3, 0xc7,
+ 0x22, 0x34, 0xff, 0x80, 0xd5, 0xd3, 0x87, 0xf9, 0x9f, 0x1a, 0x69, 0xbc,
+ 0xce, 0x7e, 0x0d, 0xe7, 0xcc, 0x7e, 0x0d, 0xf5, 0xcb, 0x2a, 0x3a, 0x88,
+ 0xba, 0xd6, 0x78, 0x10, 0xf2, 0x71, 0x4f, 0x7b, 0xfd, 0xf2, 0xe2, 0x47,
+ 0xe7, 0xe1, 0xb2, 0x38, 0xd9, 0xcf, 0x09, 0x4e, 0x97, 0x7c, 0xf1, 0x39,
+ 0x6c, 0xe2, 0xd3, 0x1b, 0x93, 0xf3, 0xd2, 0x7c, 0x29, 0xe8, 0x17, 0xf1,
+ 0x9d, 0x71, 0xef, 0x9d, 0xae, 0x95, 0xa0, 0xdd, 0x2b, 0xe5, 0x9c, 0xd6,
+ 0xf9, 0xf3, 0x6b, 0x3e, 0xea, 0xf2, 0xb8, 0x7b, 0x4f, 0x20, 0xbf, 0xac,
+ 0x9d, 0xf0, 0x4b, 0xbd, 0x28, 0x79, 0x3c, 0x2e, 0xf4, 0x65, 0xc9, 0xdf,
+ 0x6d, 0xd2, 0xb7, 0x98, 0xfe, 0xe2, 0x0f, 0xcc, 0x3b, 0xfd, 0x6e, 0x5f,
+ 0x60, 0xea, 0x36, 0x8d, 0x43, 0xca, 0x89, 0x13, 0x83, 0x36, 0xeb, 0x33,
+ 0x24, 0x4a, 0xcf, 0x1a, 0xe0, 0x35, 0x52, 0x07, 0xbe, 0xdd, 0x91, 0xb0,
+ 0x8c, 0x21, 0x6f, 0xac, 0xda, 0x77, 0x0f, 0xd7, 0x4f, 0xc6, 0x93, 0xe4,
+ 0xc6, 0xdc, 0xfa, 0x24, 0x79, 0xaf, 0x26, 0x84, 0x96, 0x2f, 0xbe, 0x2c,
+ 0xbe, 0x85, 0xfe, 0x64, 0xa9, 0x17, 0xdf, 0x97, 0x34, 0xbe, 0xbc, 0xaf,
+ 0xbe, 0xf9, 0x12, 0xa6, 0x4b, 0x6f, 0x05, 0xed, 0xbb, 0x95, 0xe7, 0x17,
+ 0xa3, 0xee, 0x11, 0x7e, 0x9c, 0x5f, 0xf5, 0x6f, 0x0c, 0x9a, 0x7e, 0x42,
+ 0xf0, 0x08, 0xf4, 0x41, 0x65, 0x77, 0x80, 0xbe, 0x29, 0x74, 0xce, 0x2a,
+ 0xd0, 0xbd, 0xab, 0xfc, 0x71, 0x88, 0xa5, 0x7c, 0x71, 0xac, 0x47, 0x1c,
+ 0x8f, 0x4c, 0x04, 0xeb, 0x81, 0xc4, 0x4b, 0xc7, 0x27, 0x70, 0xbf, 0x1b,
+ 0xfd, 0xe2, 0xce, 0xdf, 0xc5, 0xed, 0x4a, 0xc7, 0xab, 0x7b, 0x25, 0xee,
+ 0x93, 0x0e, 0xe9, 0x4b, 0xc7, 0xdc, 0xfb, 0xe2, 0x9f, 0xc4, 0x31, 0x7e,
+ 0x85, 0xe3, 0x78, 0xf7, 0xff, 0x2c, 0x8e, 0x9d, 0x12, 0xc7, 0x22, 0xb9,
+ 0x57, 0x4d, 0xbf, 0xd9, 0x2e, 0x7d, 0x18, 0xf5, 0x8d, 0x7e, 0xbd, 0x4f,
+ 0x70, 0x1f, 0x78, 0xb5, 0x5b, 0x8f, 0xe7, 0x33, 0x7f, 0x4e, 0xf6, 0x95,
+ 0xca, 0xbe, 0x7b, 0x26, 0xed, 0x3b, 0xc5, 0xf5, 0xee, 0xf1, 0xf1, 0xc9,
+ 0xef, 0x15, 0x9f, 0x9d, 0x59, 0x95, 0x02, 0xee, 0xa8, 0xe3, 0xb1, 0x29,
+ 0xde, 0x37, 0x86, 0x1f, 0xf9, 0xb5, 0x36, 0x85, 0xba, 0x05, 0xfe, 0xb9,
+ 0x9e, 0x7a, 0x4a, 0xe3, 0xfb, 0xc7, 0xa7, 0xef, 0x57, 0x8d, 0x3c, 0xc4,
+ 0x6d, 0x43, 0xb8, 0x84, 0xf9, 0x4e, 0xb7, 0xf3, 0x7d, 0xe7, 0xfa, 0xb7,
+ 0x9a, 0xfd, 0x3a, 0x2a, 0xfe, 0x55, 0x88, 0x7f, 0x7a, 0xb9, 0x96, 0xeb,
+ 0xbe, 0x75, 0xba, 0xdd, 0xeb, 0xdf, 0x9d, 0x97, 0xd1, 0xf7, 0x4f, 0xfb,
+ 0x63, 0xd1, 0x9b, 0x32, 0xfa, 0x49, 0x5e, 0xb9, 0xf4, 0x7d, 0xd4, 0x4f,
+ 0x62, 0x7e, 0x72, 0x9f, 0x41, 0xfa, 0x5b, 0x34, 0x5e, 0x72, 0xdf, 0x70,
+ 0x3e, 0x47, 0xac, 0xa3, 0x6c, 0x57, 0x5e, 0xf9, 0x71, 0x39, 0x23, 0x7c,
+ 0x53, 0xc5, 0x8d, 0xd6, 0x8b, 0x64, 0x7d, 0x2a, 0xbf, 0xc5, 0x4e, 0x37,
+ 0x1f, 0x64, 0x1f, 0xf3, 0x35, 0x0b, 0x5f, 0x34, 0x34, 0x39, 0xfe, 0x18,
+ 0xe5, 0xab, 0x38, 0xaf, 0xf7, 0x6f, 0xcb, 0x11, 0x9f, 0x76, 0x9e, 0xf3,
+ 0xf0, 0xfb, 0x80, 0x7d, 0xe9, 0x2b, 0x80, 0x23, 0xf1, 0xcd, 0x50, 0x4d,
+ 0xce, 0x74, 0x78, 0xe1, 0xdd, 0x30, 0x9a, 0x33, 0x78, 0xdb, 0xec, 0xe7,
+ 0x48, 0x27, 0xe9, 0x5f, 0x1d, 0xc0, 0x31, 0x2c, 0x38, 0x9e, 0x50, 0x7f,
+ 0x9f, 0xf7, 0xc6, 0x0f, 0x6f, 0x5e, 0x8c, 0xff, 0x19, 0xcc, 0xe3, 0x87,
+ 0xe5, 0x5d, 0xdd, 0x18, 0x03, 0xfd, 0x2e, 0x62, 0xec, 0x46, 0x5e, 0xdf,
+ 0xc3, 0xe7, 0xb5, 0x4a, 0xf5, 0xf2, 0xbb, 0xc3, 0x52, 0x0d, 0x6b, 0xc9,
+ 0xee, 0x94, 0xae, 0x7f, 0xc8, 0x77, 0x27, 0xee, 0xbd, 0xb7, 0x75, 0x0d,
+ 0x4c, 0xc4, 0x69, 0x58, 0x31, 0x33, 0xc1, 0x82, 0xde, 0xf8, 0xe2, 0x4b,
+ 0x5e, 0x7e, 0xaf, 0xbf, 0x18, 0xf3, 0x65, 0xf7, 0x91, 0x9c, 0x88, 0xda,
+ 0x8b, 0xba, 0xfb, 0xee, 0x1e, 0xd0, 0xb7, 0xd5, 0xbd, 0xd8, 0x3f, 0x73,
+ 0x3b, 0xd7, 0x51, 0xab, 0x4c, 0xf2, 0x2b, 0x0d, 0x5c, 0xd3, 0xa8, 0xc3,
+ 0x13, 0x13, 0xaa, 0x04, 0xf7, 0x9a, 0x79, 0x07, 0xab, 0x1a, 0xd1, 0x8b,
+ 0xfa, 0x68, 0x17, 0xde, 0xc1, 0x44, 0x8b, 0x83, 0x7d, 0x9f, 0x55, 0xe8,
+ 0xaf, 0x08, 0x8f, 0xf7, 0x5d, 0x1c, 0xd3, 0xe1, 0x60, 0x5d, 0xf2, 0xfa,
+ 0x15, 0x93, 0x73, 0xfd, 0xab, 0xfb, 0x6e, 0xee, 0xe1, 0x7e, 0x2a, 0x19,
+ 0xac, 0xcb, 0x01, 0xf9, 0xfb, 0x24, 0x7e, 0x49, 0x89, 0x5f, 0x54, 0xc7,
+ 0x0f, 0xef, 0xed, 0x4f, 0x7d, 0xef, 0x7a, 0xaa, 0x1b, 0xde, 0xbc, 0xfb,
+ 0xfc, 0x4f, 0x63, 0xd7, 0xf6, 0x98, 0xb7, 0x0e, 0x57, 0xbb, 0xe7, 0xae,
+ 0x43, 0xde, 0x8b, 0x5d, 0x87, 0x30, 0xce, 0x73, 0xbf, 0xbc, 0x38, 0xd3,
+ 0x21, 0x79, 0x74, 0x57, 0x44, 0xf2, 0x41, 0xec, 0xfb, 0x22, 0x62, 0xee,
+ 0x1b, 0x8c, 0xbf, 0x92, 0xfb, 0xee, 0x97, 0x2a, 0xf4, 0xd9, 0x17, 0x87,
+ 0xcc, 0xfb, 0xc4, 0xbc, 0x57, 0xb0, 0xbe, 0x3e, 0xae, 0x04, 0x67, 0xbe,
+ 0xff, 0xb5, 0x3f, 0x9c, 0xaf, 0x99, 0x8e, 0x61, 0x1f, 0x5e, 0x2a, 0x16,
+ 0x78, 0xbf, 0xc4, 0xe5, 0xfb, 0x45, 0xbf, 0xe0, 0xe1, 0xf0, 0xf9, 0x29,
+ 0xd5, 0xf6, 0x13, 0x4d, 0x65, 0x3a, 0x73, 0xb0, 0xa7, 0xd5, 0xed, 0x23,
+ 0xc1, 0x27, 0xd4, 0x79, 0x4b, 0xde, 0xc1, 0xf2, 0x5e, 0xd6, 0xef, 0x61,
+ 0xf4, 0x73, 0xad, 0x79, 0x8c, 0xc7, 0xd0, 0xb7, 0x39, 0xbf, 0xca, 0xbd,
+ 0xb5, 0x75, 0x9b, 0xe9, 0x4b, 0xa7, 0xde, 0x67, 0xee, 0xb9, 0xb6, 0x6a,
+ 0xd0, 0x16, 0xee, 0x5b, 0x1f, 0xb2, 0xf3, 0x92, 0x1f, 0x85, 0x77, 0x89,
+ 0xff, 0x3d, 0x62, 0xfa, 0x85, 0x73, 0xc5, 0xb8, 0x67, 0xf3, 0xbd, 0x34,
+ 0xa1, 0xdf, 0x23, 0x09, 0x6f, 0x9e, 0x25, 0x32, 0x65, 0x82, 0xfb, 0xec,
+ 0x9b, 0x40, 0xf7, 0xdc, 0x84, 0xbe, 0xbc, 0xb5, 0x4b, 0x70, 0xb8, 0x91,
+ 0x71, 0x5b, 0x3e, 0x9a, 0x0b, 0x7e, 0x67, 0x21, 0x5c, 0x7f, 0x73, 0xfb,
+ 0xd1, 0x73, 0x6c, 0xd7, 0xbc, 0x81, 0x3c, 0xf3, 0xcd, 0x55, 0xb3, 0xf8,
+ 0xfc, 0xa6, 0x9d, 0x51, 0xd8, 0x99, 0xe9, 0x17, 0xbf, 0xda, 0x6f, 0x01,
+ 0xed, 0x92, 0x3a, 0x73, 0xd2, 0x7d, 0x97, 0xc3, 0x4e, 0x53, 0x4f, 0x26,
+ 0xbf, 0x13, 0x30, 0x9e, 0x5b, 0xc7, 0x63, 0xd5, 0xbc, 0x95, 0xe4, 0x97,
+ 0x4c, 0x7a, 0xcf, 0x16, 0xe2, 0x6e, 0xf2, 0xc1, 0xe4, 0x8f, 0xf7, 0x1d,
+ 0x7b, 0x9b, 0xa7, 0x5e, 0xfa, 0xe3, 0xef, 0x70, 0xbe, 0x84, 0x65, 0x3d,
+ 0x96, 0xe9, 0xef, 0xbb, 0x3c, 0x3e, 0x6f, 0x01, 0x9f, 0x8c, 0xd8, 0x6d,
+ 0xb7, 0xf0, 0x3b, 0x74, 0x96, 0xda, 0x25, 0xf1, 0x39, 0x57, 0x2d, 0x75,
+ 0x50, 0xec, 0xfb, 0x49, 0xfa, 0x1f, 0xc4, 0x31, 0x6e, 0x6f, 0xc9, 0x49,
+ 0xdc, 0x24, 0x8f, 0x9e, 0x16, 0xbf, 0x7f, 0x84, 0xdf, 0xb6, 0xf1, 0xbb,
+ 0xc5, 0xf5, 0xdb, 0xd4, 0x59, 0xaf, 0x9c, 0x99, 0x3a, 0x1f, 0xb8, 0x5e,
+ 0xdb, 0x27, 0xf9, 0xdd, 0x53, 0x24, 0xe7, 0xa1, 0x42, 0xbe, 0x3b, 0x38,
+ 0xe2, 0x4f, 0x89, 0x6a, 0x5a, 0xee, 0xdd, 0x57, 0x2c, 0xfb, 0x92, 0x7a,
+ 0x1f, 0xe6, 0x71, 0xfe, 0xec, 0x29, 0xf0, 0x34, 0xdf, 0x11, 0x8c, 0xdc,
+ 0xe0, 0x39, 0xf2, 0xe2, 0xc7, 0x37, 0x13, 0xff, 0x50, 0x07, 0x74, 0x9c,
+ 0x6a, 0xcd, 0xf7, 0x07, 0xcc, 0xe3, 0xfc, 0x26, 0xf7, 0xb7, 0xa1, 0xaf,
+ 0xdc, 0xdf, 0x76, 0x48, 0xfa, 0x08, 0xc1, 0xe5, 0x81, 0x21, 0xb2, 0x43,
+ 0xc7, 0xae, 0xd2, 0x7f, 0xfe, 0x61, 0x47, 0x54, 0xec, 0x28, 0xf7, 0xd8,
+ 0x11, 0xd0, 0x7b, 0x1d, 0xcd, 0xaf, 0x50, 0x5f, 0x73, 0x1e, 0x2e, 0x57,
+ 0xeb, 0x29, 0x47, 0xf4, 0xbd, 0xb0, 0xae, 0x88, 0xc6, 0xcb, 0xd4, 0xab,
+ 0xf0, 0xb7, 0x37, 0x59, 0x84, 0x3a, 0x96, 0xdc, 0x49, 0xf3, 0x35, 0xea,
+ 0xd5, 0x3e, 0x0e, 0xc4, 0x2b, 0xea, 0x18, 0xea, 0x73, 0xe3, 0x41, 0xb6,
+ 0x47, 0x1d, 0x1f, 0x34, 0xf5, 0x7a, 0xca, 0xef, 0x98, 0xbd, 0xeb, 0xa4,
+ 0x5e, 0x9c, 0xc0, 0x77, 0x51, 0xfd, 0x5e, 0x23, 0xfe, 0xd9, 0xe6, 0x3d,
+ 0xb8, 0xfb, 0x98, 0xa1, 0x8b, 0x7c, 0xe3, 0xfd, 0x27, 0x96, 0x0a, 0xad,
+ 0xf2, 0x8d, 0x07, 0xd6, 0x55, 0x09, 0xad, 0x36, 0xe3, 0xe9, 0xbe, 0x2b,
+ 0x5e, 0x29, 0xf9, 0x62, 0xf7, 0x7b, 0xe2, 0xcf, 0x47, 0xe2, 0xcf, 0x59,
+ 0xe0, 0x9f, 0xdc, 0x28, 0x78, 0x2c, 0x0a, 0xea, 0x17, 0xbb, 0xdc, 0x73,
+ 0x63, 0xd6, 0x11, 0x8f, 0x47, 0xd5, 0x5f, 0x3f, 0x97, 0x8f, 0x31, 0xd8,
+ 0x17, 0x00, 0x00, 0x00 };
static const int bnx2_TPAT_b06FwReleaseMajor = 0x1;
static const int bnx2_TPAT_b06FwReleaseMinor = 0x0;
@@ -2339,201 +1330,199 @@ static const u32 bnx2_TPAT_b06FwBssAddr = 0x08001aa0;
static const int bnx2_TPAT_b06FwBssLen = 0x250;
static const u32 bnx2_TPAT_b06FwSbssAddr = 0x08001a60;
static const int bnx2_TPAT_b06FwSbssLen = 0x34;
-static u32 bnx2_TPAT_b06FwText[(0x122c/4) + 1] = {
- 0x0a000218, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20322e35,
- 0x2e313100, 0x02050b01, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800,
- 0x24421a60, 0x3c030800, 0x24631cf0, 0xac400000, 0x0043202b, 0x1480fffd,
- 0x24420004, 0x3c1d0800, 0x37bd2ffc, 0x03a0f021, 0x3c100800, 0x26100860,
- 0x3c1c0800, 0x279c1a60, 0x0e000546, 0x00000000, 0x0000000d, 0x8f820010,
- 0x8c450008, 0x24030800, 0xaf430178, 0x97430104, 0x3c020008, 0xaf420140,
- 0x8f820024, 0x30420001, 0x10400007, 0x3069ffff, 0x24020002, 0x2523fffe,
- 0xa7420146, 0xa7430148, 0x0a000242, 0x3c020800, 0xa7400146, 0x3c020800,
- 0x8c43083c, 0x1460000e, 0x24020f00, 0x8f820024, 0x30430020, 0x0003182b,
- 0x00031823, 0x30650009, 0x30420c00, 0x24030400, 0x14430002, 0x34a40001,
- 0x34a40005, 0xa744014a, 0x0a000264, 0x3c020800, 0x8f830014, 0x14620008,
- 0x00000000, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023, 0x3042000d,
- 0x0a000262, 0x34420005, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023,
- 0x30420009, 0x34420001, 0xa742014a, 0x3c020800, 0x8c430820, 0x8f840024,
- 0x3c020048, 0x00621825, 0x30840006, 0x24020002, 0x1082000d, 0x2c820003,
- 0x50400005, 0x24020004, 0x10800012, 0x3c020001, 0x0a000284, 0x00000000,
- 0x10820007, 0x24020006, 0x1482000f, 0x3c020111, 0x0a00027c, 0x00621025,
- 0x0a00027b, 0x3c020101, 0x3c020011, 0x00621025, 0x24030001, 0xaf421000,
- 0xaf830020, 0x0a000284, 0x00000000, 0x00621025, 0xaf421000, 0xaf800020,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f830020, 0x1060003f,
- 0x3c048000, 0x8f421000, 0x00441024, 0x1040fffd, 0x00000000, 0x10600039,
- 0x00000000, 0x8f421000, 0x3c030020, 0x00431024, 0x10400034, 0x00000000,
- 0x97421014, 0x14400031, 0x00000000, 0x97421008, 0x8f840010, 0x24420006,
- 0x00024082, 0x00081880, 0x00643821, 0x8ce50000, 0x30430003, 0x30420001,
- 0x10400004, 0x00000000, 0x0000000d, 0x0a0002c3, 0x00081080, 0x5460000f,
- 0x30a5ffff, 0x3c06ffff, 0x00a62824, 0x0005182b, 0x00a61026, 0x0002102b,
- 0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x240001fb,
- 0x8ce20000, 0x0a0002c2, 0x00462825, 0x0005182b, 0x38a2ffff, 0x0002102b,
- 0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x24000205,
- 0x8ce20000, 0x3445ffff, 0x00081080, 0x00441021, 0x3c030800, 0xac450000,
- 0x8c620830, 0x24420001, 0xac620830, 0x8f840018, 0x01202821, 0x24820008,
- 0x30421fff, 0x24434000, 0x0343d821, 0x30a30007, 0xaf84000c, 0xaf820018,
- 0xaf420084, 0x10600002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000,
- 0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023,
- 0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000,
- 0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x8f830024, 0x27bdffe0,
- 0xafbf0018, 0xafb10014, 0x30620200, 0x14400004, 0xafb00010, 0x0000000d,
- 0x00000000, 0x24000242, 0x00031a82, 0x30630003, 0x000310c0, 0x00431021,
- 0x00021080, 0x00431021, 0x00021080, 0x3c030800, 0x24631aa0, 0x00438821,
- 0x8e240000, 0x10800004, 0x00000000, 0x0000000d, 0x00000000, 0x2400024d,
- 0x8f850010, 0x24020001, 0xae220000, 0x8ca70008, 0xa2200007, 0x8f620004,
- 0x26300014, 0x02002021, 0x00021402, 0xa2220004, 0x304600ff, 0x24c60005,
- 0x0e000673, 0x00063082, 0x8f620004, 0xa6220008, 0x8f430108, 0x3c021000,
- 0x00621824, 0x10600008, 0x00000000, 0x97420104, 0x92230007, 0x2442ffec,
- 0x3045ffff, 0x34630002, 0x0a000321, 0xa2230007, 0x97420104, 0x2442fff0,
- 0x3045ffff, 0x8f620004, 0x3042ffff, 0x2c420013, 0x54400005, 0x92230007,
- 0x92220007, 0x34420001, 0xa2220007, 0x92230007, 0x24020001, 0x10620009,
- 0x28620002, 0x14400014, 0x24020002, 0x10620012, 0x24020003, 0x1062000a,
- 0x00000000, 0x0a000342, 0x00000000, 0x8f820010, 0x8c43000c, 0x3c04ffff,
- 0x00641824, 0x00651825, 0x0a000342, 0xac43000c, 0x8f820010, 0x8c430010,
- 0x3c04ffff, 0x00641824, 0x00651825, 0xac430010, 0x8f620004, 0x3042ffff,
- 0x24420002, 0x00021083, 0xa2220005, 0x304500ff, 0x8f820010, 0x3c04ffff,
- 0x00052880, 0x00a22821, 0x8ca70000, 0x96220008, 0x97430104, 0x00e42024,
- 0x24420002, 0x00621823, 0x00833825, 0xaca70000, 0x92240005, 0x00041080,
- 0x02021021, 0x90430000, 0x3c05fff6, 0x34a5ffff, 0x3063000f, 0x00832021,
- 0xa2240006, 0x308200ff, 0x24420003, 0x00021080, 0x02021021, 0x8c460000,
- 0x308300ff, 0x8f820010, 0x3c04ff3f, 0x00031880, 0x00c53824, 0x00621821,
- 0xae26000c, 0xac67000c, 0x8e22000c, 0x92230006, 0x3484ffff, 0x00441024,
- 0x24630003, 0x00031880, 0x02031821, 0x00e42024, 0xae22000c, 0xac640000,
- 0x92220006, 0x24420004, 0x00021080, 0x02021021, 0x94470002, 0xac470000,
- 0x92230006, 0x8f820010, 0x00031880, 0x00621821, 0x24020010, 0xac670010,
- 0x24030002, 0xa7420140, 0xa7400142, 0xa7400144, 0xa7430146, 0x97420104,
- 0x24030001, 0x2442fffe, 0xa7420148, 0xa743014a, 0x8f820024, 0x24030002,
- 0x30440006, 0x1083000d, 0x2c820003, 0x10400005, 0x24020004, 0x10800011,
- 0x3c020009, 0x0a0003a5, 0x00000000, 0x10820007, 0x24020006, 0x1482000d,
- 0x3c020119, 0x0a00039f, 0x24030001, 0x0a00039e, 0x3c020109, 0x3c020019,
- 0x24030001, 0xaf421000, 0xaf830020, 0x0a0003a5, 0x00000000, 0xaf421000,
- 0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92220004,
- 0x24030008, 0x8f840020, 0x24420002, 0x30420007, 0x00621823, 0x30630007,
- 0x10800006, 0xae230010, 0x3c038000, 0x8f421000, 0x00431024, 0x1040fffd,
- 0x00000000, 0x8f820018, 0xaf82000c, 0x24420010, 0x30421fff, 0xaf820018,
- 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007,
- 0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821,
- 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030,
- 0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021,
- 0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008,
- 0x27bd0020, 0x8f830024, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x30620200,
- 0x14400004, 0xafb00010, 0x0000000d, 0x00000000, 0x240002e4, 0x00031a82,
- 0x30630003, 0x000310c0, 0x00431021, 0x00021080, 0x00431021, 0x00021080,
- 0x3c030800, 0x24631aa0, 0x00438021, 0x8e040000, 0x14800004, 0x00000000,
- 0x0000000d, 0x00000000, 0x240002e9, 0x8f620004, 0x04410008, 0x26050014,
- 0x92020006, 0x8e03000c, 0x24420003, 0x00021080, 0x00a21021, 0xac430000,
- 0xae000000, 0x92020005, 0x24420001, 0x00021080, 0x00a21021, 0x8c430000,
- 0x3c040001, 0x00641821, 0xac430000, 0x92060004, 0x27710008, 0x02202021,
- 0x24c60005, 0x0e000673, 0x00063082, 0x92040006, 0x3c057fff, 0x8f620004,
- 0x00042080, 0x00912021, 0x8c830004, 0x34a5ffff, 0x00451024, 0x00621821,
- 0xac830004, 0x92050005, 0x3c07ffff, 0x92040004, 0x00052880, 0x00b12821,
- 0x8ca30000, 0x97420104, 0x96060008, 0x00671824, 0x00441021, 0x00461023,
- 0x3042ffff, 0x00621825, 0xaca30000, 0x92030007, 0x24020001, 0x1062000a,
- 0x28620002, 0x1440001d, 0x2402000a, 0x24020002, 0x10620019, 0x24020003,
- 0x1062000e, 0x2402000a, 0x0a000447, 0x00000000, 0x92020004, 0x97430104,
- 0x8e24000c, 0x00621821, 0x2463fff2, 0x3063ffff, 0x00872024, 0x00832025,
- 0xae24000c, 0x0a000447, 0x2402000a, 0x92020004, 0x97430104, 0x8e240010,
- 0x00621821, 0x2463ffee, 0x3063ffff, 0x00872024, 0x00832025, 0xae240010,
- 0x2402000a, 0xa7420140, 0x96030012, 0x8f840024, 0xa7430142, 0x92020004,
- 0xa7420144, 0xa7400146, 0x97430104, 0x30840006, 0x24020001, 0xa7430148,
- 0xa742014a, 0x24020002, 0x1082000d, 0x2c820003, 0x10400005, 0x24020004,
- 0x10800011, 0x3c020041, 0x0a00046c, 0x00000000, 0x10820007, 0x24020006,
- 0x1482000d, 0x3c020151, 0x0a000466, 0x24030001, 0x0a000465, 0x3c020141,
- 0x3c020051, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00046c, 0x00000000,
- 0xaf421000, 0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x8f820020, 0x8f840018, 0x10400006, 0x92030004, 0x3c058000, 0x8f421000,
- 0x00451024, 0x1040fffd, 0x00000000, 0x2463000a, 0x30620007, 0x10400002,
- 0x24620007, 0x304303f8, 0x00831021, 0x30421fff, 0xaf84000c, 0xaf820018,
- 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007,
- 0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821,
- 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030,
- 0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021,
- 0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008,
- 0x27bd0020, 0x8f620000, 0x97430104, 0x3c048000, 0x3045ffff, 0x3066ffff,
- 0x8f420178, 0x00441024, 0x1440fffd, 0x2402000a, 0x30a30007, 0xa7420140,
- 0x24020008, 0x00431023, 0x30420007, 0x24a3fffe, 0xa7420142, 0xa7430144,
- 0xa7400146, 0xa7460148, 0x8f420108, 0x8f830024, 0x30420020, 0x0002102b,
- 0x00021023, 0x30420009, 0x34420001, 0x30630006, 0xa742014a, 0x24020002,
- 0x1062000d, 0x2c620003, 0x10400005, 0x24020004, 0x10600011, 0x3c020041,
- 0x0a0004d6, 0x00000000, 0x10620007, 0x24020006, 0x1462000d, 0x3c020151,
- 0x0a0004d0, 0x24030001, 0x0a0004cf, 0x3c020141, 0x3c020051, 0x24030001,
- 0xaf421000, 0xaf830020, 0x0a0004d6, 0x00000000, 0xaf421000, 0xaf800020,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f820020, 0x24a30008,
- 0x8f850018, 0x10400006, 0x30c6ffff, 0x3c048000, 0x8f421000, 0x00441024,
- 0x1040fffd, 0x00000000, 0x3063ffff, 0x30620007, 0x10400002, 0x24620007,
- 0x3043fff8, 0x00a31021, 0x30421fff, 0x24434000, 0x0343d821, 0x00c02021,
- 0x30830007, 0xaf85000c, 0xaf820018, 0xaf420084, 0x10600002, 0x24820007,
- 0x3044fff8, 0x8f820030, 0x8f850000, 0x00441821, 0xaf82001c, 0x0065102b,
- 0xaf830030, 0x14400002, 0x00651023, 0xaf820030, 0x8f840030, 0x34028000,
- 0x3c030800, 0x8c650834, 0x00821021, 0x03421821, 0xaf830010, 0xaf440080,
- 0x10a00006, 0x2402000e, 0x9383002f, 0x14620004, 0x3c021000, 0x2402043f,
- 0xa7420148, 0x3c021000, 0x03e00008, 0xaf420178, 0x8f820024, 0x30424000,
- 0x10400005, 0x24020800, 0x0000000d, 0x00000000, 0x2400040e, 0x24020800,
- 0xaf420178, 0x97440104, 0x3c030008, 0xaf430140, 0x8f820024, 0x30420001,
- 0x10400006, 0x3085ffff, 0x24020002, 0x24a3fffe, 0xa7420146, 0x0a000526,
- 0xa7430148, 0xa7400146, 0x8f840018, 0x2402000d, 0xa742014a, 0x24830008,
- 0x30631fff, 0x24624000, 0x0342d821, 0x30a20007, 0xaf84000c, 0xaf830018,
- 0xaf430084, 0x10400002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000,
- 0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023,
- 0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000,
- 0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x27bdffe8, 0x3c046008,
- 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, 0x375b4000,
- 0x00431024, 0x3442380c, 0xac825000, 0x8f430008, 0x3c100800, 0x37428000,
- 0x34630001, 0xaf430008, 0xaf820010, 0x3c02601c, 0xaf800018, 0xaf400080,
- 0xaf400084, 0x8c450008, 0x3c036000, 0x8c620808, 0x3c040800, 0x3c030080,
- 0xac830820, 0x3042fff0, 0x38420010, 0x2c420001, 0xaf850000, 0xaf820004,
- 0x0e000658, 0x00000000, 0x8f420000, 0x30420001, 0x1040fffb, 0x00000000,
- 0x8f430108, 0x8f440100, 0x30622000, 0xaf830024, 0xaf840014, 0x10400004,
- 0x8e02082c, 0x24420001, 0x0a0005c6, 0xae02082c, 0x30620200, 0x14400003,
- 0x24020f00, 0x14820027, 0x24020d00, 0x97420104, 0x1040001c, 0x30624000,
- 0x14400005, 0x00000000, 0x0e00022f, 0x00000000, 0x0a0005bb, 0x00000000,
- 0x8f620008, 0x8f630000, 0x24020030, 0x00031e02, 0x306300f0, 0x10620007,
- 0x28620031, 0x1440002f, 0x24020040, 0x10620007, 0x00000000, 0x0a0005bb,
- 0x00000000, 0x0e0002e8, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0003db,
- 0x00000000, 0x0a0005bb, 0x00000000, 0x30620040, 0x1440002b, 0x00000000,
- 0x0000000d, 0x00000000, 0x240004b2, 0x0a0005c6, 0x00000000, 0x1482000f,
- 0x30620006, 0x97420104, 0x10400005, 0x30620040, 0x0e000510, 0x00000000,
- 0x0a0005bb, 0x00000000, 0x1440001b, 0x00000000, 0x0000000d, 0x00000000,
- 0x240004c4, 0x0a0005c6, 0x00000000, 0x1040000e, 0x30621000, 0x10400005,
- 0x00000000, 0x0e000688, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0004a1,
- 0x00000000, 0x8f82002c, 0x24420001, 0xaf82002c, 0x0a0005c6, 0x00000000,
- 0x30620040, 0x14400004, 0x00000000, 0x0000000d, 0x00000000, 0x240004db,
- 0x8f420138, 0x3c034000, 0x00431025, 0xaf420138, 0x0a000566, 0x00000000,
- 0x3c046008, 0x8c835000, 0x3c1a8000, 0x2402ff7f, 0x375b4000, 0x00621824,
- 0x3463380c, 0xac835000, 0x8f420008, 0x3c056000, 0x3c03601c, 0x34420001,
- 0xaf420008, 0x37428000, 0xaf800018, 0xaf820010, 0xaf400080, 0xaf400084,
- 0x8c660008, 0x8ca20808, 0x3c040800, 0x3c030080, 0xac830820, 0x3042fff0,
- 0x38420010, 0x2c420001, 0xaf860000, 0xaf820004, 0x03e00008, 0x00000000,
- 0x3084ffff, 0x30820007, 0x10400002, 0x24820007, 0x3044fff8, 0x8f820018,
- 0x00441821, 0x30631fff, 0x24644000, 0x0344d821, 0xaf82000c, 0xaf830018,
- 0x03e00008, 0xaf430084, 0x3084ffff, 0x30820007, 0x10400002, 0x24820007,
- 0x3044fff8, 0x8f820030, 0x8f830000, 0x00442021, 0xaf82001c, 0x0083102b,
- 0xaf840030, 0x14400002, 0x00831023, 0xaf820030, 0x8f820030, 0x34038000,
- 0x00431821, 0x03432021, 0xaf840010, 0x03e00008, 0xaf420080, 0x8f830024,
- 0x24020002, 0x30630006, 0x1062000d, 0x2c620003, 0x50400005, 0x24020004,
- 0x10600012, 0x3c020001, 0x0a00062a, 0x00000000, 0x10620007, 0x24020006,
- 0x1462000f, 0x3c020111, 0x0a000622, 0x00821025, 0x0a000621, 0x3c020101,
- 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00062a,
- 0x00000000, 0x00821025, 0xaf421000, 0xaf800020, 0x00000000, 0x00000000,
- 0x00000000, 0x03e00008, 0x00000000, 0x8f820020, 0x10400005, 0x3c038000,
- 0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x03e00008, 0x00000000,
- 0x8f820024, 0x27bdffe8, 0x30424000, 0x14400005, 0xafbf0010, 0x0e00022f,
- 0x00000000, 0x0a000656, 0x8fbf0010, 0x8f620008, 0x8f630000, 0x24020030,
- 0x00031e02, 0x306300f0, 0x10620008, 0x28620031, 0x1440000d, 0x8fbf0010,
- 0x24020040, 0x10620007, 0x00000000, 0x0a000656, 0x00000000, 0x0e0002e8,
- 0x00000000, 0x0a000656, 0x8fbf0010, 0x0e0003db, 0x00000000, 0x8fbf0010,
- 0x03e00008, 0x27bd0018, 0x8f840028, 0x1080000f, 0x3c026000, 0x8c430c3c,
- 0x30630fff, 0xaf830008, 0x14600011, 0x3082000f, 0x10400005, 0x308200f0,
- 0x10400003, 0x30820f00, 0x14400006, 0x00000000, 0x0000000d, 0x00000000,
- 0x2400051a, 0x03e00008, 0x00000000, 0x0000000d, 0x00000000, 0x2400051f,
- 0x03e00008, 0x00000000, 0xaf830028, 0x03e00008, 0x00000000, 0x10c00007,
- 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb,
- 0x24840004, 0x03e00008, 0x00000000, 0x0a000684, 0x00a01021, 0xac860000,
- 0x00000000, 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa, 0x24a5ffff,
- 0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x00000000};
+static u8 bnx2_TPAT_b06FwText[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68,
+ 0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d,
+ 0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5,
+ 0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08,
+ 0xe4, 0xb2, 0x1d, 0x49, 0x36, 0x85, 0x1e, 0x5a, 0x9a, 0x43, 0xa0, 0x05,
+ 0x0f, 0x33, 0xeb, 0x34, 0x87, 0xc5, 0xdb, 0xaa, 0xc5, 0xbe, 0x94, 0xd6,
+ 0x95, 0xea, 0xe8, 0xb2, 0x68, 0xe2, 0x53, 0x0f, 0xc5, 0xd8, 0xb4, 0x54,
+ 0xd0, 0x53, 0x7b, 0x0a, 0x85, 0x5c, 0x4c, 0x69, 0x20, 0x85, 0x12, 0x44,
+ 0x0f, 0x21, 0xd4, 0xad, 0xa7, 0xcf, 0xfb, 0xcd, 0x8c, 0xbc, 0xbb, 0x95,
+ 0x5b, 0x1f, 0x02, 0x15, 0xac, 0x66, 0xe6, 0xfb, 0xde, 0xf7, 0xfb, 0x79,
+ 0x9f, 0xe7, 0x79, 0xbf, 0xf7, 0x6b, 0xca, 0x34, 0x49, 0xe5, 0xdf, 0x14,
+ 0x7e, 0x6f, 0x7f, 0xe3, 0xdb, 0x6f, 0x7f, 0xf5, 0xa5, 0x57, 0x2c, 0xa2,
+ 0x57, 0x5e, 0x92, 0x64, 0x5d, 0xa6, 0x2f, 0xe0, 0x4f, 0x21, 0x32, 0xab,
+ 0xf1, 0xf9, 0x47, 0x86, 0xec, 0x75, 0xce, 0x04, 0x0e, 0x19, 0x8a, 0x77,
+ 0x34, 0xbb, 0xe9, 0x10, 0xf9, 0x83, 0x15, 0x2b, 0xa4, 0x7f, 0xe5, 0x71,
+ 0x43, 0x25, 0x6e, 0x7f, 0xc1, 0xfb, 0xe7, 0xb9, 0x7b, 0xe7, 0xed, 0xa3,
+ 0xdb, 0x0a, 0x19, 0xa6, 0xd7, 0x31, 0xcc, 0x45, 0x32, 0x66, 0xe1, 0xf3,
+ 0xd3, 0xa5, 0x75, 0x8d, 0xa6, 0xab, 0xb1, 0x4c, 0x4a, 0xfa, 0x06, 0xad,
+ 0xf5, 0x30, 0x8e, 0xf3, 0x8e, 0x14, 0x66, 0xaa, 0x14, 0xde, 0x32, 0x48,
+ 0xf6, 0x7c, 0x29, 0xc8, 0x1c, 0xf4, 0x49, 0x14, 0xb8, 0x35, 0xf2, 0xcd,
+ 0x3c, 0xff, 0xa6, 0x2b, 0x93, 0xec, 0x3c, 0xce, 0xe7, 0x17, 0xd6, 0xa5,
+ 0x60, 0x7f, 0x43, 0x0a, 0xf7, 0x03, 0xde, 0x37, 0xd6, 0xb1, 0x2e, 0xf9,
+ 0xfb, 0xfc, 0xf4, 0x8c, 0xb0, 0x37, 0x4d, 0x9d, 0x06, 0xcd, 0xc8, 0x0e,
+ 0xfb, 0x5a, 0x14, 0xba, 0x2b, 0x4d, 0x85, 0xe6, 0xf1, 0x9b, 0xa0, 0x6d,
+ 0x97, 0xea, 0x81, 0x4b, 0xaa, 0xe2, 0xc8, 0x14, 0x36, 0x24, 0xfa, 0x65,
+ 0x4b, 0xc3, 0xef, 0x92, 0xd4, 0xde, 0xdf, 0x2a, 0xc7, 0x69, 0x50, 0x8a,
+ 0xb5, 0x44, 0x0d, 0x5e, 0x5b, 0xe1, 0x1f, 0xb8, 0x2b, 0xa6, 0x4c, 0xf3,
+ 0xf8, 0x4d, 0xe1, 0x3d, 0x82, 0x9d, 0x46, 0x41, 0x6b, 0xbc, 0x6f, 0x02,
+ 0xef, 0x58, 0x27, 0xc6, 0x0a, 0xc4, 0x3a, 0x2c, 0xac, 0xc3, 0xa1, 0x6e,
+ 0x7f, 0x03, 0xfb, 0x58, 0x68, 0x46, 0xa4, 0x53, 0x57, 0xac, 0x7d, 0x8a,
+ 0x12, 0x53, 0xa1, 0xe4, 0xac, 0x46, 0xfe, 0x65, 0x15, 0xdf, 0xcf, 0x51,
+ 0x6c, 0x4a, 0xb0, 0xe9, 0x96, 0xf8, 0xd5, 0xd0, 0xaf, 0xa3, 0x7d, 0x86,
+ 0x92, 0xc6, 0x29, 0x49, 0xf6, 0xbe, 0x8f, 0xf6, 0x05, 0x33, 0xa2, 0xef,
+ 0xe1, 0x29, 0xe1, 0xfb, 0x14, 0x8f, 0x87, 0x6f, 0x89, 0x14, 0x87, 0xcc,
+ 0x20, 0xb3, 0x28, 0xcd, 0x2a, 0x5f, 0x6e, 0x2f, 0xda, 0xe2, 0x6c, 0x1c,
+ 0x3b, 0xd8, 0xf5, 0x5f, 0xa5, 0x8e, 0x49, 0xb1, 0xea, 0xc1, 0xa6, 0xef,
+ 0x98, 0x6d, 0xe0, 0xe4, 0x0b, 0x3c, 0xbf, 0xc6, 0xed, 0xfc, 0x87, 0x76,
+ 0x8b, 0x14, 0xcf, 0x31, 0x43, 0x6a, 0x51, 0xd1, 0xd7, 0x30, 0x83, 0x5b,
+ 0x2f, 0x93, 0x2f, 0xe2, 0x61, 0xe0, 0xdd, 0xc4, 0x9e, 0x74, 0x60, 0x9b,
+ 0xf8, 0x32, 0xc5, 0x4d, 0x83, 0xec, 0xd5, 0x2d, 0xf4, 0x7c, 0xdc, 0x53,
+ 0x10, 0x67, 0xc6, 0x49, 0x2d, 0xfd, 0x18, 0xd7, 0xdf, 0x62, 0x5d, 0xb1,
+ 0x69, 0xd0, 0x0c, 0x75, 0x5e, 0xcf, 0xf3, 0x3b, 0x6e, 0x9e, 0xeb, 0x9e,
+ 0xb3, 0xfc, 0x3e, 0xad, 0x34, 0x35, 0x5a, 0x34, 0xf1, 0x44, 0xdc, 0x1c,
+ 0xc4, 0x46, 0x2d, 0xe7, 0x9f, 0x2a, 0xd7, 0xfa, 0x48, 0x42, 0xe8, 0xe9,
+ 0xcf, 0xbd, 0xdf, 0xf0, 0xde, 0x97, 0xd7, 0x85, 0x7d, 0x9e, 0xef, 0xae,
+ 0x3e, 0xcd, 0x5e, 0x93, 0x0b, 0xfb, 0x3c, 0x5f, 0x6b, 0xf1, 0x7c, 0x36,
+ 0xf6, 0xc6, 0x9c, 0x24, 0x5a, 0x1b, 0xb8, 0x46, 0xd4, 0xc3, 0xba, 0x1c,
+ 0x3c, 0x07, 0x4d, 0xac, 0xdd, 0x5e, 0xb6, 0x24, 0x83, 0x12, 0x27, 0x7f,
+ 0x11, 0x3c, 0xf0, 0x43, 0xc7, 0xfe, 0x53, 0xa8, 0xd4, 0x68, 0xcf, 0xad,
+ 0x53, 0x37, 0x6b, 0x52, 0x92, 0x75, 0x29, 0xc8, 0x64, 0x8c, 0x5f, 0xa3,
+ 0x5d, 0xe7, 0xf3, 0x7c, 0xcd, 0x75, 0x81, 0x33, 0xb1, 0x5f, 0x73, 0x8d,
+ 0x66, 0xd1, 0xbf, 0x62, 0x6e, 0x91, 0x8b, 0x98, 0xcb, 0x88, 0xc9, 0xbc,
+ 0x78, 0x4f, 0x32, 0x17, 0xfd, 0x14, 0xcb, 0x2d, 0xdb, 0x4c, 0xc8, 0x6e,
+ 0x06, 0x0a, 0x99, 0xb2, 0x67, 0xc2, 0x26, 0xa6, 0x76, 0x66, 0xd0, 0x43,
+ 0xe5, 0x1d, 0xc1, 0xe3, 0xb4, 0xff, 0x30, 0xbf, 0xb7, 0xd4, 0xa4, 0xfb,
+ 0x59, 0x83, 0xee, 0x66, 0x24, 0x47, 0x1c, 0xab, 0x86, 0x49, 0x1f, 0x64,
+ 0xd5, 0x3e, 0xc0, 0x65, 0x27, 0x39, 0xa3, 0x40, 0x67, 0x9b, 0xee, 0x03,
+ 0xb0, 0xc4, 0x06, 0x0e, 0x31, 0xf6, 0x5c, 0x3d, 0x79, 0x4f, 0xb7, 0xcf,
+ 0x6c, 0x3a, 0xf6, 0x7b, 0x21, 0xb3, 0xf3, 0x86, 0x8a, 0xd6, 0xe1, 0x38,
+ 0x7c, 0x1d, 0xfe, 0x26, 0x5d, 0x87, 0x5e, 0x64, 0xc4, 0x63, 0xee, 0xc0,
+ 0xa0, 0xfd, 0x5e, 0x8d, 0xac, 0x5d, 0x95, 0xa2, 0x7e, 0x83, 0xdc, 0x45,
+ 0xdb, 0x22, 0x59, 0x6e, 0xc8, 0x88, 0xdf, 0xdc, 0x6e, 0x4e, 0xeb, 0xae,
+ 0x46, 0x87, 0xce, 0x77, 0x75, 0x9a, 0x4e, 0x5c, 0x9d, 0xd8, 0xc6, 0xa0,
+ 0xb9, 0xf7, 0x0d, 0x29, 0xec, 0xf3, 0xfa, 0x39, 0xce, 0x46, 0x19, 0x67,
+ 0x55, 0x0a, 0x6e, 0xd5, 0x68, 0x7e, 0xe7, 0x6f, 0x79, 0xe0, 0x20, 0xc6,
+ 0xe0, 0xf1, 0x66, 0xcb, 0x56, 0x68, 0x12, 0x6d, 0xbb, 0xdc, 0x77, 0x54,
+ 0xb6, 0xf3, 0x18, 0x79, 0x1e, 0xb8, 0xcf, 0x53, 0xc0, 0xfc, 0x7e, 0x9d,
+ 0x7d, 0x6a, 0x34, 0xb7, 0xc3, 0xba, 0xc0, 0x73, 0x97, 0xbf, 0x79, 0x6d,
+ 0x13, 0x14, 0x61, 0x37, 0xd1, 0x72, 0x03, 0xfb, 0x97, 0x85, 0x06, 0x22,
+ 0xec, 0x56, 0x76, 0x26, 0xf1, 0x14, 0x71, 0x50, 0x0a, 0x3e, 0x73, 0x5e,
+ 0xa8, 0x53, 0x08, 0x5c, 0x55, 0xac, 0x67, 0x8b, 0x16, 0x9a, 0xdb, 0xa2,
+ 0x0f, 0x6d, 0x03, 0xee, 0x33, 0xc7, 0xfa, 0xf0, 0x3d, 0xa8, 0xd6, 0x20,
+ 0x03, 0xf3, 0x14, 0xb3, 0x68, 0x62, 0xaf, 0x6b, 0x2e, 0xdb, 0xb3, 0x6d,
+ 0xbc, 0xac, 0x91, 0xbd, 0xbc, 0x8b, 0xd1, 0xf7, 0x7b, 0xd8, 0xef, 0x4d,
+ 0xce, 0x35, 0x8e, 0xf5, 0x17, 0x62, 0xfb, 0x79, 0xec, 0x79, 0x61, 0x35,
+ 0xe5, 0xbe, 0x81, 0x46, 0xce, 0x4e, 0x6c, 0xaa, 0x88, 0xbd, 0x8c, 0xc0,
+ 0x87, 0x3f, 0xfc, 0x2c, 0xd7, 0x3c, 0x70, 0xb8, 0x35, 0x03, 0x6c, 0x6c,
+ 0x2b, 0x85, 0x9e, 0x1d, 0x8c, 0x9b, 0xb8, 0x0a, 0xfc, 0x0a, 0x8c, 0xd8,
+ 0x6e, 0xbd, 0x97, 0x53, 0x2a, 0xe6, 0xba, 0xc6, 0x73, 0x21, 0xe7, 0x38,
+ 0xab, 0xbf, 0x03, 0x27, 0x22, 0xaa, 0xd3, 0xe2, 0x41, 0x9d, 0xae, 0x0e,
+ 0xea, 0x34, 0x77, 0x43, 0x47, 0x1c, 0xf2, 0xbc, 0xdb, 0x62, 0x0d, 0x02,
+ 0x6b, 0x87, 0xed, 0xec, 0xa6, 0x22, 0xf3, 0x3a, 0xd0, 0x7f, 0x40, 0xb4,
+ 0x35, 0xd0, 0x11, 0x37, 0x75, 0x68, 0x6c, 0x99, 0x2e, 0xfe, 0x84, 0xe8,
+ 0xe2, 0x80, 0x7d, 0x79, 0xfc, 0xc2, 0x27, 0xc2, 0x9e, 0x65, 0x60, 0x7e,
+ 0x75, 0x20, 0x23, 0x1f, 0x20, 0x5f, 0xee, 0x07, 0xc8, 0x83, 0x6d, 0xfc,
+ 0xd6, 0x91, 0x1b, 0x19, 0x1b, 0xce, 0x13, 0x8f, 0x81, 0xcf, 0x06, 0xfa,
+ 0x2e, 0xa1, 0x8d, 0xf3, 0x16, 0xdb, 0xea, 0xd4, 0x76, 0xa7, 0x28, 0xad,
+ 0x72, 0x91, 0xc9, 0xb9, 0xe8, 0x14, 0xf8, 0x34, 0x81, 0xfc, 0x72, 0x47,
+ 0x19, 0xcd, 0x45, 0xc8, 0x59, 0x8d, 0xd3, 0xc8, 0x3d, 0x3f, 0x47, 0x3b,
+ 0x8f, 0xf7, 0x33, 0x3c, 0x27, 0xf0, 0x7d, 0x1a, 0xb6, 0xc3, 0x79, 0xa8,
+ 0xf2, 0x7b, 0x5a, 0x0e, 0x02, 0xef, 0x76, 0x0c, 0xd8, 0x5b, 0xd0, 0x0b,
+ 0xc7, 0xbb, 0x86, 0x7c, 0xc1, 0x31, 0xaf, 0x21, 0xa6, 0x3a, 0xe6, 0x36,
+ 0x69, 0xfe, 0x80, 0x62, 0xa5, 0xcc, 0x4f, 0xe1, 0x71, 0x7e, 0x6a, 0x0a,
+ 0x1e, 0x24, 0x99, 0x09, 0x1f, 0xd6, 0x6d, 0xa5, 0x53, 0xc6, 0x8e, 0xfc,
+ 0x00, 0x1a, 0x0e, 0x94, 0x3c, 0xdf, 0xc4, 0x19, 0x11, 0x01, 0x77, 0x1f,
+ 0xda, 0x8d, 0xa0, 0xdd, 0x70, 0x48, 0xbb, 0xe1, 0xff, 0xd4, 0x2e, 0x74,
+ 0x09, 0x8d, 0xdc, 0x05, 0xa7, 0x3e, 0xe8, 0x9f, 0xa4, 0x63, 0xd6, 0x30,
+ 0x6b, 0xd9, 0xa2, 0x7b, 0x4b, 0xcf, 0xa2, 0xe5, 0xbf, 0x3e, 0xab, 0x96,
+ 0x63, 0xd6, 0xb2, 0xca, 0x5a, 0x6e, 0x0c, 0x6b, 0xf9, 0x53, 0xf8, 0x17,
+ 0x9a, 0xbc, 0xa0, 0x36, 0x48, 0x5b, 0x04, 0x0e, 0x3b, 0x75, 0x52, 0x6e,
+ 0x3c, 0xe1, 0x1b, 0x73, 0x38, 0x1c, 0xe0, 0xdf, 0x81, 0x86, 0x3e, 0x69,
+ 0xb4, 0x1d, 0x39, 0x4f, 0xf5, 0xec, 0xe6, 0x96, 0xb0, 0x51, 0x49, 0x47,
+ 0xdc, 0xbf, 0xb3, 0x64, 0x5b, 0x96, 0x3c, 0xac, 0x79, 0xa8, 0x7e, 0x27,
+ 0xbf, 0xa6, 0x79, 0x3c, 0x4f, 0x6c, 0x81, 0xeb, 0xd6, 0x8f, 0x80, 0x51,
+ 0xda, 0x63, 0x9e, 0x3b, 0xe6, 0x9a, 0xe0, 0x17, 0xbe, 0xa1, 0x05, 0x0d,
+ 0x7c, 0xad, 0xc1, 0x4e, 0xdd, 0x29, 0xf4, 0x73, 0x17, 0xe3, 0xee, 0xf5,
+ 0x98, 0x5f, 0x06, 0xe9, 0x37, 0x9d, 0xe6, 0x55, 0x91, 0x73, 0xe7, 0xcd,
+ 0x75, 0x62, 0xed, 0xf1, 0x79, 0x87, 0xfe, 0x41, 0x8d, 0x14, 0xa1, 0xf7,
+ 0xc9, 0x52, 0xef, 0x2f, 0x20, 0x46, 0x93, 0xf8, 0x66, 0xcd, 0x9f, 0x2e,
+ 0x35, 0x3f, 0x8d, 0x27, 0xb7, 0x5d, 0x54, 0x0b, 0xee, 0x80, 0x87, 0x3b,
+ 0x8c, 0x6b, 0x1d, 0xf9, 0x8d, 0xe7, 0xff, 0x7b, 0xbe, 0xe9, 0x30, 0xb6,
+ 0x8e, 0xf5, 0x03, 0x5a, 0x80, 0xee, 0xd0, 0x7e, 0xc0, 0xb6, 0xec, 0x53,
+ 0xd9, 0x9a, 0xa5, 0xed, 0xa7, 0x63, 0xb6, 0x68, 0x3f, 0x60, 0x3b, 0xd6,
+ 0xc5, 0x73, 0xa4, 0xdc, 0xe4, 0xf3, 0x38, 0x60, 0x5d, 0xc0, 0xaf, 0x8d,
+ 0x36, 0xae, 0x19, 0xd8, 0x9f, 0xcf, 0x66, 0x5e, 0x27, 0xd7, 0x13, 0x7c,
+ 0x7e, 0x8f, 0x9d, 0xd3, 0xc7, 0xda, 0xb8, 0x00, 0xbe, 0x7f, 0x4b, 0xfd,
+ 0x4f, 0x6d, 0xbc, 0x06, 0x2d, 0x5c, 0x51, 0x0b, 0x6d, 0x6c, 0xe3, 0x79,
+ 0x01, 0xdf, 0xaf, 0x8d, 0x69, 0xa3, 0xf2, 0x7b, 0xfa, 0xf9, 0x9c, 0xf4,
+ 0x9b, 0xe2, 0x6c, 0xe5, 0xf9, 0x94, 0x1d, 0x8a, 0xb5, 0x52, 0x07, 0x6b,
+ 0xc7, 0x3a, 0x98, 0x44, 0xae, 0x18, 0xe1, 0xb8, 0x12, 0xba, 0xb6, 0x99,
+ 0x12, 0x6b, 0x62, 0xf8, 0xfc, 0xfa, 0x7f, 0xe9, 0x82, 0xc0, 0x23, 0x31,
+ 0x37, 0x6a, 0x0c, 0x3e, 0x0f, 0xf2, 0xfc, 0x8a, 0x8b, 0xfe, 0xaa, 0xd6,
+ 0x10, 0xd8, 0xf3, 0x59, 0xcb, 0x78, 0xa0, 0xbe, 0x73, 0xe6, 0xa1, 0x05,
+ 0xce, 0x01, 0x8f, 0xf3, 0x3d, 0x27, 0x40, 0x5b, 0x1b, 0xf1, 0x67, 0x4c,
+ 0x36, 0xa4, 0xf5, 0x7d, 0x83, 0xfd, 0xa0, 0xb3, 0x93, 0x6a, 0x2c, 0x1d,
+ 0x9a, 0x7a, 0x82, 0x13, 0xf3, 0x28, 0x1a, 0xc2, 0xa9, 0x23, 0x70, 0xfa,
+ 0xf0, 0x18, 0xa7, 0xa8, 0xc4, 0x29, 0x12, 0x38, 0xfd, 0xb1, 0xc4, 0xe9,
+ 0x0f, 0x4f, 0xc1, 0xe9, 0xc3, 0x67, 0xc0, 0xc9, 0xa0, 0x3d, 0xa7, 0x89,
+ 0x73, 0x56, 0x17, 0x35, 0xe9, 0xa1, 0x7b, 0x52, 0x4d, 0x75, 0x52, 0xdc,
+ 0x6d, 0x73, 0x8f, 0x86, 0xeb, 0x0e, 0xdb, 0x7a, 0x80, 0xf5, 0xa5, 0xc0,
+ 0xee, 0xfa, 0x58, 0xed, 0x91, 0xc0, 0xbe, 0x5d, 0xe2, 0x74, 0x1d, 0x38,
+ 0xb5, 0x4b, 0x9c, 0xb6, 0x87, 0x70, 0xda, 0x1e, 0xc1, 0x89, 0xf3, 0x49,
+ 0xcb, 0xd8, 0xee, 0x55, 0x18, 0x55, 0xf8, 0xe8, 0x74, 0xdb, 0x9c, 0xc6,
+ 0xfe, 0xcf, 0x51, 0xfa, 0x63, 0x95, 0xeb, 0x5a, 0x60, 0xf7, 0xaa, 0x2a,
+ 0x8b, 0xf3, 0x80, 0xdf, 0x9f, 0xd4, 0x27, 0x98, 0xcb, 0x0f, 0x5c, 0x8e,
+ 0x23, 0xea, 0x57, 0xa7, 0xca, 0x43, 0xcf, 0xab, 0xa8, 0xad, 0xf0, 0xcd,
+ 0x36, 0xaa, 0xd4, 0x86, 0xde, 0x15, 0xd4, 0xe5, 0xe1, 0x71, 0x5d, 0x5e,
+ 0xc4, 0xe0, 0x7a, 0x59, 0x97, 0xef, 0x39, 0x5c, 0x97, 0x2f, 0x6a, 0x34,
+ 0xb9, 0x51, 0x62, 0xc9, 0x9c, 0x9e, 0x42, 0xdf, 0x25, 0x81, 0x79, 0x8a,
+ 0xfc, 0xbd, 0x89, 0xfd, 0x47, 0x82, 0x9b, 0xa8, 0xb1, 0x4a, 0xde, 0xa2,
+ 0x86, 0xa5, 0x30, 0x2b, 0x62, 0xf5, 0xc5, 0xd6, 0x5d, 0x9f, 0x20, 0x4f,
+ 0x1b, 0x1d, 0x15, 0x75, 0xfd, 0xfd, 0x8c, 0xf3, 0x33, 0x5d, 0x4e, 0x7a,
+ 0x14, 0x9f, 0xf1, 0xae, 0xe5, 0xc0, 0xdc, 0x7f, 0xeb, 0x3c, 0x9f, 0x33,
+ 0xf5, 0xd5, 0xa0, 0x85, 0xf6, 0x81, 0x41, 0xa8, 0x7d, 0x70, 0x4f, 0xa1,
+ 0x38, 0x38, 0x2f, 0xa1, 0xc6, 0xc1, 0x37, 0x7c, 0x92, 0x6c, 0xb6, 0x23,
+ 0x7b, 0x4d, 0x70, 0x21, 0x26, 0x1f, 0xeb, 0xf4, 0x33, 0x71, 0x57, 0xe9,
+ 0x28, 0x9e, 0x81, 0xda, 0x92, 0x0c, 0x9c, 0xf3, 0x88, 0x89, 0x65, 0xa4,
+ 0x03, 0xd4, 0x41, 0x38, 0xfb, 0x83, 0x55, 0xc4, 0xe5, 0x2c, 0x70, 0xcb,
+ 0x54, 0xf8, 0xbe, 0xa9, 0x17, 0xf7, 0x1c, 0x54, 0x35, 0x22, 0x5e, 0x8f,
+ 0x4a, 0x7e, 0x88, 0x3a, 0x4b, 0x6a, 0xf7, 0xc9, 0x8a, 0x5c, 0xf0, 0x1c,
+ 0xe7, 0x48, 0x37, 0xe3, 0xda, 0xf9, 0xac, 0x21, 0xdf, 0xe0, 0x5c, 0x7e,
+ 0x88, 0x18, 0xe2, 0xfd, 0x80, 0xcf, 0x16, 0x85, 0xeb, 0x6f, 0xdc, 0x67,
+ 0x96, 0x90, 0x6b, 0x68, 0x0a, 0x79, 0x0f, 0x79, 0x77, 0x96, 0x71, 0xf2,
+ 0x23, 0xc6, 0x4b, 0x9c, 0x1b, 0xe7, 0xe4, 0x62, 0x9e, 0x5f, 0x6b, 0x05,
+ 0x7f, 0x71, 0x87, 0x41, 0xfc, 0x36, 0xfb, 0x2e, 0xe7, 0xdb, 0x2f, 0x2b,
+ 0x74, 0x44, 0x82, 0x8f, 0xe6, 0xcb, 0xc8, 0xc3, 0xe7, 0xe0, 0xe3, 0x0b,
+ 0x2d, 0x16, 0xf5, 0x56, 0xe5, 0xf3, 0xc9, 0xd8, 0x18, 0x1f, 0x29, 0xa3,
+ 0xdf, 0x3e, 0xf8, 0xbc, 0x52, 0xce, 0x57, 0xf1, 0xe3, 0x57, 0xe0, 0xc7,
+ 0x61, 0xd9, 0xcf, 0x77, 0x16, 0x1d, 0x36, 0xbc, 0x3e, 0xe6, 0x11, 0xdb,
+ 0x9b, 0xda, 0xe8, 0x18, 0x5f, 0x1a, 0xf3, 0xff, 0xfd, 0x90, 0xff, 0x34,
+ 0xef, 0xc9, 0x8c, 0x0a, 0x0e, 0xe2, 0xef, 0x3d, 0x7d, 0xd4, 0xf7, 0x17,
+ 0x6a, 0xf1, 0x7d, 0xb6, 0xe0, 0x9e, 0x83, 0x67, 0x76, 0x38, 0xb4, 0x36,
+ 0x75, 0x6c, 0xec, 0x87, 0x18, 0x7b, 0x15, 0x79, 0x84, 0x7c, 0x05, 0x77,
+ 0xa6, 0x90, 0xf0, 0x9e, 0x5d, 0xa9, 0xe2, 0x03, 0x4e, 0xd0, 0xe5, 0xb4,
+ 0xe4, 0x82, 0x5c, 0x70, 0x81, 0xeb, 0xb4, 0xd5, 0x4d, 0x70, 0x21, 0x05,
+ 0x17, 0xe0, 0xd7, 0xd1, 0xbc, 0x59, 0xe0, 0xcc, 0x39, 0x07, 0xdf, 0x19,
+ 0xf3, 0x82, 0x79, 0xc0, 0x9c, 0x78, 0xc2, 0x85, 0x2b, 0x3d, 0xc3, 0xd8,
+ 0xfd, 0x2f, 0x3c, 0x78, 0x57, 0xf0, 0x80, 0xf9, 0x58, 0xe4, 0x85, 0x2e,
+ 0x70, 0x48, 0xca, 0xbc, 0x50, 0xe8, 0x9c, 0xeb, 0x1b, 0xd6, 0x78, 0xa1,
+ 0x8d, 0x2d, 0x68, 0xa3, 0xad, 0x70, 0xbd, 0xc3, 0xba, 0x60, 0x3f, 0xd6,
+ 0xc6, 0x49, 0x7e, 0x85, 0x46, 0xd2, 0xbe, 0x6d, 0x55, 0xf9, 0x21, 0x85,
+ 0x2e, 0xba, 0xa5, 0x46, 0xd2, 0x52, 0x23, 0xb0, 0x89, 0x95, 0x16, 0xe7,
+ 0x7a, 0xdb, 0x0a, 0x91, 0x17, 0xba, 0x62, 0xcc, 0x98, 0x8a, 0x3b, 0x09,
+ 0xeb, 0x96, 0xf3, 0xe9, 0x50, 0x1e, 0x2d, 0xef, 0xa5, 0x1d, 0x71, 0x2f,
+ 0xfd, 0x8a, 0x3e, 0x9a, 0x47, 0x67, 0x90, 0x43, 0xf8, 0x5e, 0x3a, 0xa7,
+ 0xf3, 0xbd, 0x14, 0xba, 0xd3, 0x87, 0xef, 0xa5, 0xc9, 0xc8, 0xbd, 0xb4,
+ 0xf2, 0xe5, 0xf6, 0x93, 0xf2, 0x69, 0x15, 0x13, 0xce, 0xa9, 0x02, 0xf3,
+ 0x13, 0x6a, 0xbf, 0xca, 0x86, 0xf3, 0x0d, 0x6b, 0xb9, 0xcc, 0x51, 0xa8,
+ 0xb5, 0xee, 0x67, 0x15, 0xe7, 0xdf, 0xc0, 0x3c, 0xf8, 0xee, 0x9f, 0xc4,
+ 0x79, 0xa3, 0xe4, 0xfc, 0x54, 0xe1, 0xd3, 0x1f, 0xe6, 0xfd, 0x1b, 0xfa,
+ 0x28, 0xef, 0xab, 0x71, 0x2a, 0xde, 0x17, 0x63, 0x3e, 0x54, 0x9a, 0x38,
+ 0xdb, 0x96, 0x91, 0x6b, 0x66, 0xf8, 0xbe, 0x85, 0x5c, 0xe0, 0xd5, 0x71,
+ 0xef, 0x98, 0xe1, 0xb1, 0xd3, 0x0c, 0xe7, 0x4d, 0x03, 0xbc, 0x17, 0x9c,
+ 0x3d, 0x12, 0xf7, 0x01, 0xac, 0x7b, 0x86, 0xab, 0xab, 0x51, 0x2e, 0xbe,
+ 0x88, 0x0b, 0x45, 0xb5, 0x97, 0xaa, 0xcd, 0x19, 0x6a, 0x5b, 0x2e, 0xb1,
+ 0x2e, 0x62, 0xfd, 0xa0, 0xb8, 0x8f, 0xd3, 0x2e, 0x6a, 0xb1, 0x43, 0xd4,
+ 0x39, 0x77, 0x70, 0x9f, 0x4b, 0x06, 0x8f, 0xf2, 0x07, 0x0d, 0x95, 0xba,
+ 0xc7, 0x3e, 0x5d, 0xac, 0xd7, 0x36, 0x6f, 0xe3, 0xed, 0xdd, 0x41, 0x15,
+ 0x53, 0xee, 0xe7, 0xb6, 0x7f, 0xe0, 0xbc, 0x45, 0x1d, 0x37, 0x32, 0x67,
+ 0xf5, 0xce, 0x7f, 0xff, 0x06, 0x63, 0xe1, 0x4b, 0x7b, 0x30, 0x12, 0x00,
+ 0x00, 0x00 };
static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
@@ -2554,939 +1543,422 @@ static const u32 bnx2_TXP_b06FwBssAddr = 0x080057a0;
static const int bnx2_TXP_b06FwBssLen = 0x1c4;
static const u32 bnx2_TXP_b06FwSbssAddr = 0x08005760;
static const int bnx2_TXP_b06FwSbssLen = 0x38;
-static u32 bnx2_TXP_b06FwText[(0x5748/4) + 1] = {
- 0x0a000d2c, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x322e352e,
- 0x38000000, 0x02050800, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800,
- 0x24425760, 0x3c030800, 0x24635964, 0xac400000, 0x0043202b, 0x1480fffd,
- 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261034b0,
- 0x3c1c0800, 0x279c5760, 0x0e000f5b, 0x00000000, 0x0000000d, 0x8f840014,
- 0x27bdffe8, 0xafb10014, 0xafb00010, 0x8f460104, 0x8f830008, 0x8c8500ac,
- 0xaf430080, 0x948200a8, 0xa7420e10, 0x948300aa, 0xa7430e12, 0x8c8200ac,
- 0xaf420e18, 0x97430e10, 0xa7430e14, 0x97420e12, 0x00008021, 0xa7420e16,
- 0x8f430e18, 0x00006021, 0x00c53023, 0xaf430e1c, 0x10c001a2, 0x2d820001,
- 0x3c0e1000, 0x2419fff8, 0x24110010, 0x240f0f00, 0x3c188100, 0x93620008,
- 0x10400009, 0x00000000, 0x97620010, 0x00c2102b, 0x14400005, 0x00000000,
- 0x97620010, 0x3042ffff, 0x0a000d6d, 0xaf420e00, 0xaf460e00, 0x8f420000,
- 0x30420008, 0x1040fffd, 0x00000000, 0x97420e08, 0x8f450e04, 0x3044ffff,
- 0x30820001, 0x14400005, 0x00000000, 0x14a00005, 0x3083a040, 0x0a000f34,
- 0x00000000, 0x0000000d, 0x3083a040, 0x24020040, 0x1462004f, 0x3082a000,
- 0x308a0036, 0x8f88000c, 0x30890008, 0x24020800, 0xaf420178, 0x01001821,
- 0x9742008a, 0x00431023, 0x2442ffff, 0x30421fff, 0x2c420008, 0x1440fffa,
- 0x00a06021, 0x8f820018, 0x00cc3023, 0x24070001, 0x8f830008, 0x304b00ff,
- 0x24420001, 0xaf820018, 0x25024000, 0x106f0005, 0x03422021, 0x93820012,
- 0x30420007, 0x00021240, 0x34470001, 0x000b1400, 0x3c030100, 0x00431025,
- 0xac820000, 0x8f830018, 0x00ea3825, 0x1120000f, 0xac830004, 0x97430e0a,
- 0x8f84000c, 0x00ee3825, 0x2402000e, 0x00781825, 0xaf430160, 0x25830006,
- 0x24840008, 0x30841fff, 0xa742015a, 0xa7430158, 0xaf84000c, 0x0a000db7,
- 0x00000000, 0x8f83000c, 0x25820002, 0xa7420158, 0x24630008, 0x30631fff,
- 0xaf83000c, 0x54c0000f, 0x8f420e14, 0x8f820008, 0x504f0002, 0x24100001,
- 0x34e70040, 0x97420e10, 0x97430e12, 0x8f850014, 0x00021400, 0x00621825,
- 0xaca300a8, 0x8f840014, 0x8f420e18, 0xac8200ac, 0x8f420e14, 0x8f430e1c,
- 0xaf420144, 0xaf430148, 0xa34b0152, 0xaf470154, 0x0a000efb, 0xaf4e0178,
- 0x10400165, 0x00000000, 0x93620008, 0x50400008, 0xafa60008, 0x97620010,
- 0x00a2102b, 0x10400003, 0x30820040, 0x1040015c, 0x00000000, 0xafa60008,
- 0xa7840010, 0xaf850004, 0x93620008, 0x1440005f, 0x27ac0008, 0xaf60000c,
- 0x97820010, 0x30424000, 0x10400002, 0x2403000e, 0x24030016, 0xa363000a,
- 0x24034007, 0xaf630014, 0x93820012, 0x8f630014, 0x30420007, 0x00021240,
- 0x00621825, 0xaf630014, 0x97820010, 0x8f630014, 0x30420010, 0x00621825,
- 0xaf630014, 0x97820010, 0x30420008, 0x5040000e, 0x00002821, 0x8f620014,
- 0x004e1025, 0xaf620014, 0x97430e0a, 0x2402000e, 0x00781825, 0xaf630004,
- 0xa3620002, 0x9363000a, 0x3405fffc, 0x24630004, 0x0a000e06, 0xa363000a,
- 0xaf600004, 0xa3600002, 0x97820010, 0x9363000a, 0x30421f00, 0x00021182,
- 0x24420028, 0x00621821, 0xa3630009, 0x97420e0c, 0xa7620010, 0x93630009,
- 0x24020008, 0x24630002, 0x30630007, 0x00431023, 0x30420007, 0xa362000b,
- 0x93640009, 0x97620010, 0x8f890004, 0x97830010, 0x00441021, 0x00a21021,
- 0x30630040, 0x10600007, 0x3045ffff, 0x00a9102b, 0x14400005, 0x0125102b,
- 0x3c068000, 0x0a000e3a, 0x00005821, 0x0125102b, 0x544000c7, 0x00006021,
- 0x97420e14, 0xa7420e10, 0x97430e16, 0xa7430e12, 0x8f420e1c, 0xaf420e18,
- 0xaf450e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000, 0x97420e08,
- 0x00a04821, 0xa7820010, 0x8f430e04, 0x00003021, 0x240b0001, 0xaf830004,
- 0x97620010, 0x0a000e4c, 0x304dffff, 0x8f890004, 0x97820010, 0x30420040,
- 0x10400004, 0x01206821, 0x3c068000, 0x0a000e4c, 0x00005821, 0x97630010,
- 0x8f820004, 0x10430003, 0x00003021, 0x0a000eee, 0x00006021, 0x240b0001,
- 0x8d820000, 0x00491023, 0x1440000d, 0xad820000, 0x8f620014, 0x34420040,
- 0xaf620014, 0x97430e10, 0x97420e12, 0x8f840014, 0x00031c00, 0x00431025,
- 0xac8200a8, 0x8f830014, 0x8f420e18, 0xac6200ac, 0x93620008, 0x1440003e,
- 0x00000000, 0x25260002, 0x8f84000c, 0x9743008a, 0x3063ffff, 0xafa30000,
- 0x8fa20000, 0x00441023, 0x2442ffff, 0x30421fff, 0x2c420010, 0x1440fff7,
- 0x00000000, 0x8f82000c, 0x8f830018, 0x00021082, 0x00021080, 0x24424000,
- 0x03422821, 0x00605021, 0x24630001, 0x314200ff, 0x00021400, 0xaf830018,
- 0x3c033200, 0x00431025, 0xaca20000, 0x93630009, 0x9362000a, 0x00031c00,
- 0x00431025, 0xaca20004, 0x8f830018, 0xaca30008, 0x97820010, 0x30420008,
- 0x10400002, 0x00c04021, 0x25280006, 0x97430e14, 0x93640002, 0x8f450e1c,
- 0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0xa7420146,
- 0xaf450148, 0xa34a0152, 0x8f82000c, 0x308400ff, 0xa744015a, 0xaf460160,
- 0xa7480158, 0xaf470154, 0xaf4e0178, 0x00511021, 0x30421fff, 0xaf82000c,
- 0x0a000ed9, 0x8d820000, 0x93620009, 0x9363000b, 0x8f85000c, 0x2463000a,
- 0x00435021, 0x25440007, 0x00992024, 0x9743008a, 0x3063ffff, 0xafa30000,
- 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b, 0x1440fff7,
- 0x00000000, 0x8f82000c, 0x8f840018, 0x00021082, 0x00021080, 0x24424000,
- 0x03422821, 0x00804021, 0x24840001, 0xaf840018, 0x93630009, 0x310200ff,
- 0x00022400, 0x3c024100, 0x24630002, 0x00621825, 0x00832025, 0xaca40000,
- 0x8f62000c, 0x00461025, 0xaca20004, 0x97430e14, 0x93640002, 0x8f450e1c,
- 0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0x308400ff,
- 0xa7420146, 0xaf450148, 0xa3480152, 0x8f83000c, 0x25420007, 0x00591024,
- 0xa744015a, 0xaf460160, 0xa7490158, 0xaf470154, 0xaf4e0178, 0x00621821,
- 0x30631fff, 0xaf83000c, 0x8d820000, 0x14400005, 0x00000000, 0x8f620014,
- 0x2403ffbf, 0x00431024, 0xaf620014, 0x8f62000c, 0x004d1021, 0xaf62000c,
- 0x93630008, 0x14600008, 0x00000000, 0x11600006, 0x00000000, 0x8f630014,
- 0x3c02efff, 0x3442fffe, 0x00621824, 0xaf630014, 0xa36b0008, 0x01206021,
- 0x1580000c, 0x8fa60008, 0x97420e14, 0x97430e16, 0x8f850014, 0x00021400,
- 0x00621825, 0xaca300a8, 0x8f840014, 0x8f420e1c, 0xac8200ac, 0x0a000efd,
- 0x2d820001, 0x14c0fe65, 0x2d820001, 0x00501025, 0x10400058, 0x24020f00,
- 0x8f830008, 0x14620023, 0x3c048000, 0x11800009, 0x3c038000, 0x97420e08,
- 0x30420040, 0x14400005, 0x00000000, 0x0000000d, 0x00000000, 0x2400032c,
- 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x00000000, 0x97420e10,
- 0x3c030500, 0x00431025, 0xaf42014c, 0x97430e14, 0xa7430144, 0x97420e16,
- 0xa7420146, 0x8f430e1c, 0x24022000, 0xaf430148, 0x3c031000, 0xa3400152,
- 0xa740015a, 0xaf400160, 0xa7400158, 0xaf420154, 0xaf430178, 0x8f830008,
- 0x3c048000, 0x8f420178, 0x00441024, 0x1440fffd, 0x24020f00, 0x10620016,
- 0x00000000, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c,
- 0x3c031000, 0xaf420148, 0x0a000f51, 0x24020240, 0x97420e14, 0x97430e16,
- 0x8f840014, 0x00021400, 0x00621825, 0xac8300a8, 0x8f850014, 0x8f420e1c,
- 0x00006021, 0xaca200ac, 0x0a000efd, 0x2d820001, 0xaf40014c, 0x11800007,
- 0x00000000, 0x97420e10, 0xa7420144, 0x97430e12, 0xa7430146, 0x0a000f4e,
- 0x8f420e18, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c,
- 0xaf420148, 0x24020040, 0x3c031000, 0xa3400152, 0xa740015a, 0xaf400160,
- 0xa7400158, 0xaf420154, 0xaf430178, 0x8fb10014, 0x8fb00010, 0x03e00008,
- 0x27bd0018, 0x27bdffd0, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008,
- 0x03421821, 0xafbf002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c,
- 0xafb20018, 0xafb10014, 0xafb00010, 0xaf830014, 0xaf440e00, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd,
- 0x3c046004, 0xaf420e00, 0x8c835000, 0x24160800, 0x24150d00, 0x3c140800,
- 0x24130f00, 0x3c120800, 0x3c114000, 0x2402ff7f, 0x00621824, 0x3463380c,
- 0x24020009, 0xac835000, 0xaf420008, 0xaf800018, 0xaf80000c, 0x0e001559,
- 0x00000000, 0x0e000ff0, 0x00000000, 0x3c020800, 0x245057c0, 0x8f420000,
- 0x30420001, 0x1040fffd, 0x00000000, 0x8f440100, 0xaf840008, 0xaf440020,
- 0xaf560178, 0x93430108, 0xa3830012, 0x93820012, 0x30420001, 0x10400008,
- 0x00000000, 0x93820012, 0x30420006, 0x00021100, 0x0e000d43, 0x0050d821,
- 0x0a000fac, 0x00000000, 0x14950005, 0x00000000, 0x0e000d43, 0x269b5840,
- 0x0a000fac, 0x00000000, 0x14930005, 0x00000000, 0x0e000d43, 0x265b5860,
- 0x0a000fac, 0x00000000, 0x0e0010ea, 0x00000000, 0xaf510138, 0x0a000f89,
- 0x00000000, 0x27bdfff8, 0x3084ffff, 0x24820007, 0x3044fff8, 0x8f85000c,
- 0x9743008a, 0x3063ffff, 0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff,
- 0x30421fff, 0x0044102b, 0x1440fff7, 0x00000000, 0x8f82000c, 0x00021082,
- 0x00021080, 0x24424000, 0x03421021, 0x03e00008, 0x27bd0008, 0x3084ffff,
- 0x8f82000c, 0x24840007, 0x3084fff8, 0x00441021, 0x30421fff, 0xaf82000c,
- 0x03e00008, 0x00000000, 0x27bdffe8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd,
- 0x3c020008, 0x03421821, 0xafbf0010, 0xaf830014, 0xaf440e00, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd,
- 0x3c046004, 0xaf420e00, 0x8c825000, 0x2403ff7f, 0x00431024, 0x3442380c,
- 0x24030009, 0xac825000, 0xaf430008, 0xaf800018, 0xaf80000c, 0x0e001559,
- 0x00000000, 0x0e000ff0, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018,
- 0x27bdffe8, 0x3c02000a, 0x03421821, 0x3c040800, 0x24845880, 0x24050019,
- 0xafbf0010, 0xaf830024, 0x0e001565, 0x00003021, 0x3c050800, 0x3c020800,
- 0x24425330, 0xaca258e8, 0x24a558e8, 0x3c020800, 0x244254f8, 0x3c030800,
- 0x2463550c, 0x3c040800, 0xaca20004, 0x3c020800, 0x24425338, 0xaca30008,
- 0xac825900, 0x24845900, 0x3c020800, 0x244253c4, 0x3c070800, 0x24e75404,
- 0x3c060800, 0x24c65520, 0x3c050800, 0x24a55438, 0x3c030800, 0xac820004,
- 0x3c020800, 0x24425528, 0xac870008, 0xac86000c, 0xac850010, 0xac625920,
- 0x24635920, 0x8fbf0010, 0x3c020800, 0x24425540, 0xac620004, 0x3c020800,
- 0xac670008, 0xac66000c, 0xac650010, 0xac400048, 0x03e00008, 0x27bd0018,
- 0x974309da, 0x00804021, 0xad030000, 0x8f4209dc, 0xad020004, 0x8f4309e0,
- 0xad030008, 0x934409d9, 0x24020001, 0x30840003, 0x1082001f, 0x30a900ff,
- 0x28820002, 0x10400005, 0x24020002, 0x10800009, 0x3c0a0800, 0x0a001078,
- 0x93420934, 0x1082000b, 0x24020003, 0x10820026, 0x3c0a0800, 0x0a001078,
- 0x93420934, 0x974209e4, 0x00021400, 0x34420800, 0xad02000c, 0x0a001077,
- 0x25080010, 0x974209e4, 0x00021400, 0x34428100, 0xad02000c, 0x974309e8,
- 0x3c0a0800, 0x00031c00, 0x34630800, 0xad030010, 0x0a001077, 0x25080014,
- 0x974409e4, 0x3c050800, 0x24a25880, 0x9443001c, 0x94460014, 0x94470010,
- 0x00a05021, 0x24020800, 0xad000010, 0xad020014, 0x00042400, 0x00661821,
- 0x00671823, 0x2463fff2, 0x00832025, 0xad04000c, 0x0a001077, 0x25080018,
- 0x974209e4, 0x3c050800, 0x00021400, 0x34428100, 0xad02000c, 0x974409e8,
- 0x24a25880, 0x9443001c, 0x94460014, 0x94470010, 0x00a05021, 0x24020800,
- 0xad000014, 0xad020018, 0x00042400, 0x00661821, 0x00671823, 0x2463ffee,
- 0x00832025, 0xad040010, 0x2508001c, 0x93420934, 0x93450921, 0x3c074000,
- 0x25445880, 0x94830018, 0x94860014, 0x00021082, 0x00021600, 0x00052c00,
- 0x00a72825, 0x00451025, 0x00661821, 0x00431025, 0xad020000, 0x9783002c,
- 0x974209ea, 0x00621821, 0x00031c00, 0xad030004, 0x9782002c, 0x24420001,
- 0x30427fff, 0xa782002c, 0x93430920, 0x3c020006, 0x00031e00, 0x00621825,
- 0xad030008, 0x8f42092c, 0xad02000c, 0x8f430930, 0xad030010, 0x8f440938,
- 0x25080014, 0xad040000, 0x8f820020, 0x11200004, 0xad020004, 0x8f420940,
- 0x0a0010a1, 0x2442ffff, 0x8f420940, 0xad020008, 0x8f440948, 0x8f420940,
- 0x93430936, 0x00823023, 0x00663006, 0x3402ffff, 0x0046102b, 0x54400001,
- 0x3406ffff, 0x93420937, 0x25445880, 0x90830024, 0xad000010, 0x00021700,
- 0x34630010, 0x00031c00, 0x00431025, 0x00461025, 0xad02000c, 0x8c830008,
- 0x14600031, 0x25080014, 0x3c020800, 0x8c430048, 0x1060002d, 0x00000000,
- 0x9342010b, 0xad020000, 0x8f830000, 0x8c6200b0, 0xad020004, 0x8f830000,
- 0x8c6200b4, 0xad020008, 0x8f830000, 0x8c6200c0, 0xad02000c, 0x8f830000,
- 0x8c6200c4, 0xad020010, 0x8f830000, 0x8c6200c8, 0xad020014, 0x8f830000,
- 0x8c6200cc, 0xad020018, 0x8f830000, 0x8c6200e0, 0xad02001c, 0x8f830000,
- 0x8c6200e8, 0xad020020, 0x8f830000, 0x8c6200f0, 0x3c04600e, 0xad020024,
- 0x8c8200d0, 0xad020028, 0x8c8300d4, 0xad03002c, 0x8f820028, 0x3c046012,
- 0xad020030, 0x8c8200a8, 0xad020034, 0x8c8300ac, 0x3c026000, 0xad030038,
- 0x8c434448, 0xad03003c, 0x03e00008, 0x01001021, 0x27bdffa8, 0x3c020008,
- 0x03423021, 0xafbf0054, 0xafbe0050, 0xafb7004c, 0xafb60048, 0xafb50044,
- 0xafb40040, 0xafb3003c, 0xafb20038, 0xafb10034, 0xafb00030, 0xaf860000,
- 0x24020040, 0xaf420814, 0xaf400810, 0x8f420944, 0x8f430950, 0x8f440954,
- 0x8f45095c, 0xaf820034, 0xaf830020, 0xaf84001c, 0xaf850030, 0x90c20000,
- 0x24030020, 0x304400ff, 0x10830005, 0x24020030, 0x10820022, 0x3c030800,
- 0x0a001139, 0x8c62002c, 0x24020088, 0xaf420818, 0x3c020800, 0x244258e8,
- 0xafa20020, 0x93430109, 0x3c020800, 0x10600009, 0x24575900, 0x3c026000,
- 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000,
- 0x24000376, 0x9342010a, 0x30420080, 0x14400021, 0x24020800, 0x3c026000,
- 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000,
- 0x2400037d, 0x0a001141, 0x24020800, 0x93430109, 0x3063007f, 0x00031140,
- 0x000318c0, 0x00431021, 0x24430088, 0xaf430818, 0x0000000d, 0x3c020800,
- 0x24425940, 0x3c030800, 0x24775950, 0x0a001140, 0xafa20020, 0x24420001,
- 0xac62002c, 0x0000000d, 0x00000000, 0x24000395, 0x0a0014c1, 0x8fbf0054,
- 0x24020800, 0xaf420178, 0x8f450104, 0x8f420988, 0x00a21023, 0x58400005,
- 0x8f4309a0, 0x0000000d, 0x00000000, 0x240003b1, 0x8f4309a0, 0x3c100800,
- 0xae0358b0, 0x8f4209a4, 0x8f830020, 0x260458b0, 0x2491ffd0, 0xae220034,
- 0x00a21023, 0xae230028, 0xac82ffd0, 0x8fa30020, 0x8c620000, 0x0040f809,
- 0x0200b021, 0x00409021, 0x32440010, 0x32420002, 0x10400007, 0xafa40024,
- 0x8e220020, 0x32530040, 0x2403ffbf, 0x00431024, 0x0a001493, 0xae220020,
- 0x32420020, 0x10400002, 0x3c020800, 0x24575920, 0x32420001, 0x14400007,
- 0x00000000, 0x8f820008, 0xaf420080, 0x8ec358b0, 0xaf430e10, 0x8e220034,
- 0xaf420e18, 0x9343010b, 0x93420905, 0x30420008, 0x1040003c, 0x307400ff,
- 0x8f820000, 0x8c430074, 0x0460000a, 0x00000000, 0x3c026000, 0x24030100,
- 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x240003ed,
- 0x8f820000, 0x9044007b, 0x9343010a, 0x14830027, 0x32530040, 0x00003821,
- 0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd,
- 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100,
- 0xaf420148, 0x24020047, 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000,
- 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001, 0xad230030,
- 0x9342010a, 0x3c030047, 0xafa50014, 0x00021600, 0x00431025, 0x00471025,
- 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b,
- 0x3c070100, 0x3c050800, 0x24a25880, 0x0a001250, 0x8c430020, 0x32820002,
- 0x10400050, 0x00000000, 0x0e0015b9, 0x32530040, 0x3c039000, 0x34630001,
- 0x8f820008, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024,
- 0x1440fffd, 0x00000000, 0x8f830000, 0x90620005, 0x34420008, 0xa0620005,
- 0x8f840000, 0x8c820074, 0x3c038000, 0x00431025, 0xac820074, 0x90830000,
- 0x24020020, 0x10620004, 0x00000000, 0x0000000d, 0x00000000, 0x2400040b,
- 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x9084007b,
- 0x9342010a, 0x14820028, 0x3c030800, 0x00003821, 0x24052000, 0x3c090800,
- 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0,
- 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100, 0xaf420148, 0x24020046,
- 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154,
- 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030046,
- 0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b,
- 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070100, 0x3c030800,
- 0x24625880, 0x0a001250, 0x8c430020, 0x93420108, 0x30420010, 0x50400056,
- 0x9343093f, 0x8f860000, 0x90c2007f, 0x8cc30178, 0x304800ff, 0x15030004,
- 0x00000000, 0x0000000d, 0x00000000, 0x24000425, 0x90c2007e, 0x90c40080,
- 0x00081c00, 0x00021600, 0x00431025, 0x00042200, 0x90c3007a, 0x90c5000a,
- 0x00441025, 0x11050028, 0x00623825, 0xa0c8000a, 0x00004021, 0x24056000,
- 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0,
- 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0xaf420148, 0x24020052,
- 0xaf47014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7480158, 0xaf450154,
- 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030052,
- 0xafa50014, 0x00021600, 0x00431025, 0x00481025, 0xafa20010, 0x9343010b,
- 0xafa30018, 0x8f440100, 0x0e00159b, 0x8f450104, 0x0a00124a, 0x00000000,
- 0x3c026000, 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d,
- 0x00000000, 0x2400043e, 0x16800009, 0x3c050800, 0x3c040800, 0x24825880,
- 0x8c430020, 0x32530040, 0x2404ffbf, 0x00641824, 0x0a001493, 0xac430020,
- 0x8ca25880, 0x10400005, 0x3c030800, 0x8c620034, 0xaca05880, 0x24420001,
- 0xac620034, 0x9343093f, 0x24020012, 0x5462000e, 0x97420908, 0x32820038,
- 0x14400009, 0x3c030800, 0x8f830000, 0x8c62004c, 0xac62005c, 0x3c020800,
- 0x24445880, 0x8c820020, 0x0a001285, 0x32530040, 0xac605880, 0x97420908,
- 0x5440001c, 0x97420908, 0x3c039000, 0x34630001, 0x8f820008, 0x32530040,
- 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd,
- 0x3c028000, 0x8f840000, 0x8f850008, 0x8c830050, 0x34420001, 0x00a22825,
- 0xaf830020, 0xac830070, 0xac83005c, 0xaf450020, 0x3c050800, 0x24a45880,
- 0x8c820020, 0x2403ffbf, 0x00431024, 0x0a001493, 0xac820020, 0x000211c0,
- 0xaf420024, 0x97420908, 0x3c030080, 0x34630003, 0x000211c0, 0xaf42080c,
- 0xaf43081c, 0x974209ec, 0x8f4309a4, 0xa782002c, 0x3c020800, 0x24445880,
- 0xac83002c, 0x93420937, 0x93430934, 0x00021080, 0x00621821, 0xa4830018,
- 0x934209d8, 0x32850038, 0xafa50028, 0x00621821, 0xa483001a, 0x934209d8,
- 0x93430934, 0x3c1e0800, 0x00809821, 0x00431021, 0x24420010, 0xa4820016,
- 0x24020006, 0xae620020, 0x8fa20028, 0x10400003, 0x0000a821, 0x0a0012f0,
- 0x24120008, 0x8f420958, 0x8f830020, 0x8f840030, 0x00431023, 0x00832023,
- 0x04800003, 0xae620004, 0x04410003, 0x0082102b, 0x0a0012bc, 0xae600004,
- 0x54400001, 0xae640004, 0x8ee20000, 0x0040f809, 0x00000000, 0x00409021,
- 0x32420001, 0x5440001e, 0x8ee20004, 0x8e630008, 0x1060002b, 0x3c02c000,
- 0x00621025, 0xaf420e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000,
- 0x97420e08, 0xa7820010, 0x8f430e04, 0x8e620008, 0xaf830004, 0x8f840004,
- 0x0044102b, 0x1040000b, 0x24150001, 0x24020100, 0x3c016000, 0xac22081c,
- 0x3c020001, 0x3c016000, 0xac22081c, 0x0000000d, 0x00000000, 0x240004cd,
- 0x24150001, 0x8ee20004, 0x0040f809, 0x00000000, 0x02429025, 0x32420002,
- 0x5040001d, 0x8f470940, 0x12a00006, 0x8ec258b0, 0x8f830000, 0xac6200a8,
- 0x8f840000, 0x8e620034, 0xac8200ac, 0x32420004, 0x50400013, 0x8f470940,
- 0x3c020800, 0x3283007d, 0x10600110, 0x24575920, 0x32820001, 0x50400006,
- 0x36520002, 0x8f830034, 0x8f420940, 0x10620109, 0x00000000, 0x36520002,
- 0x24020008, 0xa6600010, 0xa6620012, 0xae600008, 0xa2600024, 0x8f470940,
- 0x3c030800, 0x24685880, 0x8d02002c, 0x8d050008, 0x95040010, 0x9506000a,
- 0x95030026, 0x00451021, 0x00862021, 0x00641821, 0xaf870034, 0xad02002c,
- 0x32820030, 0x10400008, 0xa5030014, 0x91020024, 0x32910040, 0x34420004,
- 0xa1020024, 0xaf400048, 0x0a001345, 0x3c040800, 0x93420923, 0x30420002,
- 0x10400029, 0x32910040, 0x8f830000, 0x8f840020, 0x8c620084, 0x00441023,
- 0x0442000a, 0x3c039000, 0x95020014, 0x8c630084, 0x00821021, 0x00621823,
- 0x1c600004, 0x3c039000, 0x91020024, 0x34420001, 0xa1020024, 0x34630001,
- 0x8f820008, 0x32910040, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020,
- 0x00441024, 0x1440fffd, 0x00000000, 0x8f840000, 0x9083003f, 0x2402000a,
- 0x10620005, 0x2402000c, 0x9083003f, 0x24020008, 0x14620002, 0x24020014,
- 0xa082003f, 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020,
- 0x3c040800, 0x24865880, 0x94c20010, 0x94c3001a, 0x8cc40008, 0x00432821,
- 0x14800006, 0xa4c5001c, 0x3c020800, 0x8c430048, 0x10600002, 0x24a20040,
- 0xa4c2001c, 0x27d05880, 0x9604001c, 0x96020012, 0x00822021, 0x24840002,
- 0x0e000faf, 0x3084ffff, 0x8f850018, 0x00a01821, 0xa2030025, 0x8ee60008,
- 0x00402021, 0x24a50001, 0xaf850018, 0x00c0f809, 0x00000000, 0x00402021,
- 0x0e001026, 0x02202821, 0x8ee3000c, 0x0060f809, 0x00402021, 0x9604001c,
- 0x96020012, 0x00822021, 0x24840002, 0x0e000fc5, 0x3084ffff, 0x8fc25880,
- 0x8e030008, 0x00431023, 0x14400012, 0xafc25880, 0x54600006, 0x8e020020,
- 0x3243004a, 0x24020002, 0x14620005, 0x00000000, 0x8e020020, 0x34420040,
- 0x0a001382, 0xae020020, 0x52a00006, 0x36520002, 0x8e020030, 0xaf420e10,
- 0x8e030034, 0xaf430e18, 0x36520002, 0x52a00008, 0x96670014, 0x8f830000,
- 0x8f420e10, 0xac6200a8, 0x8f840000, 0x8f420e18, 0xac8200ac, 0x96670014,
- 0x92680024, 0x24020040, 0xaf420814, 0x8f830020, 0x8f82001c, 0x00671821,
- 0x00621023, 0xaf830020, 0x18400008, 0x00000000, 0x8f820000, 0xaf83001c,
- 0xac430054, 0x54e00005, 0xaf400040, 0x0a0013a0, 0x8f42095c, 0x54e00001,
- 0xaf400044, 0x8f42095c, 0x31030008, 0xaf820030, 0x1060001a, 0x00000000,
- 0x8f840000, 0x90820120, 0x90830121, 0x304600ff, 0x00c31823, 0x30630007,
- 0x24020007, 0x1062000e, 0x00000000, 0x90820122, 0x304200fe, 0xa0820122,
- 0x8f850000, 0x00061880, 0x8f840020, 0x24a20100, 0x00431021, 0x24c30001,
- 0x30630007, 0xac440000, 0x0a0013bd, 0xa0a30120, 0x90820122, 0x34420001,
- 0xa0820122, 0x14e00003, 0x31020001, 0x10400031, 0x32510002, 0x8f820000,
- 0x8c43000c, 0x30630001, 0x1060002c, 0x32510002, 0x3c029000, 0x8f830008,
- 0x34420001, 0x3c048000, 0x00621825, 0xaf430020, 0x8f420020, 0x00441024,
- 0x1440fffd, 0x00000000, 0x8f870000, 0x8ce2000c, 0x30420001, 0x10400018,
- 0x00000000, 0x94e2006a, 0x00022880, 0x50a00001, 0x24050001, 0x94e30068,
- 0x90e40081, 0x3c020800, 0x8c460024, 0x00652821, 0x00852804, 0x00c5102b,
- 0x54400001, 0x00a03021, 0x3c020800, 0x8c440028, 0x00c4182b, 0x54600001,
- 0x00c02021, 0x8f430074, 0x2402fffe, 0x00822824, 0x00a31821, 0xace3000c,
- 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x8f820020,
- 0x3c050800, 0x24b05880, 0xae020028, 0x8ee30010, 0x0060f809, 0x00000000,
- 0x8f820028, 0x24420001, 0xaf820028, 0x12a00005, 0xaf40004c, 0x8f420e10,
- 0xae020030, 0x8f430e18, 0xae030034, 0x1220fea7, 0x24020006, 0x8f870024,
- 0x9786002c, 0x8f830000, 0x8f820034, 0x8f840020, 0x8f85001c, 0x32530040,
- 0xa4e6002c, 0xac620044, 0x32420008, 0xac640050, 0xac650054, 0x1040007a,
- 0x32820020, 0x10400027, 0x32910010, 0x00003821, 0x24052000, 0x3c090800,
- 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0,
- 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030400, 0xaf420148, 0x24020041,
- 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154,
- 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030041,
- 0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b,
- 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070400, 0x12200028,
- 0x00003821, 0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024,
- 0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034,
- 0x3c030300, 0xaf420148, 0x2402004e, 0xaf43014c, 0xa3420152, 0x8d230030,
- 0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001,
- 0xad230030, 0x9342010a, 0x3c03004e, 0xafa50014, 0x00021600, 0x00431025,
- 0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104,
- 0x0e00159b, 0x3c070300, 0x0a00148b, 0x8fa20024, 0x32820008, 0x10400026,
- 0x24052000, 0x00003821, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024,
- 0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034,
- 0x3c030200, 0xaf420148, 0x2402004b, 0xaf43014c, 0xa3420152, 0x8d230030,
- 0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001,
- 0xad230030, 0x9342010a, 0x3c03004b, 0xafa50014, 0x00021600, 0x00431025,
- 0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104,
- 0x0e00159b, 0x3c070200, 0x8fa20024, 0x14400004, 0x8fa30020, 0x32420010,
- 0x10400004, 0x00000000, 0x8c620004, 0x0040f809, 0x00000000, 0x12600006,
- 0x8fa40020, 0x8c820008, 0x0040f809, 0x00000000, 0x0a0014c1, 0x8fbf0054,
- 0x3c030800, 0x8c6258a0, 0x30420040, 0x14400023, 0x8fbf0054, 0x00002821,
- 0x24040040, 0x8f870020, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd,
- 0x8ec258b0, 0x26c358b0, 0x2463ffd0, 0xaf420144, 0x8c620034, 0xaf420148,
- 0x24020049, 0xaf47014c, 0xa3420152, 0x3c021000, 0xa7450158, 0xaf440154,
- 0xaf420178, 0x8c660034, 0x9342010a, 0x3c030049, 0xafa40014, 0x00021600,
- 0x00431025, 0x00451025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100,
- 0x0e00159b, 0x8f450104, 0x8fbf0054, 0x8fbe0050, 0x8fb7004c, 0x8fb60048,
- 0x8fb50044, 0x8fb40040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
- 0x03e00008, 0x27bd0058, 0x03e00008, 0x00001021, 0x3c020800, 0x24435880,
- 0x8c650004, 0x8c445880, 0x0085182b, 0x10600002, 0x00403021, 0x00802821,
- 0x9744093c, 0x00a4102b, 0x54400001, 0x00a02021, 0x93420923, 0x0004182b,
- 0x00021042, 0x30420001, 0x00431024, 0x1040000d, 0x24c25880, 0x8f850000,
- 0x8f830020, 0x8ca20084, 0x00431023, 0x04420007, 0x24c25880, 0x8ca20084,
- 0x00641821, 0x00431023, 0x28420001, 0x00822023, 0x24c25880, 0xac440008,
- 0xa4400026, 0x03e00008, 0x00001021, 0x8f850004, 0x97840010, 0x3c030800,
- 0x24635880, 0x24020008, 0xa4620012, 0x8f820004, 0xa4600010, 0x000420c2,
- 0x30840008, 0x2c420001, 0x00021023, 0x30420006, 0xac650008, 0x03e00008,
- 0xa0640024, 0x3c020800, 0x24425880, 0x90450025, 0x9443001c, 0x3c021100,
- 0xac800004, 0x00052c00, 0x24630002, 0x00621825, 0x00a32825, 0x24820008,
- 0x03e00008, 0xac850000, 0x27bdffd8, 0x3c020800, 0x24425880, 0xafbf0020,
- 0x90480025, 0x8c440008, 0x8c460020, 0x8f870020, 0x3c030800, 0x3c058000,
- 0x8f420178, 0x00451024, 0x1440fffd, 0x8c6258b0, 0x246358b0, 0x2469ffd0,
- 0xaf420144, 0x8d220034, 0x30c32000, 0xaf420148, 0x3c021000, 0xaf47014c,
- 0xa3480152, 0xa7440158, 0xaf460154, 0xaf420178, 0x10600004, 0x3c030800,
- 0x8c620030, 0x24420001, 0xac620030, 0x9342010a, 0x00081c00, 0x3084ffff,
- 0xafa60014, 0x00021600, 0x00431025, 0x00441025, 0xafa20010, 0x9343010b,
- 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x8d260034, 0x8fbf0020,
- 0x03e00008, 0x27bd0028, 0x0000000d, 0x00000000, 0x2400019d, 0x03e00008,
- 0x00000000, 0x0000000d, 0x00000000, 0x240001a9, 0x03e00008, 0x00000000,
- 0x03e00008, 0x00000000, 0x3c020800, 0x24425880, 0xac400008, 0xa4400026,
- 0x03e00008, 0x24020001, 0x3c020800, 0x24425880, 0x24030008, 0xac400008,
- 0xa4400010, 0xa4430012, 0xa0400024, 0x03e00008, 0x24020004, 0x03e00008,
- 0x00001021, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004,
- 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a00156c,
- 0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004, 0x00a01021,
- 0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c0a0800, 0x8d490068,
- 0x3c050800, 0x24a52098, 0x00093140, 0x00c51021, 0xac440000, 0x8f440e04,
- 0x00a61021, 0xac440004, 0x97430e08, 0x97420e0c, 0x00a62021, 0x00031c00,
- 0x00431025, 0xac820008, 0x8f430e10, 0x00801021, 0xac43000c, 0x8f440e14,
- 0xac440010, 0x8f430e18, 0x3c0800ff, 0xac430014, 0x8f470e1c, 0x3508ffff,
- 0x25290001, 0xac470018, 0x3c070800, 0x8ce3006c, 0x9344010a, 0x3c026000,
- 0x24630001, 0xace3006c, 0x8c434448, 0x3129007f, 0x00a62821, 0xad490068,
- 0x00042600, 0x00681824, 0x00832025, 0x03e00008, 0xaca4001c, 0x8fac0010,
- 0x8fad0014, 0x8fae0018, 0x3c0b0800, 0x8d6a0060, 0x3c080800, 0x25080080,
- 0x000a4940, 0x01281021, 0x01091821, 0xac440000, 0x00601021, 0xac650004,
- 0xac460008, 0xac67000c, 0xac4c0010, 0xac6d0014, 0x3c036000, 0xac4e0018,
- 0x8c654448, 0x3c040800, 0x8c820064, 0x254a0001, 0x314a00ff, 0x01094021,
- 0xad6a0060, 0x24420001, 0xac820064, 0x03e00008, 0xad05001c, 0x3c030800,
- 0x3c090800, 0x8d250070, 0x246330b0, 0x8f460100, 0x00053900, 0x00e31021,
- 0xac460000, 0x8f440104, 0x00671021, 0xac440004, 0x8f460108, 0x8f840014,
- 0x24a50001, 0xac460008, 0x8c880074, 0x3c060800, 0x8cc20074, 0x30a5003f,
- 0x00671821, 0xad250070, 0x24420001, 0xacc20074, 0x03e00008, 0xac68000c,
- 0x00000000 };
+static u8 bnx2_TXP_b06FwText[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c,
+ 0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2,
+ 0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05,
+ 0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71,
+ 0x94, 0x86, 0x6e, 0x0d, 0x8c, 0xa0, 0xec, 0xd8, 0xeb, 0x5a, 0x2c, 0x1f,
+ 0x8c, 0xd5, 0x68, 0xd1, 0x99, 0xa1, 0x68, 0xc7, 0xc9, 0x68, 0x51, 0xa9,
+ 0xe5, 0xa8, 0x43, 0x57, 0x80, 0x95, 0x64, 0xcb, 0x29, 0x4e, 0x3a, 0x65,
+ 0xcb, 0x16, 0x0c, 0x58, 0x16, 0xcd, 0x2f, 0x5d, 0x3f, 0x74, 0x80, 0x3f,
+ 0xec, 0x43, 0x3a, 0xec, 0x83, 0x91, 0x14, 0xad, 0x11, 0x6c, 0x59, 0xb0,
+ 0x2f, 0x33, 0xd6, 0x26, 0xb7, 0xdf, 0x73, 0x77, 0x94, 0x95, 0xc4, 0x4e,
+ 0xab, 0x7d, 0xbe, 0x07, 0x20, 0xee, 0x7f, 0xff, 0xd7, 0xe7, 0xfd, 0xe5,
+ 0x7f, 0x90, 0x06, 0xb7, 0x53, 0x17, 0x85, 0xb0, 0x1d, 0x3f, 0xed, 0x99,
+ 0x93, 0x27, 0x3e, 0xf7, 0xf9, 0xcf, 0x0d, 0xa1, 0x39, 0x4c, 0x4a, 0x4c,
+ 0xe4, 0xc1, 0x5b, 0x12, 0x51, 0xf9, 0x1d, 0x8a, 0x20, 0x82, 0x08, 0x22,
+ 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20,
+ 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08,
+ 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88,
+ 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82,
+ 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22,
+ 0xf8, 0x9d, 0x20, 0x11, 0xa9, 0xfc, 0xdc, 0x1e, 0xfe, 0x48, 0x11, 0xcd,
+ 0xf2, 0x53, 0xb6, 0x41, 0x8a, 0x64, 0x1e, 0x39, 0x34, 0x65, 0x10, 0x59,
+ 0xce, 0x80, 0x56, 0xa0, 0xf7, 0xbd, 0x6a, 0x52, 0x26, 0xee, 0xff, 0xb4,
+ 0xf9, 0xdb, 0x53, 0xaf, 0x7f, 0x41, 0x7f, 0xaf, 0x25, 0x91, 0xa2, 0x9a,
+ 0x6b, 0x79, 0xb5, 0x9f, 0x94, 0x34, 0xd6, 0xfc, 0xd5, 0xee, 0xaf, 0xef,
+ 0xa0, 0x44, 0x7b, 0xaf, 0x24, 0xd5, 0x9b, 0xb7, 0xbc, 0xd7, 0x77, 0x27,
+ 0xe9, 0x15, 0x57, 0xa5, 0x35, 0x57, 0x16, 0x46, 0x9b, 0x0a, 0x4d, 0x37,
+ 0x1d, 0x3a, 0xdd, 0xa8, 0x52, 0xc1, 0xbd, 0x4c, 0xb5, 0x39, 0x35, 0x61,
+ 0x2f, 0xff, 0x84, 0xa6, 0xe7, 0x7a, 0x13, 0x85, 0x65, 0x87, 0x6a, 0x8d,
+ 0x54, 0xc2, 0x76, 0xd5, 0x44, 0x61, 0x3e, 0x89, 0xf7, 0xde, 0x84, 0x3d,
+ 0xaf, 0x57, 0x89, 0x76, 0x62, 0x4e, 0x2a, 0x51, 0x68, 0xea, 0x65, 0xa2,
+ 0xbe, 0xdc, 0x75, 0x4a, 0x27, 0x0a, 0xee, 0x82, 0xb0, 0xae, 0x0a, 0x54,
+ 0xfb, 0x2c, 0xa9, 0x09, 0xf3, 0xb6, 0xf7, 0x29, 0x43, 0xa5, 0x1e, 0x83,
+ 0x76, 0xec, 0x30, 0xe8, 0xd9, 0x94, 0xa9, 0x50, 0xe5, 0x7c, 0x9c, 0x2c,
+ 0x9f, 0x26, 0x95, 0x2a, 0xf3, 0x03, 0xea, 0x15, 0x8a, 0x91, 0x95, 0x6c,
+ 0xbf, 0x7b, 0x9e, 0x9d, 0xfb, 0x16, 0xff, 0x9d, 0x16, 0xce, 0xa2, 0xc4,
+ 0xa8, 0x4b, 0x64, 0x03, 0x2f, 0x3b, 0xf7, 0xbe, 0x17, 0xac, 0x51, 0x70,
+ 0xae, 0x9c, 0x18, 0x69, 0x7a, 0x5e, 0x31, 0x87, 0x33, 0x72, 0xed, 0xb5,
+ 0x31, 0x6a, 0x25, 0xad, 0xd6, 0x74, 0x2e, 0xbf, 0x23, 0xf8, 0x1b, 0x2f,
+ 0xa6, 0x91, 0xdf, 0x2d, 0x12, 0x8d, 0xaf, 0x50, 0x25, 0x49, 0xad, 0x5a,
+ 0xee, 0x61, 0x7a, 0x21, 0xd7, 0x4d, 0x67, 0xb1, 0xdf, 0xf3, 0x39, 0xf0,
+ 0xd1, 0x38, 0x29, 0xd8, 0xae, 0x9e, 0x22, 0xe1, 0x05, 0xb2, 0xe7, 0xfb,
+ 0xd4, 0x02, 0xe1, 0x6c, 0xc3, 0xfb, 0x8c, 0x9d, 0xc3, 0x79, 0x83, 0xff,
+ 0xeb, 0x59, 0x49, 0xbd, 0xdc, 0xa2, 0x14, 0xd5, 0x9a, 0x7d, 0xb9, 0x9f,
+ 0x93, 0x40, 0x9d, 0x06, 0xf3, 0xc7, 0xa3, 0xc7, 0x70, 0xae, 0x6d, 0xa0,
+ 0xdf, 0x25, 0x4b, 0xcc, 0xc4, 0xe8, 0x4f, 0x55, 0x5d, 0xb3, 0xa5, 0x5e,
+ 0xaa, 0x9d, 0xef, 0x04, 0x9e, 0x56, 0xaf, 0x88, 0xb9, 0x63, 0x79, 0x4a,
+ 0x6e, 0x23, 0x12, 0x24, 0x33, 0x83, 0x7d, 0x89, 0x6a, 0x4e, 0x0a, 0x6b,
+ 0x33, 0xc3, 0xef, 0xd0, 0x0e, 0xd2, 0x7a, 0x64, 0x9a, 0x76, 0xba, 0xc0,
+ 0xc7, 0x6e, 0xc8, 0x20, 0x33, 0xfc, 0x2e, 0x84, 0x22, 0x1a, 0x99, 0xd4,
+ 0x49, 0x2a, 0x0b, 0x05, 0xb7, 0x83, 0xa6, 0x33, 0x0a, 0xd5, 0x81, 0x47,
+ 0x3d, 0xf7, 0x35, 0xc1, 0x5e, 0x2e, 0x09, 0x85, 0x65, 0xcc, 0x73, 0x5f,
+ 0x0b, 0xff, 0x76, 0xad, 0x1b, 0xfb, 0x88, 0x54, 0xcb, 0x94, 0x30, 0xa6,
+ 0xd0, 0x14, 0xe6, 0x4d, 0x81, 0xa6, 0x69, 0x77, 0x07, 0xad, 0x4f, 0x26,
+ 0x13, 0xcc, 0xab, 0x1a, 0xc6, 0xbf, 0x32, 0x21, 0x90, 0x6a, 0x58, 0xf4,
+ 0xeb, 0x3c, 0x64, 0x38, 0xdf, 0xcb, 0x32, 0xa3, 0xd3, 0x4d, 0x4a, 0x8a,
+ 0x94, 0x49, 0x55, 0xe8, 0x32, 0x2d, 0x3a, 0x2c, 0x7f, 0xc8, 0x13, 0xf2,
+ 0xae, 0x39, 0xbc, 0x0e, 0x72, 0x6b, 0x16, 0xc1, 0x8f, 0x71, 0xe0, 0x70,
+ 0x50, 0x78, 0x6c, 0x71, 0x52, 0x18, 0x73, 0x7f, 0x93, 0xa0, 0xae, 0x93,
+ 0xc2, 0x01, 0xf7, 0xa8, 0x10, 0xf2, 0x1e, 0xb2, 0x53, 0xc8, 0x9a, 0x50,
+ 0xe8, 0x92, 0x1b, 0xc8, 0x6e, 0x01, 0xfa, 0x69, 0xa9, 0x16, 0xe4, 0x70,
+ 0x78, 0x63, 0x0e, 0x8f, 0xd5, 0x97, 0x65, 0x3a, 0xed, 0xf2, 0xfc, 0x3f,
+ 0x82, 0x7c, 0x14, 0x72, 0x76, 0x77, 0x53, 0x19, 0xfd, 0xb5, 0x79, 0xb2,
+ 0xec, 0x9c, 0x88, 0x35, 0x09, 0x92, 0x8c, 0x9d, 0xf8, 0x75, 0xd1, 0xd4,
+ 0x62, 0xa7, 0x25, 0x19, 0x49, 0x9a, 0x72, 0x99, 0x87, 0x78, 0x36, 0xdb,
+ 0x7c, 0x64, 0x5c, 0xb9, 0x9f, 0xd7, 0x71, 0xbf, 0x8a, 0xfe, 0xcd, 0x7d,
+ 0xac, 0x17, 0x09, 0xe0, 0xa3, 0x67, 0x59, 0x9f, 0x2b, 0xcd, 0x8c, 0x7a,
+ 0x80, 0x9f, 0x2e, 0xf3, 0xb6, 0xcd, 0x53, 0x19, 0x73, 0x45, 0xaa, 0x2c,
+ 0xe2, 0x9c, 0xf3, 0xbf, 0xf5, 0x62, 0x79, 0xbc, 0x1b, 0x1d, 0xa0, 0x8b,
+ 0xcf, 0x95, 0x81, 0x93, 0x48, 0xe5, 0x45, 0xde, 0x8b, 0xc7, 0x09, 0xb2,
+ 0xaf, 0xf5, 0x88, 0x94, 0x85, 0x7c, 0x75, 0x9c, 0x13, 0xc7, 0x9c, 0x6e,
+ 0xf0, 0x0f, 0xb4, 0x2e, 0xa3, 0x0d, 0xda, 0x45, 0x43, 0xc4, 0xfa, 0x4e,
+ 0x9a, 0xca, 0xb1, 0xbe, 0x30, 0x9e, 0xdb, 0xb0, 0x77, 0x9c, 0x8e, 0x9c,
+ 0x67, 0x7e, 0xc8, 0xf4, 0x3c, 0x70, 0x9c, 0x9e, 0xd7, 0xd5, 0x22, 0xe9,
+ 0xe0, 0x8d, 0x85, 0x79, 0x9d, 0x54, 0x56, 0x3d, 0x6f, 0x24, 0x37, 0xa0,
+ 0xbe, 0xec, 0xeb, 0xf9, 0x80, 0x9a, 0x11, 0xa8, 0xda, 0x61, 0xfe, 0x21,
+ 0x70, 0xd0, 0x4b, 0x44, 0xfc, 0xfe, 0xcf, 0x64, 0x4d, 0xb2, 0xfd, 0x24,
+ 0xf9, 0x2c, 0xd8, 0xd3, 0x4e, 0xe0, 0xcf, 0x36, 0x97, 0x86, 0x5c, 0x52,
+ 0xbe, 0x1d, 0x8c, 0xdc, 0xd5, 0x0e, 0xf4, 0xf1, 0x16, 0x6c, 0xa6, 0xb6,
+ 0x2c, 0xb3, 0xfd, 0xe5, 0xa0, 0x6e, 0xb4, 0xcd, 0x80, 0x6e, 0xf9, 0xb2,
+ 0xd9, 0x8f, 0xfd, 0x3d, 0xef, 0xcb, 0xb9, 0x00, 0xa7, 0xda, 0xbc, 0x85,
+ 0xb5, 0x32, 0xf8, 0xae, 0x1f, 0xd7, 0xfc, 0xf3, 0xf7, 0x87, 0xe7, 0xab,
+ 0x34, 0x05, 0xbc, 0x6b, 0x4d, 0x89, 0x0a, 0x2a, 0xef, 0xf1, 0x2e, 0xf7,
+ 0x97, 0x83, 0xbd, 0xa0, 0xb7, 0xe7, 0xfa, 0xd4, 0x7d, 0xb0, 0x25, 0xb6,
+ 0xb1, 0xda, 0x0a, 0xf3, 0x18, 0xfb, 0xe4, 0x99, 0xc7, 0xaa, 0x8f, 0xa3,
+ 0x3d, 0xcf, 0x7a, 0x44, 0x69, 0x89, 0x58, 0xcf, 0x2f, 0xb3, 0x2e, 0x41,
+ 0x3f, 0x03, 0xbd, 0xaa, 0x38, 0x2c, 0xff, 0x2f, 0x85, 0xf6, 0x29, 0x52,
+ 0x7f, 0x86, 0xf5, 0xfd, 0x05, 0x2a, 0xc0, 0xc6, 0xa7, 0x70, 0xd2, 0x22,
+ 0x68, 0x5a, 0x68, 0xf6, 0x81, 0x57, 0x6d, 0xbb, 0x83, 0x7c, 0x07, 0xff,
+ 0xc7, 0x0b, 0xe6, 0x77, 0x03, 0x27, 0xb6, 0x99, 0x9a, 0x2a, 0x52, 0x15,
+ 0x3f, 0xe8, 0x8d, 0xa1, 0x67, 0x6d, 0x49, 0x9f, 0x28, 0x03, 0x37, 0xe8,
+ 0x3d, 0xd9, 0x7b, 0x58, 0x9f, 0x31, 0xc7, 0xa5, 0xa1, 0xb6, 0x9d, 0x2d,
+ 0x38, 0x2c, 0xa7, 0x2e, 0x9c, 0xdb, 0xc6, 0x49, 0x46, 0x1f, 0xef, 0xa3,
+ 0x40, 0xe7, 0xdb, 0x3a, 0xc3, 0xfa, 0xa7, 0x5b, 0xeb, 0xd4, 0x41, 0xd9,
+ 0x0c, 0x7c, 0xd9, 0xbc, 0x08, 0xf9, 0xa5, 0xe1, 0x53, 0x64, 0x7a, 0xba,
+ 0x99, 0xa4, 0x63, 0x4d, 0xc6, 0xaf, 0x08, 0xbb, 0x83, 0x6f, 0x9b, 0x1f,
+ 0x85, 0x9d, 0x8d, 0x0b, 0x23, 0xb0, 0x89, 0x47, 0x17, 0x19, 0x27, 0x8f,
+ 0xd8, 0x2e, 0x8b, 0xcb, 0x65, 0x61, 0xd4, 0x2d, 0x09, 0xe3, 0xcb, 0x6c,
+ 0x27, 0x6c, 0x23, 0xba, 0xfa, 0x38, 0x31, 0x0d, 0x98, 0xe3, 0xfe, 0x22,
+ 0xc1, 0xb6, 0x5a, 0x3b, 0x17, 0x07, 0x1e, 0xdb, 0x80, 0x4f, 0x37, 0x6c,
+ 0x0f, 0xfa, 0x65, 0xe8, 0x13, 0xac, 0x33, 0xc5, 0x8c, 0xa1, 0xfd, 0x25,
+ 0x7d, 0x9c, 0x0f, 0x23, 0x1b, 0x7c, 0x18, 0x00, 0x4f, 0x3e, 0xcc, 0x87,
+ 0xfa, 0xc7, 0xf9, 0x60, 0x55, 0xc1, 0x87, 0x3a, 0xfc, 0x50, 0xdd, 0x65,
+ 0x9a, 0x3d, 0x12, 0xf7, 0x10, 0xb4, 0x93, 0xf6, 0x8a, 0x26, 0xeb, 0x28,
+ 0xdb, 0x49, 0x46, 0x9b, 0xc6, 0x0e, 0x4b, 0x4e, 0xb7, 0x6f, 0x1b, 0xa3,
+ 0x3e, 0x2f, 0x7e, 0x17, 0xbd, 0x4c, 0xdf, 0x1d, 0x9a, 0xc7, 0x17, 0xd9,
+ 0xdf, 0x40, 0xcf, 0x33, 0x86, 0x7a, 0x88, 0xee, 0xd0, 0xbd, 0xef, 0x0e,
+ 0xdd, 0x38, 0xa7, 0xed, 0x83, 0x98, 0xe6, 0xb6, 0x3f, 0x66, 0x5d, 0x79,
+ 0xc3, 0x93, 0x0c, 0x03, 0x32, 0x60, 0x7d, 0x61, 0x1c, 0x74, 0xf5, 0xcb,
+ 0xa0, 0xa7, 0x02, 0xbf, 0xc0, 0xb6, 0x54, 0xf6, 0xe7, 0x75, 0x50, 0xb9,
+ 0x27, 0x98, 0x3f, 0xd5, 0xf4, 0xfe, 0x4b, 0x34, 0x3f, 0xf0, 0xec, 0xbc,
+ 0x11, 0xda, 0xb8, 0x42, 0x7f, 0xb2, 0xa8, 0x97, 0x35, 0xa1, 0x9b, 0xaa,
+ 0xf7, 0xc3, 0xaf, 0x34, 0xd9, 0x3e, 0x76, 0xde, 0xc3, 0x97, 0xa5, 0x43,
+ 0x5f, 0xf6, 0x3e, 0x78, 0xcf, 0xb1, 0xe7, 0xe8, 0x07, 0xeb, 0x49, 0x7e,
+ 0x66, 0xd4, 0x09, 0x2a, 0x71, 0xbc, 0xd9, 0x21, 0xfa, 0xfe, 0xbb, 0x8f,
+ 0x63, 0x41, 0x55, 0x36, 0xe3, 0x54, 0xed, 0xa1, 0xaa, 0x64, 0xb2, 0x1d,
+ 0xb1, 0x6d, 0xb4, 0xf1, 0xde, 0x1e, 0xc6, 0xdd, 0x41, 0x89, 0x0c, 0x1e,
+ 0x47, 0x8c, 0x68, 0x32, 0x0d, 0xef, 0x87, 0xf2, 0x60, 0x7f, 0x4a, 0xb1,
+ 0x40, 0xdf, 0xf6, 0xc3, 0x5f, 0x32, 0x3f, 0x37, 0xeb, 0x0a, 0xfb, 0x51,
+ 0xd2, 0x44, 0x83, 0xfd, 0x28, 0xa9, 0x92, 0x79, 0x50, 0xb0, 0x16, 0xbf,
+ 0x26, 0x58, 0xe0, 0x9b, 0x05, 0xbe, 0x59, 0xe0, 0x9b, 0x0d, 0xbe, 0x15,
+ 0x5c, 0xc6, 0x85, 0xf1, 0x08, 0xf6, 0x2f, 0x06, 0xfb, 0x03, 0xc7, 0x9d,
+ 0x54, 0xf1, 0xed, 0x9b, 0x69, 0x85, 0x3f, 0xf6, 0x7d, 0xc1, 0xa8, 0x10,
+ 0xf8, 0x02, 0xde, 0x6f, 0x1c, 0xeb, 0x1f, 0x47, 0x8c, 0xb3, 0x44, 0xd1,
+ 0xb8, 0xc3, 0x8f, 0xfa, 0x26, 0x7e, 0x4c, 0x3b, 0xcc, 0x1f, 0x9e, 0xcf,
+ 0x76, 0xec, 0x40, 0xe6, 0x6d, 0x9e, 0xec, 0x07, 0x0e, 0x9d, 0x4c, 0x77,
+ 0x48, 0x07, 0xef, 0xdf, 0x1b, 0xee, 0x7f, 0x00, 0x7b, 0xb2, 0xdd, 0xde,
+ 0xed, 0x5c, 0x3e, 0x93, 0xe3, 0xe8, 0x27, 0xd1, 0x83, 0x3c, 0x02, 0x7e,
+ 0x66, 0x0d, 0x76, 0x76, 0x53, 0x4a, 0xd1, 0xeb, 0xbb, 0x6f, 0x20, 0xb7,
+ 0xa0, 0xea, 0x03, 0xa6, 0xa7, 0xc9, 0xe6, 0xfb, 0x5e, 0x3d, 0x0f, 0xdf,
+ 0x69, 0xea, 0x29, 0x5b, 0x1a, 0xa4, 0x37, 0xdc, 0x2c, 0xfd, 0x9d, 0x6b,
+ 0xd0, 0xdf, 0xba, 0x1a, 0xbd, 0xea, 0xa6, 0xe9, 0x6f, 0xdc, 0x14, 0xfd,
+ 0xb5, 0xdb, 0xce, 0x43, 0x92, 0xac, 0x47, 0x89, 0xa2, 0x7b, 0xb7, 0x5c,
+ 0x08, 0x3a, 0x8e, 0xbd, 0xec, 0xbc, 0x5c, 0x96, 0x4d, 0x3f, 0x3f, 0x98,
+ 0x98, 0x6e, 0x90, 0xb2, 0xd3, 0xa0, 0xed, 0xf7, 0x23, 0xef, 0x49, 0x9a,
+ 0xb4, 0xe3, 0x3e, 0x3c, 0x7b, 0x4d, 0xb2, 0x7a, 0xcc, 0x53, 0x9e, 0x68,
+ 0xb0, 0x1e, 0x75, 0x0f, 0x4f, 0xe5, 0xe3, 0x8c, 0xfb, 0xc4, 0x34, 0xfc,
+ 0x91, 0x8d, 0xb3, 0xaa, 0xd0, 0xc5, 0xaa, 0x7b, 0xe8, 0xfe, 0x20, 0x17,
+ 0x7a, 0x2f, 0xcc, 0x89, 0x38, 0xaf, 0x5a, 0x7f, 0x6a, 0xc2, 0x60, 0x3f,
+ 0x2b, 0x6c, 0xf2, 0xb3, 0x24, 0x14, 0x41, 0x53, 0x1d, 0xb8, 0x16, 0x41,
+ 0xe7, 0x57, 0x5d, 0x45, 0x28, 0x9c, 0xef, 0xa5, 0xe9, 0x45, 0x8e, 0x55,
+ 0x3c, 0x4f, 0x09, 0x73, 0x19, 0x7e, 0xef, 0xc0, 0x3b, 0x21, 0x7e, 0x14,
+ 0xb6, 0x53, 0x42, 0x7f, 0x73, 0x82, 0x9c, 0x30, 0x17, 0x89, 0xd1, 0x05,
+ 0x5f, 0x77, 0xb8, 0xdf, 0x2a, 0xfd, 0xb0, 0xff, 0x4e, 0xff, 0xf9, 0x8d,
+ 0xfe, 0x72, 0xe9, 0xeb, 0x1b, 0xfd, 0xef, 0xa8, 0x01, 0x4e, 0xc3, 0xc2,
+ 0xe3, 0xee, 0xf3, 0x61, 0xdf, 0x6d, 0xf0, 0xd3, 0xf3, 0xea, 0x88, 0x27,
+ 0x35, 0xe3, 0x36, 0x72, 0x1f, 0xf6, 0x29, 0x5b, 0xf1, 0x21, 0x1f, 0xf2,
+ 0x1f, 0xaa, 0x2d, 0xb1, 0x9c, 0x14, 0x0a, 0xf6, 0xe4, 0xf1, 0x4e, 0xf8,
+ 0x92, 0xdb, 0x68, 0x73, 0xec, 0x6a, 0xfb, 0x31, 0x9e, 0xc3, 0xeb, 0x6f,
+ 0xdd, 0x43, 0x96, 0x2a, 0x64, 0xb9, 0x35, 0x79, 0xd5, 0x1a, 0xa7, 0x42,
+ 0x9f, 0xd0, 0x3d, 0x6c, 0x43, 0x2e, 0x12, 0xe4, 0x52, 0x83, 0x5c, 0x0a,
+ 0xf7, 0x94, 0x0b, 0xce, 0xd8, 0xd0, 0x29, 0xc6, 0xa3, 0x2b, 0x3c, 0x9b,
+ 0x14, 0xd9, 0xac, 0x96, 0xea, 0xc6, 0xa7, 0x28, 0x66, 0x30, 0x1e, 0x06,
+ 0xf0, 0x38, 0x8a, 0xb5, 0x1c, 0xc3, 0x48, 0x89, 0x99, 0x2c, 0xcf, 0xdc,
+ 0x13, 0xb6, 0x71, 0xab, 0xb4, 0xe0, 0xdc, 0x2a, 0x5d, 0x34, 0xf8, 0xfd,
+ 0xf6, 0x64, 0x90, 0x37, 0x77, 0x3f, 0x89, 0xbc, 0x19, 0xeb, 0xd9, 0x1f,
+ 0x72, 0xff, 0x30, 0xe6, 0x71, 0x7c, 0xa0, 0x43, 0x35, 0xfc, 0xea, 0xfe,
+ 0xdc, 0x6b, 0x4f, 0xf0, 0xdc, 0x4e, 0x53, 0x9e, 0xfc, 0x35, 0x9e, 0x1d,
+ 0xa6, 0xf6, 0xe4, 0x4f, 0x0d, 0xde, 0x77, 0x78, 0xf2, 0xa2, 0xbf, 0x07,
+ 0x62, 0xa6, 0xbf, 0x36, 0xfb, 0x24, 0xaf, 0x7d, 0x0e, 0x3e, 0xf6, 0x0c,
+ 0xe2, 0xcb, 0x69, 0x47, 0x3b, 0x54, 0xc1, 0x6f, 0x8a, 0x71, 0x6a, 0xf2,
+ 0xb8, 0x85, 0x71, 0x19, 0xb1, 0x90, 0xdb, 0x0a, 0x1d, 0xc3, 0xbc, 0xa7,
+ 0x31, 0xef, 0xa8, 0x33, 0x8e, 0xbc, 0xbd, 0x4d, 0xd7, 0xbf, 0xc5, 0x0b,
+ 0xf3, 0xec, 0xcf, 0x91, 0xed, 0xaf, 0xfc, 0x7b, 0xdc, 0x86, 0x5f, 0x16,
+ 0x57, 0x6e, 0xc6, 0x0b, 0xa0, 0x5b, 0x5a, 0xf9, 0x45, 0xbc, 0x08, 0x3d,
+ 0x13, 0x0d, 0x09, 0x7e, 0xf9, 0x33, 0x54, 0x53, 0x3d, 0x7a, 0x19, 0xf1,
+ 0xab, 0x96, 0x85, 0xbf, 0x82, 0x34, 0x45, 0x03, 0x7e, 0x4c, 0x25, 0xa5,
+ 0xcb, 0x3c, 0xa9, 0x52, 0x57, 0x3e, 0x6e, 0x23, 0xde, 0xd4, 0x54, 0x09,
+ 0xfd, 0xfd, 0x78, 0x6e, 0xee, 0xff, 0x65, 0x1c, 0x7e, 0x0b, 0x3e, 0x82,
+ 0x14, 0x3b, 0xdf, 0x8d, 0xfd, 0xbf, 0x8d, 0x7e, 0x4c, 0xc8, 0x6c, 0xf4,
+ 0x3f, 0x1b, 0xf4, 0xdf, 0x02, 0x2e, 0xbc, 0x8e, 0xe3, 0x27, 0x29, 0x53,
+ 0x79, 0x15, 0x38, 0xf0, 0xdc, 0xa4, 0x3f, 0xb7, 0x38, 0xcf, 0x3c, 0xa8,
+ 0x96, 0x16, 0x8c, 0x34, 0x15, 0xe6, 0x92, 0x34, 0x3a, 0xa7, 0xd2, 0xd8,
+ 0x9c, 0x3e, 0xd1, 0x62, 0xfb, 0x01, 0xcd, 0x84, 0x1c, 0x41, 0x5c, 0x21,
+ 0x50, 0xac, 0xa7, 0x9e, 0xa6, 0xbe, 0xd4, 0x31, 0xfa, 0x6f, 0x0f, 0xb1,
+ 0x08, 0x71, 0xa8, 0x9b, 0x64, 0x7f, 0x9f, 0x54, 0xfb, 0x4c, 0x96, 0xd1,
+ 0x87, 0xce, 0x2d, 0xce, 0xdf, 0x6b, 0x5f, 0x28, 0xf1, 0x4a, 0xea, 0x23,
+ 0xfb, 0xbe, 0x1b, 0xee, 0xab, 0x62, 0xdf, 0x34, 0xf6, 0x64, 0x1a, 0xf5,
+ 0xf8, 0xc8, 0x79, 0xb2, 0x3a, 0x81, 0x5f, 0x31, 0x83, 0x98, 0x8f, 0x7d,
+ 0xce, 0xcc, 0xb1, 0xde, 0xd3, 0x4e, 0xfc, 0x06, 0x63, 0x94, 0xc9, 0x2e,
+ 0x23, 0x27, 0x18, 0xf1, 0xf7, 0x08, 0xf2, 0x05, 0x71, 0x65, 0x10, 0xf9,
+ 0xda, 0x3b, 0xc0, 0x87, 0xe3, 0x18, 0xd3, 0x2c, 0x83, 0xde, 0x41, 0xe4,
+ 0x09, 0x9c, 0xe3, 0x7b, 0xa7, 0xec, 0x1c, 0xda, 0xcb, 0x5a, 0xbc, 0x00,
+ 0xdb, 0x16, 0x4d, 0x7a, 0x50, 0xf2, 0x7d, 0x2c, 0xcb, 0x65, 0x10, 0x72,
+ 0x62, 0xbc, 0x73, 0x90, 0x13, 0xf3, 0x68, 0x38, 0x5e, 0x6c, 0x32, 0x8f,
+ 0x08, 0xf8, 0x68, 0xb0, 0x27, 0xd9, 0xcf, 0xf3, 0xc5, 0x15, 0x0b, 0xf3,
+ 0x7e, 0xac, 0x72, 0x2e, 0x66, 0x1b, 0xdc, 0x86, 0xed, 0xac, 0x8c, 0x63,
+ 0x2e, 0xb7, 0x1f, 0xc6, 0xbe, 0x7d, 0xb9, 0x1a, 0x75, 0xe4, 0x9e, 0x86,
+ 0xdd, 0x8a, 0xf9, 0x01, 0xc4, 0x68, 0x01, 0xb9, 0xa0, 0xe7, 0x75, 0xe4,
+ 0xbf, 0x00, 0x7a, 0x98, 0x0e, 0xe8, 0xf5, 0x2c, 0xf3, 0x95, 0xfe, 0x40,
+ 0xe4, 0x5c, 0x2d, 0xdf, 0xce, 0x6b, 0x38, 0x9e, 0xf3, 0xf9, 0x88, 0x23,
+ 0x8d, 0x3d, 0x88, 0xa5, 0xfe, 0xd9, 0xd0, 0xb1, 0x71, 0x2a, 0x34, 0x3e,
+ 0x8b, 0x9c, 0x93, 0x6d, 0x67, 0x9b, 0x60, 0x9f, 0x67, 0x1a, 0x09, 0xb1,
+ 0x66, 0x8d, 0x2a, 0x0d, 0x39, 0x6c, 0xbf, 0x8a, 0xb6, 0x12, 0xb6, 0xd7,
+ 0xd1, 0xee, 0x0e, 0xdb, 0xd7, 0xd0, 0x56, 0xc3, 0xf6, 0xcf, 0xd0, 0x4e,
+ 0x86, 0xed, 0x9f, 0xa3, 0x9d, 0x0a, 0xdb, 0x37, 0xd1, 0x4e, 0x87, 0xed,
+ 0x5b, 0x68, 0x6b, 0x61, 0xfb, 0x3d, 0xb4, 0x13, 0xb0, 0x73, 0x03, 0xef,
+ 0x37, 0x50, 0x2b, 0x66, 0xf1, 0xfc, 0x57, 0xe0, 0x36, 0x08, 0xde, 0x64,
+ 0xc1, 0x8f, 0x5e, 0x8c, 0xe5, 0xd0, 0x87, 0x1c, 0xb1, 0x91, 0xc7, 0xd3,
+ 0xc1, 0x18, 0x95, 0x61, 0x7b, 0x18, 0x1f, 0x2f, 0x16, 0x1a, 0x26, 0x9e,
+ 0x6c, 0x0f, 0xba, 0x4a, 0xc2, 0x65, 0xd8, 0xb9, 0xef, 0x63, 0x72, 0xb6,
+ 0x34, 0x09, 0xdb, 0x9e, 0xa0, 0x7f, 0x74, 0xf7, 0xd3, 0x6b, 0xee, 0x38,
+ 0xe2, 0x46, 0x11, 0x71, 0xc3, 0x42, 0xdc, 0x30, 0x11, 0x37, 0x86, 0x11,
+ 0x37, 0xf2, 0x88, 0x1b, 0x39, 0xc4, 0x0d, 0xa2, 0x33, 0x7e, 0x8c, 0x4a,
+ 0x2a, 0xa8, 0x51, 0x15, 0xcb, 0x2d, 0x82, 0xbf, 0x13, 0x90, 0xcd, 0x24,
+ 0x78, 0x7d, 0x38, 0x3e, 0xd2, 0xcc, 0xc3, 0x9f, 0x69, 0xf0, 0x11, 0x69,
+ 0xf8, 0xf2, 0x1c, 0x6a, 0x13, 0xa2, 0x2b, 0xb3, 0x1a, 0xfc, 0x8f, 0x47,
+ 0x45, 0xc4, 0xfe, 0x69, 0x15, 0xb8, 0x19, 0xbb, 0x7c, 0x9b, 0x91, 0xcc,
+ 0x2f, 0xf6, 0x50, 0xd7, 0x20, 0xe8, 0x39, 0x8b, 0xbe, 0x14, 0xf6, 0x63,
+ 0xbe, 0xde, 0x2a, 0xd9, 0x86, 0x46, 0x0b, 0x6e, 0x1c, 0xfe, 0x9f, 0xdf,
+ 0xe3, 0xcc, 0xe3, 0x43, 0x4f, 0x19, 0x4c, 0x03, 0xea, 0x3c, 0x23, 0xad,
+ 0x14, 0x1c, 0x81, 0x24, 0x93, 0x9f, 0xed, 0x1c, 0xe2, 0xcf, 0x90, 0x43,
+ 0x74, 0x41, 0x06, 0x55, 0xc4, 0x05, 0x9d, 0xf3, 0x0b, 0xe8, 0xf2, 0x27,
+ 0xcd, 0xff, 0x1e, 0xe6, 0xef, 0xc5, 0xd9, 0x3c, 0x8f, 0xcf, 0x39, 0x85,
+ 0xfa, 0xc1, 0xea, 0x91, 0x68, 0x3d, 0x25, 0xa1, 0x9e, 0x28, 0xd0, 0x59,
+ 0x2a, 0x00, 0x9f, 0x82, 0xdb, 0xbe, 0x07, 0xb0, 0x0e, 0x05, 0xfe, 0x6c,
+ 0xe2, 0xd0, 0xb7, 0x0d, 0x0b, 0xeb, 0x18, 0x3f, 0xd6, 0x5b, 0xe0, 0xbe,
+ 0xb1, 0xe7, 0x05, 0xec, 0xf9, 0x4f, 0x49, 0xea, 0x9a, 0x0c, 0xfc, 0x91,
+ 0x5f, 0xf3, 0xca, 0xc2, 0x48, 0xf3, 0x2c, 0xf8, 0xd3, 0x87, 0x1a, 0x05,
+ 0x7e, 0xa4, 0xd4, 0x02, 0x9f, 0xda, 0xf3, 0x5f, 0xc1, 0x7c, 0x7e, 0xf7,
+ 0xef, 0x0e, 0x4a, 0xd2, 0xea, 0x12, 0xe6, 0x69, 0xac, 0x3f, 0x25, 0xb9,
+ 0xff, 0x86, 0xf7, 0xa2, 0x91, 0xa7, 0x5d, 0xab, 0xbc, 0x2e, 0x4b, 0x7d,
+ 0xab, 0x37, 0xbc, 0x9a, 0xa3, 0xd1, 0x62, 0x93, 0xc0, 0xab, 0xf8, 0x6d,
+ 0x8b, 0xf4, 0x35, 0x12, 0xf5, 0x59, 0x0b, 0x7a, 0x5a, 0x1c, 0x12, 0xc9,
+ 0x1e, 0xea, 0x84, 0x8f, 0x32, 0x68, 0x09, 0x7c, 0xdf, 0x35, 0x63, 0xd1,
+ 0x13, 0x43, 0xed, 0x7c, 0x10, 0x51, 0x0f, 0xb8, 0xee, 0x5a, 0xd5, 0x30,
+ 0x87, 0x73, 0x71, 0xa6, 0x45, 0x03, 0x2f, 0x85, 0x60, 0x8d, 0x1f, 0xb3,
+ 0xb8, 0x8e, 0x05, 0xdf, 0xdc, 0xb5, 0xd2, 0xd5, 0x19, 0xd4, 0x1a, 0x90,
+ 0xf3, 0xae, 0x19, 0xae, 0x85, 0xb6, 0x81, 0x2f, 0x31, 0xd8, 0x06, 0xe7,
+ 0xf1, 0x08, 0xf4, 0xf0, 0x87, 0x27, 0xe0, 0xf1, 0x6b, 0xcd, 0x13, 0xd0,
+ 0xfb, 0x2e, 0x2a, 0xcb, 0x3e, 0x11, 0x9f, 0xc0, 0xe3, 0xff, 0xe4, 0xbc,
+ 0x0e, 0xf3, 0xbf, 0x4b, 0xc5, 0xd9, 0x2e, 0xec, 0xb5, 0x9b, 0xa6, 0x93,
+ 0x8c, 0x9b, 0x3e, 0x8c, 0x41, 0x2d, 0x06, 0x7e, 0xc6, 0xcd, 0x8f, 0xe6,
+ 0x7d, 0x6b, 0xa5, 0x2b, 0x33, 0x6b, 0xa5, 0x6b, 0xa0, 0xbf, 0x6e, 0x70,
+ 0x8d, 0x0c, 0x5d, 0x6a, 0x70, 0x6d, 0xcf, 0x79, 0xd1, 0x18, 0x74, 0x64,
+ 0xbf, 0x5f, 0x33, 0xdb, 0x8b, 0x39, 0xea, 0x3b, 0x47, 0xaa, 0x68, 0x96,
+ 0x84, 0x31, 0xe4, 0x45, 0x23, 0xee, 0x49, 0x7f, 0xee, 0x99, 0x06, 0xd7,
+ 0x2b, 0x18, 0x5b, 0x61, 0x5d, 0x18, 0x03, 0x3e, 0x49, 0xba, 0xe8, 0xb2,
+ 0x4f, 0x0a, 0xec, 0x78, 0x0c, 0xfc, 0x5a, 0xf0, 0xe9, 0x4a, 0x71, 0x1c,
+ 0x47, 0xbe, 0xc1, 0xf2, 0xf9, 0x21, 0xc7, 0x41, 0xa1, 0xd3, 0x6c, 0xfb,
+ 0xdb, 0x89, 0x5e, 0xe6, 0x59, 0xa1, 0x01, 0xdf, 0x3f, 0x34, 0x11, 0xe6,
+ 0x1c, 0x7f, 0x8f, 0x39, 0x8c, 0x3b, 0xcd, 0x4a, 0x26, 0xce, 0xc8, 0x33,
+ 0xcf, 0x38, 0xa7, 0xe4, 0x7d, 0xc1, 0x5b, 0xf0, 0x7d, 0x53, 0x6e, 0xe9,
+ 0xc3, 0x74, 0x33, 0x46, 0x95, 0x59, 0xf0, 0x2e, 0x8f, 0x27, 0x9c, 0x6b,
+ 0x1d, 0x7c, 0x03, 0x2d, 0xd5, 0x20, 0x9f, 0x3d, 0xc1, 0x31, 0x0d, 0xfe,
+ 0x06, 0x36, 0xcd, 0x31, 0x6b, 0xe3, 0xde, 0xc9, 0xf7, 0x25, 0x32, 0x19,
+ 0x41, 0xce, 0x2a, 0xe2, 0x2c, 0x3b, 0xcf, 0x7e, 0x10, 0xf8, 0xb8, 0xdf,
+ 0xa5, 0xfa, 0x2c, 0xd3, 0x05, 0x1b, 0x4f, 0xb2, 0x2e, 0xfe, 0x7f, 0xf9,
+ 0x38, 0xba, 0x45, 0x3e, 0x8e, 0x6e, 0x99, 0x8f, 0x12, 0xf8, 0x58, 0xd9,
+ 0xe0, 0xa3, 0x82, 0x3d, 0xf8, 0x3e, 0xe1, 0xab, 0x64, 0x4d, 0x3c, 0x02,
+ 0x3f, 0x0c, 0xff, 0xd1, 0x3c, 0x05, 0x9f, 0x70, 0x52, 0xb8, 0xda, 0xf0,
+ 0x68, 0x1c, 0xb5, 0xb2, 0x74, 0xff, 0x66, 0xfa, 0x33, 0xa0, 0xff, 0xcf,
+ 0x31, 0x5e, 0xa5, 0x6b, 0xb3, 0x94, 0x56, 0xa8, 0x7d, 0x2e, 0xed, 0x92,
+ 0xe9, 0x3b, 0x74, 0x75, 0xb6, 0x8b, 0xae, 0xcf, 0x66, 0xc0, 0xeb, 0x2c,
+ 0xc5, 0x7a, 0x32, 0xc3, 0x15, 0x18, 0xf1, 0xcf, 0x5a, 0xba, 0xc5, 0xba,
+ 0xf8, 0xfb, 0xf3, 0x82, 0xf9, 0x70, 0xd0, 0xe7, 0xc3, 0xd8, 0x47, 0xf8,
+ 0x30, 0x7e, 0x4f, 0x3e, 0x1c, 0xfc, 0x18, 0x1f, 0xc6, 0x3f, 0xc6, 0x07,
+ 0xe6, 0x01, 0xf3, 0xe2, 0xd1, 0xde, 0xf0, 0xff, 0x1f, 0x7d, 0x82, 0x7d,
+ 0x7c, 0x09, 0x74, 0x22, 0xa7, 0xd8, 0x19, 0xe4, 0x50, 0x9c, 0x63, 0xd5,
+ 0x0c, 0xe6, 0x57, 0x60, 0xbf, 0x32, 0x72, 0xea, 0x23, 0xa1, 0xfd, 0x16,
+ 0x1c, 0xe8, 0x65, 0x23, 0xe6, 0xdb, 0xaf, 0x64, 0xe6, 0xe1, 0x03, 0xaa,
+ 0xa5, 0x96, 0xc3, 0xfe, 0x07, 0x6d, 0x87, 0x79, 0xda, 0x0b, 0x5a, 0x12,
+ 0x54, 0x99, 0x54, 0x10, 0x5f, 0x87, 0xa1, 0xb7, 0x71, 0xdf, 0x07, 0x4a,
+ 0x26, 0xeb, 0xe1, 0x7e, 0xcc, 0x3f, 0x1c, 0xe6, 0x45, 0x88, 0x73, 0x38,
+ 0xa3, 0xd6, 0x38, 0x0d, 0xfc, 0xf8, 0x9c, 0x6a, 0xa9, 0xec, 0xf0, 0x9a,
+ 0x34, 0x62, 0x21, 0x3f, 0x37, 0xeb, 0xb7, 0xaf, 0xef, 0xf7, 0xd2, 0x71,
+ 0xe8, 0x26, 0xeb, 0xb4, 0x82, 0xdc, 0x78, 0x02, 0xf1, 0xc5, 0xd7, 0xd3,
+ 0xec, 0x02, 0xb1, 0xdf, 0x7f, 0x06, 0x75, 0xd1, 0x61, 0xfc, 0x34, 0x1a,
+ 0x71, 0x03, 0x9b, 0x5a, 0xf2, 0xcf, 0xfc, 0xb0, 0x4f, 0xaa, 0x39, 0xeb,
+ 0xc8, 0xdf, 0x0d, 0xec, 0xcb, 0xe7, 0x56, 0xc1, 0x1b, 0x09, 0xe7, 0x72,
+ 0x5f, 0x37, 0xe2, 0x00, 0xf8, 0xe4, 0xfe, 0x07, 0xfa, 0x97, 0xe0, 0x1f,
+ 0x39, 0x2f, 0x68, 0xe3, 0x8e, 0x1c, 0xc2, 0xe1, 0x78, 0x9d, 0x07, 0xcd,
+ 0x9c, 0x63, 0x73, 0x2e, 0x81, 0xfc, 0x63, 0xe9, 0x4d, 0xf4, 0x0d, 0xd3,
+ 0xe9, 0xa1, 0x2c, 0xe4, 0xc3, 0x7d, 0x0f, 0x84, 0x7d, 0x3c, 0x8f, 0x94,
+ 0x07, 0x4d, 0xfd, 0x07, 0x55, 0xdf, 0xaf, 0x43, 0x0f, 0x51, 0xf7, 0xd5,
+ 0x96, 0x90, 0x63, 0x00, 0xa7, 0xca, 0x6a, 0x16, 0xb9, 0x3c, 0xdf, 0xab,
+ 0xe9, 0x97, 0x91, 0x07, 0x83, 0x27, 0x0a, 0xf5, 0x1a, 0xa5, 0xd0, 0x0f,
+ 0xe7, 0x40, 0x1f, 0xdf, 0x3d, 0xf5, 0x21, 0xf7, 0x91, 0xc0, 0x08, 0xd8,
+ 0xe9, 0xaa, 0x44, 0x7b, 0xe5, 0x01, 0xb5, 0x46, 0xff, 0x80, 0xb9, 0x32,
+ 0x95, 0x57, 0x39, 0x87, 0x90, 0xe9, 0xc8, 0x2a, 0xd1, 0x5b, 0x33, 0xec,
+ 0x97, 0x19, 0xd8, 0x2f, 0xb3, 0x7f, 0x7d, 0xd0, 0x1f, 0x7b, 0x6b, 0x06,
+ 0x35, 0xf8, 0xcc, 0x00, 0xc7, 0xb0, 0x75, 0x11, 0xbc, 0x44, 0xee, 0xc3,
+ 0xf9, 0xf9, 0x5d, 0xee, 0x98, 0xda, 0xf7, 0x4b, 0x0a, 0x55, 0x66, 0xf8,
+ 0x6e, 0x49, 0xc6, 0xf9, 0x5c, 0x5b, 0x6c, 0x03, 0x7e, 0x02, 0xa1, 0xee,
+ 0x12, 0x38, 0xa6, 0x09, 0xd0, 0xa1, 0x5d, 0x90, 0x3d, 0xf8, 0x1f, 0xb6,
+ 0xdb, 0xfa, 0xf4, 0x2f, 0xd0, 0x27, 0x9e, 0x27, 0x6f, 0xc2, 0x25, 0x33,
+ 0x6b, 0x8b, 0x1c, 0x1f, 0x3e, 0x0d, 0xdb, 0xb3, 0xe2, 0x63, 0xcd, 0x0e,
+ 0x6a, 0xf5, 0xb2, 0x3d, 0xb0, 0x5e, 0x5c, 0x66, 0x9d, 0xc0, 0x19, 0xd0,
+ 0xa1, 0x19, 0xae, 0xe7, 0x65, 0xcc, 0xbb, 0x2f, 0x9c, 0xc7, 0xfc, 0xfe,
+ 0x1e, 0x4d, 0x0f, 0xa9, 0x42, 0x59, 0x0d, 0xe2, 0x45, 0x6d, 0xa8, 0x03,
+ 0x63, 0x22, 0x1d, 0x7c, 0x38, 0x8f, 0xb5, 0x9c, 0x53, 0xc5, 0x85, 0xc0,
+ 0x6f, 0x71, 0x1f, 0xdf, 0xd7, 0xa9, 0x54, 0xbe, 0xd4, 0x4b, 0x95, 0x4b,
+ 0x0a, 0xf8, 0x02, 0x44, 0x17, 0x82, 0x7d, 0xd8, 0x17, 0x1c, 0x87, 0xdc,
+ 0xc4, 0x73, 0x0a, 0xc5, 0xce, 0x21, 0x87, 0xbc, 0xd0, 0x45, 0x1d, 0x17,
+ 0xfa, 0x49, 0xba, 0xa0, 0x73, 0x7e, 0xa8, 0x9d, 0x81, 0x0c, 0x8f, 0x50,
+ 0x9e, 0x9e, 0x73, 0x07, 0x39, 0xc7, 0xc3, 0x39, 0x5c, 0xe7, 0x25, 0x49,
+ 0x42, 0xf2, 0x2f, 0xbe, 0x68, 0xd1, 0x8b, 0x43, 0xc0, 0x2b, 0x8f, 0xf6,
+ 0x8f, 0x91, 0xc7, 0xbb, 0x23, 0xf7, 0x71, 0xcc, 0x96, 0xcd, 0x3e, 0xc8,
+ 0x16, 0x74, 0xe5, 0x1e, 0xf2, 0xef, 0x44, 0x5f, 0x1c, 0x62, 0x7a, 0x34,
+ 0xd0, 0x52, 0x87, 0xae, 0xf3, 0x3d, 0x57, 0x17, 0xd9, 0x32, 0xeb, 0x32,
+ 0xf2, 0xaa, 0x0b, 0x75, 0x9a, 0x6a, 0xe8, 0x90, 0x59, 0x1f, 0xf4, 0x02,
+ 0x32, 0x4b, 0x73, 0x3f, 0xef, 0x2d, 0x84, 0xfb, 0xde, 0xd1, 0xf7, 0x17,
+ 0xef, 0xad, 0xef, 0x3e, 0xd4, 0x9b, 0x8f, 0xc0, 0x67, 0xa3, 0x2e, 0x32,
+ 0xe0, 0xd3, 0x55, 0xe4, 0x72, 0x06, 0xbf, 0x07, 0x77, 0x95, 0x15, 0xe4,
+ 0x85, 0xfc, 0x5e, 0x6b, 0xdd, 0xcd, 0x77, 0x07, 0xf6, 0x7d, 0x06, 0x3c,
+ 0xba, 0x32, 0xf7, 0x00, 0x5d, 0x9d, 0x53, 0xe8, 0x5a, 0x43, 0xcf, 0x16,
+ 0xa8, 0x83, 0xaa, 0xc9, 0x34, 0x5d, 0x5f, 0x6a, 0xe7, 0x93, 0x22, 0xf4,
+ 0xc4, 0x22, 0xce, 0xcd, 0xaf, 0x2c, 0x55, 0x4b, 0x37, 0x76, 0xa7, 0x49,
+ 0x7e, 0x09, 0xb6, 0xfd, 0x92, 0xae, 0xd5, 0xc0, 0xe7, 0xba, 0xe1, 0xa2,
+ 0x56, 0xe3, 0x3a, 0x32, 0x05, 0xbb, 0xd3, 0x53, 0x2d, 0xca, 0x90, 0xb4,
+ 0xa0, 0xd0, 0xaf, 0x66, 0x74, 0x8d, 0x75, 0xee, 0xa2, 0x81, 0x7e, 0x37,
+ 0x7e, 0x7b, 0x3d, 0xd0, 0x43, 0xf4, 0xf5, 0xa3, 0xbe, 0xd5, 0xb3, 0x9a,
+ 0xd8, 0x4d, 0x6f, 0x43, 0x27, 0xca, 0x7e, 0xdf, 0x47, 0xf7, 0xbc, 0x1e,
+ 0xee, 0x59, 0x2d, 0x5d, 0xe1, 0x3a, 0x68, 0x86, 0x75, 0xbe, 0x17, 0xfe,
+ 0x03, 0xef, 0x6e, 0x07, 0x95, 0x27, 0x11, 0xa3, 0x66, 0x1e, 0xa5, 0xc2,
+ 0x90, 0x18, 0xd0, 0xed, 0xf3, 0x82, 0xfb, 0xf8, 0x7e, 0xb2, 0x76, 0x1f,
+ 0xdb, 0xb2, 0xb8, 0x0a, 0xbd, 0x3a, 0xc8, 0x7a, 0x80, 0xdc, 0x0e, 0x39,
+ 0x04, 0xfb, 0x4e, 0x09, 0x39, 0x44, 0xc1, 0x0d, 0x74, 0xa3, 0x75, 0x30,
+ 0x49, 0xc7, 0x5e, 0x62, 0x19, 0x61, 0x6c, 0x43, 0xef, 0x36, 0xee, 0xc4,
+ 0x31, 0x66, 0xd0, 0xf1, 0xef, 0xb7, 0x73, 0x4a, 0xb6, 0xbd, 0x34, 0xe4,
+ 0xa1, 0xa3, 0xf6, 0xe8, 0x53, 0x2b, 0xbe, 0x4f, 0x81, 0x4e, 0xa4, 0x02,
+ 0x19, 0xd4, 0x30, 0x36, 0xed, 0x4e, 0xc2, 0x27, 0xc6, 0xe8, 0xe6, 0xa4,
+ 0x05, 0x9d, 0x68, 0x01, 0x87, 0xc3, 0x71, 0xbe, 0x4b, 0xb8, 0x39, 0x59,
+ 0xc4, 0xfb, 0x61, 0x3f, 0xf7, 0x97, 0xf6, 0x40, 0x97, 0xdc, 0x07, 0xc2,
+ 0xfc, 0x9c, 0xcf, 0xd3, 0x84, 0xda, 0xac, 0x2e, 0x4c, 0xcf, 0x7a, 0x34,
+ 0x9a, 0xeb, 0x4b, 0x5d, 0xa5, 0x4e, 0xff, 0xce, 0xd8, 0xf7, 0x9b, 0xfe,
+ 0x9c, 0x5d, 0x18, 0xff, 0x00, 0x3a, 0x85, 0x27, 0xe2, 0xf5, 0xe9, 0x66,
+ 0x35, 0xd5, 0x41, 0xac, 0x53, 0x24, 0x2c, 0x18, 0xec, 0x3b, 0x04, 0xba,
+ 0xea, 0xdf, 0x47, 0x13, 0x15, 0x9d, 0xd7, 0x99, 0x6e, 0x61, 0xb1, 0xc5,
+ 0x6b, 0x58, 0xce, 0xbc, 0x46, 0xa2, 0x9b, 0x49, 0xd8, 0xe5, 0x9e, 0x3d,
+ 0x7e, 0xbd, 0xf8, 0xf8, 0x10, 0xe3, 0xda, 0x0d, 0x99, 0x42, 0xbf, 0x50,
+ 0xdb, 0x94, 0x83, 0xbe, 0x59, 0xae, 0x4d, 0xa7, 0xf9, 0xde, 0x23, 0xef,
+ 0xeb, 0x5a, 0xa8, 0x1f, 0x1f, 0xd7, 0xb5, 0xe7, 0xb0, 0xf6, 0x2d, 0xf6,
+ 0xab, 0x90, 0x75, 0xe0, 0x23, 0xbe, 0x41, 0x6f, 0xcd, 0x55, 0xb3, 0xfc,
+ 0xcd, 0xa3, 0x35, 0x21, 0xa0, 0x16, 0x3f, 0x4e, 0x6f, 0xcf, 0x3d, 0x4b,
+ 0xbf, 0x9c, 0x65, 0xdd, 0x31, 0x68, 0x14, 0xfa, 0x74, 0x94, 0xe4, 0xec,
+ 0x69, 0x1a, 0x50, 0xaf, 0xfb, 0xb5, 0x8d, 0x9e, 0xf3, 0x6b, 0x3a, 0x33,
+ 0x4b, 0xc5, 0xc6, 0x40, 0xea, 0x1a, 0xfa, 0xca, 0x93, 0xba, 0xb6, 0x8e,
+ 0xdc, 0xa3, 0xd0, 0xfc, 0x80, 0xef, 0x6c, 0xb2, 0x35, 0xd8, 0xde, 0x22,
+ 0x6a, 0x9b, 0xb7, 0x9d, 0xbb, 0xe9, 0x2c, 0xd7, 0x56, 0x81, 0xff, 0x5e,
+ 0x33, 0x50, 0x63, 0xac, 0xaa, 0xa1, 0x0e, 0x31, 0x70, 0x9d, 0xc1, 0xf1,
+ 0x07, 0x4f, 0x37, 0x06, 0x9f, 0xb2, 0x1f, 0x7c, 0x67, 0xd9, 0x42, 0xfe,
+ 0xab, 0xfc, 0x8d, 0x0a, 0xf2, 0x5f, 0x5d, 0xfe, 0x40, 0xeb, 0x65, 0x3f,
+ 0x6b, 0x80, 0x96, 0x41, 0x3a, 0x33, 0xcf, 0xf2, 0x47, 0xec, 0xf5, 0xed,
+ 0x34, 0x0d, 0xfe, 0x72, 0x7c, 0x19, 0xa4, 0x5f, 0x2d, 0x15, 0xfd, 0xfb,
+ 0x6b, 0x1b, 0xb9, 0xd6, 0x11, 0x67, 0x12, 0xf5, 0xfa, 0x77, 0x40, 0x2f,
+ 0xce, 0x1e, 0xda, 0x8d, 0xa7, 0x0a, 0x9b, 0xdc, 0x72, 0x9e, 0x23, 0x07,
+ 0x79, 0xce, 0xde, 0x2d, 0xe6, 0x39, 0x7b, 0xb7, 0x92, 0xe7, 0xc8, 0x9d,
+ 0xe0, 0xab, 0xd6, 0xbb, 0x65, 0xdc, 0xa4, 0x00, 0xb7, 0x03, 0x5b, 0xc4,
+ 0xed, 0xc0, 0x56, 0x70, 0x93, 0x3a, 0xcd, 0xbf, 0x40, 0x8c, 0x35, 0x10,
+ 0xdb, 0xe0, 0xd7, 0x86, 0xfa, 0x59, 0x7f, 0x80, 0xa3, 0x8f, 0xeb, 0xef,
+ 0x8b, 0xa7, 0x18, 0xe0, 0xf9, 0xd8, 0x16, 0xf1, 0x7c, 0x6c, 0x2b, 0x78,
+ 0x8a, 0x9d, 0x26, 0xe3, 0x28, 0xc3, 0xd7, 0x70, 0x6d, 0x83, 0xd8, 0x3c,
+ 0x24, 0x87, 0xba, 0x2e, 0x87, 0x75, 0x0e, 0x03, 0x7c, 0x50, 0xaf, 0x46,
+ 0x4b, 0x4c, 0xcb, 0x46, 0xdf, 0x9d, 0x3a, 0x4b, 0x32, 0x5b, 0xa5, 0x4a,
+ 0x83, 0xef, 0x95, 0xfb, 0xb0, 0x0f, 0xf7, 0xf1, 0x37, 0x2a, 0x8b, 0x64,
+ 0xc4, 0xf7, 0xe7, 0x9a, 0x77, 0xa7, 0xf5, 0x2a, 0x68, 0x9d, 0x0a, 0x69,
+ 0xad, 0xf8, 0xb9, 0xe0, 0xbe, 0x4d, 0xb9, 0x60, 0x40, 0xe3, 0x08, 0x68,
+ 0x2c, 0x86, 0x34, 0x3e, 0xdd, 0x60, 0xda, 0xf6, 0xf9, 0xb4, 0x2d, 0x6d,
+ 0xa2, 0x6d, 0xe4, 0x9e, 0xf9, 0x1f, 0xe3, 0x81, 0x5a, 0x1a, 0xb9, 0xd7,
+ 0x6b, 0x4d, 0xd4, 0xd2, 0x4d, 0xd4, 0xd2, 0xd0, 0xf7, 0x57, 0x9b, 0xa8,
+ 0xa5, 0x9b, 0xa8, 0xa5, 0x61, 0x07, 0xaf, 0xc0, 0x56, 0x82, 0x3b, 0xdc,
+ 0x12, 0x71, 0x0d, 0xee, 0xd7, 0xe3, 0x14, 0xe4, 0x39, 0x05, 0xc4, 0xf0,
+ 0xa3, 0xc8, 0xf1, 0xd8, 0x6e, 0x4f, 0x13, 0xc7, 0x04, 0x3d, 0x87, 0x9a,
+ 0x2f, 0x5b, 0x25, 0x33, 0x5e, 0x9c, 0x1f, 0x50, 0x97, 0x02, 0xfb, 0xd6,
+ 0x5a, 0xc4, 0x71, 0x70, 0x20, 0x85, 0x08, 0xa9, 0xb2, 0x5f, 0xb0, 0x73,
+ 0x4c, 0xe7, 0x76, 0xf0, 0x10, 0xbe, 0xdb, 0x60, 0x1f, 0xc6, 0xbe, 0xb4,
+ 0x4e, 0x0b, 0x8d, 0xf0, 0x1b, 0x9a, 0xcc, 0xfd, 0xfc, 0xce, 0x31, 0xb7,
+ 0xcf, 0xf7, 0x69, 0x76, 0xb6, 0x0f, 0x71, 0x80, 0xfb, 0x15, 0xf8, 0x35,
+ 0xe8, 0xca, 0x52, 0x1b, 0x17, 0x19, 0xeb, 0x55, 0xaa, 0xcf, 0x07, 0x31,
+ 0x7c, 0xca, 0xe0, 0x38, 0x87, 0xf8, 0xbe, 0xc4, 0xdf, 0xb0, 0x10, 0xeb,
+ 0x97, 0xae, 0x68, 0x32, 0x6a, 0xc7, 0x3a, 0x7f, 0xa3, 0x1d, 0xec, 0xc3,
+ 0xf9, 0x1d, 0xfe, 0x1d, 0xed, 0x51, 0xff, 0xae, 0xcd, 0xa0, 0x23, 0xad,
+ 0x80, 0x16, 0xdb, 0xc8, 0xd0, 0xc8, 0x2c, 0xdf, 0x35, 0x51, 0x8f, 0x68,
+ 0xca, 0x54, 0x75, 0xf8, 0x7e, 0x68, 0xe3, 0xbb, 0x49, 0x76, 0x91, 0xeb,
+ 0x4f, 0x23, 0xb8, 0xff, 0x3c, 0xed, 0xbc, 0xc9, 0xf7, 0x9f, 0xe1, 0x3a,
+ 0x8d, 0xde, 0x70, 0x33, 0x34, 0x8e, 0xf8, 0x5a, 0x6c, 0x68, 0xf0, 0x6f,
+ 0xbe, 0x3c, 0x39, 0xa7, 0xad, 0xc6, 0x42, 0x99, 0x8e, 0x84, 0x32, 0xad,
+ 0x34, 0xd6, 0x80, 0xdf, 0x0d, 0xef, 0x8f, 0x43, 0x99, 0xee, 0x3a, 0x47,
+ 0xda, 0xd5, 0x1c, 0xcb, 0x95, 0x65, 0x19, 0xc8, 0x75, 0x7c, 0xb1, 0x24,
+ 0x14, 0x21, 0xd3, 0x51, 0x5f, 0xa6, 0x32, 0xc7, 0x05, 0xec, 0x95, 0x83,
+ 0xfc, 0xd9, 0x8f, 0xe1, 0xe9, 0xb0, 0x8c, 0xb9, 0xde, 0xe0, 0x58, 0x98,
+ 0xa4, 0x4b, 0x9b, 0xe4, 0x5c, 0xbc, 0xa7, 0x0e, 0xe7, 0xa9, 0xff, 0x9c,
+ 0x16, 0xde, 0x9b, 0x66, 0x21, 0xc7, 0x76, 0x2e, 0xf6, 0x23, 0x81, 0x8c,
+ 0xf6, 0x9d, 0x6e, 0xbb, 0xef, 0xe5, 0x4d, 0x7d, 0xed, 0x67, 0x9b, 0x56,
+ 0xc4, 0xb7, 0x0d, 0xde, 0xf3, 0x1d, 0xe4, 0x9d, 0x7e, 0xc9, 0x1f, 0x53,
+ 0x31, 0xd6, 0x4b, 0x85, 0x25, 0x83, 0xac, 0x16, 0xcf, 0x91, 0x49, 0x34,
+ 0xda, 0x72, 0xea, 0xa4, 0xf5, 0x30, 0xc6, 0x2d, 0x34, 0x3c, 0xef, 0xa7,
+ 0xd0, 0x9d, 0x8b, 0x5c, 0x77, 0x3b, 0xbf, 0xf1, 0xd6, 0x93, 0xc8, 0x21,
+ 0x37, 0xce, 0xfc, 0xe6, 0xfd, 0xd4, 0xa5, 0xab, 0x88, 0x09, 0x74, 0xc6,
+ 0x09, 0x51, 0x22, 0x1e, 0xe7, 0x3e, 0xfe, 0x06, 0xef, 0x79, 0x17, 0x8d,
+ 0x3b, 0x78, 0x75, 0x99, 0xc7, 0x69, 0xdf, 0x39, 0xf6, 0xff, 0x3f, 0xd0,
+ 0x2e, 0x1a, 0xd6, 0x9e, 0x38, 0xf2, 0xe7, 0xeb, 0xc4, 0xb1, 0x4f, 0x4e,
+ 0x14, 0x9b, 0xba, 0x7a, 0x09, 0x6b, 0x8b, 0x8e, 0xc2, 0xdf, 0xd6, 0xf9,
+ 0xfb, 0xa8, 0x76, 0x89, 0xda, 0xf7, 0x65, 0x90, 0xa7, 0xa3, 0xf2, 0x77,
+ 0x52, 0xb5, 0x8a, 0xd8, 0x52, 0x70, 0x92, 0x98, 0xaf, 0x62, 0x2e, 0xc7,
+ 0x05, 0x8f, 0x14, 0xd8, 0x50, 0xc1, 0x49, 0x27, 0xc6, 0x9a, 0x9e, 0xa7,
+ 0x7c, 0x5e, 0xa0, 0x87, 0x32, 0x29, 0x1a, 0x73, 0xf8, 0xfe, 0xf7, 0x9b,
+ 0xf4, 0x36, 0xec, 0xac, 0x78, 0x9e, 0x6b, 0x26, 0xf6, 0x29, 0x78, 0x77,
+ 0xf8, 0xbe, 0xea, 0x14, 0x3d, 0xb4, 0x47, 0xcf, 0x5e, 0x22, 0xe0, 0xb3,
+ 0x42, 0xfd, 0x48, 0x72, 0x53, 0xc7, 0xfd, 0xef, 0x6d, 0x8c, 0x6b, 0x9a,
+ 0x96, 0xc0, 0x1b, 0xa7, 0x99, 0xa4, 0x95, 0x66, 0x8a, 0x56, 0xa1, 0x1f,
+ 0xdb, 0xcc, 0x32, 0x7d, 0x03, 0x78, 0x2b, 0x66, 0x95, 0x94, 0x8c, 0xb5,
+ 0xaf, 0x0b, 0x78, 0x67, 0x05, 0x3d, 0x15, 0x17, 0x18, 0x77, 0x5d, 0x2d,
+ 0x03, 0x6f, 0xd6, 0xd1, 0x51, 0xa7, 0x9b, 0x8e, 0x61, 0xed, 0x7e, 0xe4,
+ 0x1f, 0xdf, 0x72, 0xa8, 0x2c, 0x99, 0x29, 0x3a, 0x80, 0xf3, 0x8e, 0x36,
+ 0x38, 0x57, 0x3b, 0x02, 0x5f, 0x23, 0xd0, 0xa3, 0x19, 0x8f, 0x1e, 0xdd,
+ 0xa3, 0x5b, 0x71, 0x01, 0x7b, 0xae, 0xb0, 0x9e, 0xa0, 0xdf, 0x09, 0xce,
+ 0x8d, 0xad, 0xf8, 0xba, 0x08, 0x7f, 0xfa, 0x0c, 0x65, 0xce, 0xad, 0xe5,
+ 0xa6, 0x90, 0x9f, 0x8f, 0x36, 0xe9, 0x8b, 0x31, 0x9c, 0xf7, 0x36, 0xf8,
+ 0x34, 0xea, 0xc8, 0x02, 0xf3, 0xe9, 0x58, 0xc0, 0x27, 0x8c, 0xf1, 0xb7,
+ 0x23, 0xce, 0xd1, 0xf8, 0xec, 0x13, 0x74, 0xb6, 0xc1, 0x77, 0xdd, 0x27,
+ 0xe8, 0x4a, 0xe3, 0x11, 0xba, 0x98, 0xe3, 0x5c, 0x07, 0xfb, 0xf8, 0x67,
+ 0xa0, 0xcf, 0x3f, 0xa3, 0x9b, 0x8e, 0xfb, 0x72, 0xfa, 0x3f, 0xc3, 0x06,
+ 0xd0, 0x70, 0x4c, 0x57, 0x00, 0x00, 0x00 };
static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 55d236726d11..8171cae06688 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1199,8 +1199,7 @@ int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev)
}
#define BOND_INTERSECT_FEATURES \
- (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM|\
- NETIF_F_TSO|NETIF_F_UFO)
+ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
/*
* Compute the common dev->feature set available to all slaves. Some
@@ -1218,9 +1217,7 @@ static int bond_compute_features(struct bonding *bond)
features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
if ((features & NETIF_F_SG) &&
- !(features & (NETIF_F_IP_CSUM |
- NETIF_F_NO_CSUM |
- NETIF_F_HW_CSUM)))
+ !(features & NETIF_F_ALL_CSUM))
features &= ~NETIF_F_SG;
/*
@@ -4191,7 +4188,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
*/
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- /* don't acquire bond device's xmit_lock when
+ /* don't acquire bond device's netif_tx_lock when
* transmitting */
bond_dev->features |= NETIF_F_LLTX;
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index ac48f7543500..39f36aa05aa8 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4877,7 +4877,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int cas_version_printed = 0;
- unsigned long casreg_base, casreg_len;
+ unsigned long casreg_len;
struct net_device *dev;
struct cas *cp;
int i, err, pci_using_dac;
@@ -4972,7 +4972,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_using_dac = 0;
}
- casreg_base = pci_resource_start(pdev, 0);
casreg_len = pci_resource_len(pdev, 0);
cp = netdev_priv(dev);
@@ -5024,7 +5023,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
cp->timer_ticks = 0;
/* give us access to cassini registers */
- cp->regs = ioremap(casreg_base, casreg_len);
+ cp->regs = pci_iomap(pdev, 0, casreg_len);
if (cp->regs == 0UL) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
@@ -5123,7 +5122,7 @@ err_out_iounmap:
cas_shutdown(cp);
mutex_unlock(&cp->pm_mutex);
- iounmap(cp->regs);
+ pci_iounmap(pdev, cp->regs);
err_out_free_res:
@@ -5171,7 +5170,7 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
#endif
pci_free_consistent(pdev, sizeof(struct cas_init_block),
cp->init_block, cp->block_dvma);
- iounmap(cp->regs);
+ pci_iounmap(pdev, cp->regs);
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 1f3627470c95..038447fb5c5e 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -53,6 +53,7 @@
#define DRV_VERSION "v1.17b"
#define DRV_RELDATE "2006/03/10"
#include "dl2k.h"
+#include <linux/dma-mapping.h>
static char version[] __devinitdata =
KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
@@ -765,7 +766,7 @@ rio_free_tx (struct net_device *dev, int irq)
break;
skb = np->tx_skbuff[entry];
pci_unmap_single (np->pdev,
- np->tx_ring[entry].fraginfo & 0xffffffffffff,
+ np->tx_ring[entry].fraginfo & DMA_48BIT_MASK,
skb->len, PCI_DMA_TODEVICE);
if (irq)
dev_kfree_skb_irq (skb);
@@ -893,7 +894,7 @@ receive_packet (struct net_device *dev)
/* Small skbuffs for short packets */
if (pkt_len > copy_thresh) {
pci_unmap_single (np->pdev,
- desc->fraginfo & 0xffffffffffff,
+ desc->fraginfo & DMA_48BIT_MASK,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
skb_put (skb = np->rx_skbuff[entry], pkt_len);
@@ -901,7 +902,7 @@ receive_packet (struct net_device *dev)
} else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
pci_dma_sync_single_for_cpu(np->pdev,
desc->fraginfo &
- 0xffffffffffff,
+ DMA_48BIT_MASK,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
skb->dev = dev;
@@ -913,7 +914,7 @@ receive_packet (struct net_device *dev)
skb_put (skb, pkt_len);
pci_dma_sync_single_for_device(np->pdev,
desc->fraginfo &
- 0xffffffffffff,
+ DMA_48BIT_MASK,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
}
@@ -1800,7 +1801,7 @@ rio_close (struct net_device *dev)
skb = np->rx_skbuff[i];
if (skb) {
pci_unmap_single(np->pdev,
- np->rx_ring[i].fraginfo & 0xffffffffffff,
+ np->rx_ring[i].fraginfo & DMA_48BIT_MASK,
skb->len, PCI_DMA_FROMDEVICE);
dev_kfree_skb (skb);
np->rx_skbuff[i] = NULL;
@@ -1810,7 +1811,7 @@ rio_close (struct net_device *dev)
skb = np->tx_skbuff[i];
if (skb) {
pci_unmap_single(np->pdev,
- np->tx_ring[i].fraginfo & 0xffffffffffff,
+ np->tx_ring[i].fraginfo & DMA_48BIT_MASK,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb (skb);
np->tx_skbuff[i] = NULL;
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 31ac001f5517..f37170cc1a37 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2780,6 +2780,80 @@ static void e100_shutdown(struct pci_dev *pdev)
DPRINTK(PROBE,ERR, "Error enabling wake\n");
}
+/* ------------------ PCI Error Recovery infrastructure -------------- */
+/**
+ * e100_io_error_detected - called when PCI error is detected.
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ */
+static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+
+ /* Similar to calling e100_down(), but avoids adpater I/O. */
+ netdev->stop(netdev);
+
+ /* Detach; put netif into state similar to hotplug unplug. */
+ netif_poll_enable(netdev);
+ netif_device_detach(netdev);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e100_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch.
+ */
+static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ /* Only one device per card can do a reset */
+ if (0 != PCI_FUNC(pdev->devfn))
+ return PCI_ERS_RESULT_RECOVERED;
+ e100_hw_reset(nic);
+ e100_phy_init(nic);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e100_io_resume - resume normal operations
+ * @pdev: Pointer to PCI device
+ *
+ * Resume normal operations after an error recovery
+ * sequence has been completed.
+ */
+static void e100_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+
+ /* ack any pending wake events, disable PME */
+ pci_enable_wake(pdev, 0, 0);
+
+ netif_device_attach(netdev);
+ if (netif_running(netdev)) {
+ e100_open(netdev);
+ mod_timer(&nic->watchdog, jiffies);
+ }
+}
+
+static struct pci_error_handlers e100_err_handler = {
+ .error_detected = e100_io_error_detected,
+ .slot_reset = e100_io_slot_reset,
+ .resume = e100_io_resume,
+};
static struct pci_driver e100_driver = {
.name = DRV_NAME,
@@ -2791,6 +2865,7 @@ static struct pci_driver e100_driver = {
.resume = e100_resume,
#endif
.shutdown = e100_shutdown,
+ .err_handler = &e100_err_handler,
};
static int __init e100_init_module(void)
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index ca9f89552da3..5dea2b7dea4d 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
#
-# Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+# Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
#
# 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
@@ -22,6 +22,7 @@
#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 281de41d030a..2bc34fbfa69c 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -114,6 +115,8 @@ struct e1000_adapter;
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
+#define E1000_RXBUFFER_512 512
+#define E1000_RXBUFFER_1024 1024
#define E1000_RXBUFFER_2048 2048
#define E1000_RXBUFFER_4096 4096
#define E1000_RXBUFFER_8192 8192
@@ -334,7 +337,6 @@ struct e1000_adapter {
boolean_t have_msi;
#endif
/* to not mess up cache alignment, always add to the bottom */
- boolean_t txb2b;
#ifdef NETIF_F_TSO
boolean_t tso_force;
#endif
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index ecccca35c6f4..6ed7f599eba3 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -864,19 +865,22 @@ static int
e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
{
struct net_device *netdev = adapter->netdev;
- uint32_t mask, i=0, shared_int = TRUE;
- uint32_t irq = adapter->pdev->irq;
+ uint32_t mask, i=0, shared_int = TRUE;
+ uint32_t irq = adapter->pdev->irq;
*data = 0;
/* Hook up test interrupt handler just for this test */
- if (!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) {
+ if (!request_irq(irq, &e1000_test_intr, SA_PROBEIRQ, netdev->name,
+ netdev)) {
shared_int = FALSE;
} else if (request_irq(irq, &e1000_test_intr, SA_SHIRQ,
netdev->name, netdev)){
*data = 1;
return -1;
}
+ DPRINTK(PROBE,INFO, "testing %s interrupt\n",
+ (shared_int ? "shared" : "unshared"));
/* Disable all the interrupts */
E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
@@ -888,22 +892,22 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
/* Interrupt to test */
mask = 1 << i;
- if (!shared_int) {
- /* Disable the interrupt to be reported in
- * the cause register and then force the same
- * interrupt and see if one gets posted. If
- * an interrupt was posted to the bus, the
- * test failed.
- */
- adapter->test_icr = 0;
- E1000_WRITE_REG(&adapter->hw, IMC, mask);
- E1000_WRITE_REG(&adapter->hw, ICS, mask);
- msec_delay(10);
-
- if (adapter->test_icr & mask) {
- *data = 3;
- break;
- }
+ if (!shared_int) {
+ /* Disable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ msec_delay(10);
+
+ if (adapter->test_icr & mask) {
+ *data = 3;
+ break;
+ }
}
/* Enable the interrupt to be reported in
@@ -922,7 +926,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
break;
}
- if (!shared_int) {
+ if (!shared_int) {
/* Disable the other interrupts to be reported in
* the cause register and then force the other
* interrupts and see if any get posted. If
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 523c2c9fc0ac..3959039b16ec 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -764,7 +765,7 @@ e1000_init_hw(struct e1000_hw *hw)
}
if (hw->mac_type == e1000_82573) {
- e1000_enable_tx_pkt_filtering(hw);
+ e1000_enable_tx_pkt_filtering(hw);
}
switch (hw->mac_type) {
@@ -860,7 +861,7 @@ e1000_adjust_serdes_amplitude(struct e1000_hw *hw)
if(eeprom_data != EEPROM_RESERVED_WORD) {
/* Adjust SERDES output amplitude only. */
- eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK;
+ eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
if(ret_val)
return ret_val;
@@ -1227,7 +1228,7 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
if (hw->phy_reset_disable)
return E1000_SUCCESS;
-
+
ret_val = e1000_phy_reset(hw);
if (ret_val) {
DEBUGOUT("Error Resetting the PHY\n");
@@ -1369,7 +1370,7 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
DEBUGFUNC("e1000_copper_link_ggp_setup");
if(!hw->phy_reset_disable) {
-
+
/* Enable CRS on TX for half-duplex operation. */
ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
&phy_data);
@@ -1518,7 +1519,7 @@ e1000_copper_link_mgp_setup(struct e1000_hw *hw)
if(hw->phy_reset_disable)
return E1000_SUCCESS;
-
+
/* Enable CRS on TX. This must be set for half-duplex operation. */
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if(ret_val)
@@ -1664,7 +1665,7 @@ e1000_copper_link_autoneg(struct e1000_hw *hw)
* collision distance in the Transmit Control Register.
* 2) Set up flow control on the MAC to that established with
* the link partner.
-* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
+* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
@@ -1673,7 +1674,7 @@ e1000_copper_link_postconfig(struct e1000_hw *hw)
{
int32_t ret_val;
DEBUGFUNC("e1000_copper_link_postconfig");
-
+
if(hw->mac_type >= e1000_82544) {
e1000_config_collision_dist(hw);
} else {
@@ -1697,7 +1698,7 @@ e1000_copper_link_postconfig(struct e1000_hw *hw)
return ret_val;
}
}
-
+
return E1000_SUCCESS;
}
@@ -1753,11 +1754,11 @@ e1000_setup_copper_link(struct e1000_hw *hw)
}
if(hw->autoneg) {
- /* Setup autoneg and flow control advertisement
- * and perform autonegotiation */
+ /* Setup autoneg and flow control advertisement
+ * and perform autonegotiation */
ret_val = e1000_copper_link_autoneg(hw);
if(ret_val)
- return ret_val;
+ return ret_val;
} else {
/* PHY will be set to 10H, 10F, 100H,or 100F
* depending on value from forced_speed_duplex. */
@@ -1785,7 +1786,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
ret_val = e1000_copper_link_postconfig(hw);
if(ret_val)
return ret_val;
-
+
DEBUGOUT("Valid link established!!!\n");
return E1000_SUCCESS;
}
@@ -1983,7 +1984,7 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
if(ret_val)
return ret_val;
@@ -2272,7 +2273,7 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
DEBUGFUNC("e1000_config_mac_to_phy");
- /* 82544 or newer MAC, Auto Speed Detection takes care of
+ /* 82544 or newer MAC, Auto Speed Detection takes care of
* MAC speed/duplex configuration.*/
if (hw->mac_type >= e1000_82544)
return E1000_SUCCESS;
@@ -2291,9 +2292,9 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
if(ret_val)
return ret_val;
- if(phy_data & M88E1000_PSSR_DPLX)
+ if(phy_data & M88E1000_PSSR_DPLX)
ctrl |= E1000_CTRL_FD;
- else
+ else
ctrl &= ~E1000_CTRL_FD;
e1000_config_collision_dist(hw);
@@ -2492,10 +2493,10 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
*/
if(hw->original_fc == e1000_fc_full) {
hw->fc = e1000_fc_full;
- DEBUGOUT("Flow Control = FULL.\r\n");
+ DEBUGOUT("Flow Control = FULL.\n");
} else {
hw->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
}
/* For receiving PAUSE frames ONLY.
@@ -2511,7 +2512,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc = e1000_fc_tx_pause;
- DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+ DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
}
/* For transmitting PAUSE frames ONLY.
*
@@ -2526,7 +2527,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
/* Per the IEEE spec, at this point flow control should be
* disabled. However, we want to consider that we could
@@ -2552,10 +2553,10 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
hw->original_fc == e1000_fc_tx_pause) ||
hw->fc_strict_ieee) {
hw->fc = e1000_fc_none;
- DEBUGOUT("Flow Control = NONE.\r\n");
+ DEBUGOUT("Flow Control = NONE.\n");
} else {
hw->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
/* Now we need to do one last check... If we auto-
@@ -2580,7 +2581,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
return ret_val;
}
} else {
- DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+ DEBUGOUT("Copper PHY and Auto Neg has not completed.\n");
}
}
return E1000_SUCCESS;
@@ -2763,7 +2764,7 @@ e1000_check_for_link(struct e1000_hw *hw)
hw->autoneg_failed = 1;
return 0;
}
- DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
/* Disable auto-negotiation in the TXCW register */
E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
@@ -2788,7 +2789,7 @@ e1000_check_for_link(struct e1000_hw *hw)
else if(((hw->media_type == e1000_media_type_fiber) ||
(hw->media_type == e1000_media_type_internal_serdes)) &&
(ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
- DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
E1000_WRITE_REG(hw, TXCW, hw->txcw);
E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -2851,13 +2852,13 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
if(status & E1000_STATUS_FD) {
*duplex = FULL_DUPLEX;
- DEBUGOUT("Full Duplex\r\n");
+ DEBUGOUT("Full Duplex\n");
} else {
*duplex = HALF_DUPLEX;
- DEBUGOUT(" Half Duplex\r\n");
+ DEBUGOUT(" Half Duplex\n");
}
} else {
- DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+ DEBUGOUT("1000 Mbs, Full Duplex\n");
*speed = SPEED_1000;
*duplex = FULL_DUPLEX;
}
@@ -2883,7 +2884,7 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
}
}
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan) &&
(hw->media_type == e1000_media_type_copper)) {
if (*speed == SPEED_1000)
ret_val = e1000_configure_kmrn_for_1000(hw);
@@ -3159,7 +3160,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if((hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3298,7 +3299,7 @@ e1000_write_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if((hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3496,22 +3497,22 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
}
/* Read the device control register and assert the E1000_CTRL_PHY_RST
* bit. Then, take it out of reset.
- * For pre-e1000_82571 hardware, we delay for 10ms between the assert
+ * For pre-e1000_82571 hardware, we delay for 10ms between the assert
* and deassert. For e1000_82571 hardware and later, we instead delay
* for 50us between and 10ms after the deassertion.
*/
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
E1000_WRITE_FLUSH(hw);
-
- if (hw->mac_type < e1000_82571)
+
+ if (hw->mac_type < e1000_82571)
msec_delay(10);
else
udelay(100);
-
+
E1000_WRITE_REG(hw, CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
-
+
if (hw->mac_type >= e1000_82571)
msec_delay(10);
e1000_swfw_sync_release(hw, swfw);
@@ -3815,7 +3816,7 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
/* Check polarity status */
ret_val = e1000_check_polarity(hw, &polarity);
if(ret_val)
- return ret_val;
+ return ret_val;
phy_info->cable_polarity = polarity;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
@@ -4540,14 +4541,14 @@ e1000_read_eeprom_eerd(struct e1000_hw *hw,
E1000_WRITE_REG(hw, EERD, eerd);
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
-
+
if(error) {
break;
}
data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
-
+
}
-
+
return error;
}
@@ -4573,24 +4574,24 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw,
return -E1000_ERR_SWFW_SYNC;
for (i = 0; i < words; i++) {
- register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) |
- ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) |
+ register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) |
+ ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) |
E1000_EEPROM_RW_REG_START;
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
if(error) {
break;
- }
+ }
E1000_WRITE_REG(hw, EEWR, register_value);
-
+
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
-
+
if(error) {
break;
- }
+ }
}
-
+
e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM);
return error;
}
@@ -4610,7 +4611,7 @@ e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
for(i = 0; i < attempts; i++) {
if(eerd == E1000_EEPROM_POLL_READ)
reg = E1000_READ_REG(hw, EERD);
- else
+ else
reg = E1000_READ_REG(hw, EEWR);
if(reg & E1000_EEPROM_RW_REG_DONE) {
@@ -5135,7 +5136,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
uint32_t i;
uint32_t num_rar_entry;
uint32_t num_mta_entry;
-
+
DEBUGFUNC("e1000_mc_addr_list_update");
/* Set the new number of MC addresses that we are being requested to use. */
@@ -6240,7 +6241,7 @@ e1000_check_polarity(struct e1000_hw *hw,
* 1 - Downshift ocured.
*
* returns: - E1000_ERR_XXX
- * E1000_SUCCESS
+ * E1000_SUCCESS
*
* For phy's older then IGP, this function reads the Downshift bit in the Phy
* Specific Status register. For IGP phy's, it reads the Downgrade bit in the
@@ -6255,7 +6256,7 @@ e1000_check_downshift(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_downshift");
- if(hw->phy_type == e1000_phy_igp ||
+ if(hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
&phy_data);
@@ -6684,8 +6685,8 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
} else {
-
- phy_data |= IGP02E1000_PM_D0_LPLU;
+
+ phy_data |= IGP02E1000_PM_D0_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
if (ret_val)
return ret_val;
@@ -6777,7 +6778,7 @@ int32_t
e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
{
uint8_t i;
- uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET;
+ uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET;
uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
length = (length >> 2);
@@ -6796,7 +6797,7 @@ e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
* and also checks whether the previous command is completed.
* It busy waits in case of previous command is not completed.
*
- * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or
* timeout
* - E1000_SUCCESS for success.
****************************************************************************/
@@ -6820,7 +6821,7 @@ e1000_mng_enable_host_if(struct e1000_hw * hw)
msec_delay_irq(1);
}
- if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
DEBUGOUT("Previous command timeout failed .\n");
return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 150e45e30f87..467c9ed944f8 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -374,7 +375,7 @@ struct e1000_host_mng_dhcp_cookie{
};
#endif
-int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer,
+int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer,
uint16_t length);
boolean_t e1000_check_mng_mode(struct e1000_hw *hw);
boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
@@ -1801,7 +1802,7 @@ struct e1000_hw {
* value2 = [0..64512], default=4096
* value3 = [0..64512], default=0
*/
-
+
#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index add8dc4aa7b0..a373ccb308d8 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,51 +22,13 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include "e1000.h"
-/* Change Log
- * 7.0.33 3-Feb-2006
- * o Added another fix for the pass false carrier bit
- * 7.0.32 24-Jan-2006
- * o Need to rebuild with noew version number for the pass false carrier
- * fix in e1000_hw.c
- * 7.0.30 18-Jan-2006
- * o fixup for tso workaround to disable it for pci-x
- * o fix mem leak on 82542
- * o fixes for 10 Mb/s connections and incorrect stats
- * 7.0.28 01/06/2006
- * o hardware workaround to only set "speed mode" bit for 1G link.
- * 7.0.26 12/23/2005
- * o wake on lan support modified for device ID 10B5
- * o fix dhcp + vlan issue not making it to the iAMT firmware
- * 7.0.24 12/9/2005
- * o New hardware support for the Gigabit NIC embedded in the south bridge
- * o Fixes to the recycling logic (skb->tail) from IBM LTC
- * 6.3.9 12/16/2005
- * o incorporate fix for recycled skbs from IBM LTC
- * 6.3.7 11/18/2005
- * o Honor eeprom setting for enabling/disabling Wake On Lan
- * 6.3.5 11/17/2005
- * o Fix memory leak in rx ring handling for PCI Express adapters
- * 6.3.4 11/8/05
- * o Patch from Jesper Juhl to remove redundant NULL checks for kfree
- * 6.3.2 9/20/05
- * o Render logic that sets/resets DRV_LOAD as inline functions to
- * avoid code replication. If f/w is AMT then set DRV_LOAD only when
- * network interface is open.
- * o Handle DRV_LOAD set/reset in cases where AMT uses VLANs.
- * o Adjust PBA partioning for Jumbo frames using MTU size and not
- * rx_buffer_len
- * 6.3.1 9/19/05
- * o Use adapter->tx_timeout_factor in Tx Hung Detect logic
- * (e1000_clean_tx_irq)
- * o Support for 8086:10B5 device (Quad Port)
- */
-
char e1000_driver_name[] = "e1000";
static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#ifndef CONFIG_E1000_NAPI
@@ -74,9 +36,9 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.0.33-k2"DRIVERNAPI
+#define DRV_VERSION "7.0.38-k4"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
-static char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
+static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -208,8 +170,8 @@ static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static void e1000_tx_timeout(struct net_device *dev);
static void e1000_reset_task(struct net_device *dev);
static void e1000_smartspeed(struct e1000_adapter *adapter);
-static inline int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
- struct sk_buff *skb);
+static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
+ struct sk_buff *skb);
static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
@@ -220,12 +182,23 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter);
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
static int e1000_resume(struct pci_dev *pdev);
#endif
+static void e1000_shutdown(struct pci_dev *pdev);
#ifdef CONFIG_NET_POLL_CONTROLLER
/* for netdump / net console */
static void e1000_netpoll (struct net_device *netdev);
#endif
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
+static void e1000_io_resume(struct pci_dev *pdev);
+
+static struct pci_error_handlers e1000_err_handler = {
+ .error_detected = e1000_io_error_detected,
+ .slot_reset = e1000_io_slot_reset,
+ .resume = e1000_io_resume,
+};
static struct pci_driver e1000_driver = {
.name = e1000_driver_name,
@@ -235,8 +208,10 @@ static struct pci_driver e1000_driver = {
/* Power Managment Hooks */
#ifdef CONFIG_PM
.suspend = e1000_suspend,
- .resume = e1000_resume
+ .resume = e1000_resume,
#endif
+ .shutdown = e1000_shutdown,
+ .err_handler = &e1000_err_handler
};
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -291,7 +266,7 @@ module_exit(e1000_exit_module);
* @adapter: board private structure
**/
-static inline void
+static void
e1000_irq_disable(struct e1000_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
@@ -305,7 +280,7 @@ e1000_irq_disable(struct e1000_adapter *adapter)
* @adapter: board private structure
**/
-static inline void
+static void
e1000_irq_enable(struct e1000_adapter *adapter)
{
if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
@@ -346,10 +321,10 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter)
* For ASF and Pass Through versions of f/w this means that the
* driver is no longer loaded. For AMT version (only with 82573) i
* of the f/w this means that the netowrk i/f is closed.
- *
+ *
**/
-static inline void
+static void
e1000_release_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
@@ -359,6 +334,7 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
switch (adapter->hw.mac_type) {
case e1000_82571:
case e1000_82572:
+ case e1000_80003es2lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
@@ -377,13 +353,13 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
* @adapter: address of board private structure
*
* e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that
- * the driver is loaded. For AMT version (only with 82573)
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
* of the f/w this means that the netowrk i/f is open.
- *
+ *
**/
-static inline void
+static void
e1000_get_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
@@ -392,6 +368,7 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
switch (adapter->hw.mac_type) {
case e1000_82571:
case e1000_82572:
+ case e1000_80003es2lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
@@ -419,7 +396,7 @@ e1000_up(struct e1000_adapter *adapter)
uint16_t mii_reg;
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
if (mii_reg & MII_CR_POWER_DOWN)
- e1000_phy_reset(&adapter->hw);
+ e1000_phy_hw_reset(&adapter->hw);
}
e1000_set_multi(netdev);
@@ -709,8 +686,8 @@ e1000_probe(struct pci_dev *pdev,
DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
/* if ksp3, indicate if it's port a being setup */
- if (pdev->device == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 &&
- e1000_ksp3_port_a == 0)
+ if (pdev->device == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 &&
+ e1000_ksp3_port_a == 0)
adapter->ksp3_port_a = 1;
e1000_ksp3_port_a++;
/* Reset for multiple KP3 adapters */
@@ -738,9 +715,9 @@ e1000_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- /* hard_start_xmit is safe against parallel locking */
- netdev->features |= NETIF_F_LLTX;
-
+ /* hard_start_xmit is safe against parallel locking */
+ netdev->features |= NETIF_F_LLTX;
+
adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
/* before reading the EEPROM, reset the controller to
@@ -970,8 +947,8 @@ e1000_sw_init(struct e1000_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
- adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- adapter->rx_ps_bsize0 = E1000_RXBUFFER_256;
+ adapter->rx_buffer_len = MAXIMUM_ETHERNET_FRAME_SIZE;
+ adapter->rx_ps_bsize0 = E1000_RXBUFFER_128;
hw->max_frame_size = netdev->mtu +
ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
@@ -1179,7 +1156,7 @@ e1000_close(struct net_device *netdev)
* @start: address of beginning of memory
* @len: length of memory
**/
-static inline boolean_t
+static boolean_t
e1000_check_64k_bound(struct e1000_adapter *adapter,
void *start, unsigned long len)
{
@@ -1597,14 +1574,21 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rctl |= E1000_RCTL_LPE;
/* Setup buffer sizes */
- if (adapter->hw.mac_type >= e1000_82571) {
- /* We can now specify buffers in 1K increments.
- * BSIZE and BSEX are ignored in this case. */
- rctl |= adapter->rx_buffer_len << 0x11;
- } else {
- rctl &= ~E1000_RCTL_SZ_4096;
- rctl |= E1000_RCTL_BSEX;
- switch (adapter->rx_buffer_len) {
+ rctl &= ~E1000_RCTL_SZ_4096;
+ rctl |= E1000_RCTL_BSEX;
+ switch (adapter->rx_buffer_len) {
+ case E1000_RXBUFFER_256:
+ rctl |= E1000_RCTL_SZ_256;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case E1000_RXBUFFER_512:
+ rctl |= E1000_RCTL_SZ_512;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case E1000_RXBUFFER_1024:
+ rctl |= E1000_RCTL_SZ_1024;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
case E1000_RXBUFFER_2048:
default:
rctl |= E1000_RCTL_SZ_2048;
@@ -1619,7 +1603,6 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
case E1000_RXBUFFER_16384:
rctl |= E1000_RCTL_SZ_16384;
break;
- }
}
#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
@@ -1713,7 +1696,7 @@ e1000_configure_rx(struct e1000_adapter *adapter)
if (hw->mac_type >= e1000_82571) {
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
/* Reset delay timers after every interrupt */
- ctrl_ext |= E1000_CTRL_EXT_CANC;
+ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
#ifdef CONFIG_E1000_NAPI
/* Auto-Mask interrupts upon ICR read. */
ctrl_ext |= E1000_CTRL_EXT_IAME;
@@ -1805,7 +1788,7 @@ e1000_free_all_tx_resources(struct e1000_adapter *adapter)
e1000_free_tx_resources(adapter, &adapter->tx_ring[i]);
}
-static inline void
+static void
e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info)
{
@@ -2245,6 +2228,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
if (link) {
if (!netif_carrier_ok(netdev)) {
+ boolean_t txb2b = 1;
e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -2258,23 +2242,22 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
* and adjust the timeout factor */
netdev->tx_queue_len = adapter->tx_queue_len;
adapter->tx_timeout_factor = 1;
- adapter->txb2b = 1;
switch (adapter->link_speed) {
case SPEED_10:
- adapter->txb2b = 0;
+ txb2b = 0;
netdev->tx_queue_len = 10;
adapter->tx_timeout_factor = 8;
break;
case SPEED_100:
- adapter->txb2b = 0;
+ txb2b = 0;
netdev->tx_queue_len = 100;
/* maybe add some timeout factor ? */
break;
}
- if ((adapter->hw.mac_type == e1000_82571 ||
+ if ((adapter->hw.mac_type == e1000_82571 ||
adapter->hw.mac_type == e1000_82572) &&
- adapter->txb2b == 0) {
+ txb2b == 0) {
#define SPEED_MODE_BIT (1 << 21)
uint32_t tarc0;
tarc0 = E1000_READ_REG(&adapter->hw, TARC0);
@@ -2398,7 +2381,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
#define E1000_TX_FLAGS_VLAN_SHIFT 16
-static inline int
+static int
e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb)
{
@@ -2420,7 +2403,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
mss = skb_shinfo(skb)->tso_size;
- if (skb->protocol == ntohs(ETH_P_IP)) {
+ if (skb->protocol == htons(ETH_P_IP)) {
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
skb->h.th->check =
@@ -2478,7 +2461,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
return FALSE;
}
-static inline boolean_t
+static boolean_t
e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb)
{
@@ -2514,7 +2497,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
#define E1000_MAX_TXD_PWR 12
#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
-static inline int
+static int
e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb, unsigned int first, unsigned int max_per_txd,
unsigned int nr_frags, unsigned int mss)
@@ -2623,7 +2606,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
return count;
}
-static inline void
+static void
e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
int tx_flags, int count)
{
@@ -2687,7 +2670,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
#define E1000_FIFO_HDR 0x10
#define E1000_82547_PAD_LEN 0x3E0
-static inline int
+static int
e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
{
uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
@@ -2714,7 +2697,7 @@ no_fifo_stall_required:
}
#define MINIMUM_DHCP_PACKET_SIZE 282
-static inline int
+static int
e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
{
struct e1000_hw *hw = &adapter->hw;
@@ -2762,7 +2745,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int nr_frags = 0;
unsigned int mss = 0;
int count = 0;
- int tso;
+ int tso;
unsigned int f;
len -= skb->data_len;
@@ -2775,7 +2758,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->tso_size;
- /* The controller does a simple calculation to
+ /* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
* initiating the DMA for each buffer. The calc is:
* 4 = ceil(buffer len/mss). To make sure we don't
@@ -2798,7 +2781,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
case e1000_82573:
pull_size = min((unsigned int)4, skb->data_len);
if (!__pskb_pull_tail(skb, pull_size)) {
- printk(KERN_ERR
+ printk(KERN_ERR
"__pskb_pull_tail failed.\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2899,7 +2882,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* Old method was to assume IPv4 packet by default if TSO was enabled.
* 82571 hardware supports TSO capabilities for IPv6 as well...
* no longer assume, we must. */
- if (likely(skb->protocol == ntohs(ETH_P_IP)))
+ if (likely(skb->protocol == htons(ETH_P_IP)))
tx_flags |= E1000_TX_FLAGS_IPV4;
e1000_tx_queue(adapter, tx_ring, tx_flags,
@@ -2980,8 +2963,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* Adapter-specific max frame size limits. */
switch (adapter->hw.mac_type) {
- case e1000_82542_rev2_0:
- case e1000_82542_rev2_1:
+ case e1000_undefined ... e1000_82542_rev2_1:
if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
@@ -3015,27 +2997,32 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
break;
}
-
- if (adapter->hw.mac_type > e1000_82547_rev_2) {
- adapter->rx_buffer_len = max_frame;
- E1000_ROUNDUP(adapter->rx_buffer_len, 1024);
- } else {
- if(unlikely((adapter->hw.mac_type < e1000_82543) &&
- (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE))) {
- DPRINTK(PROBE, ERR, "Jumbo Frames not supported "
- "on 82542\n");
- return -EINVAL;
- } else {
- if(max_frame <= E1000_RXBUFFER_2048)
- adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- else if(max_frame <= E1000_RXBUFFER_4096)
- adapter->rx_buffer_len = E1000_RXBUFFER_4096;
- else if(max_frame <= E1000_RXBUFFER_8192)
- adapter->rx_buffer_len = E1000_RXBUFFER_8192;
- else if(max_frame <= E1000_RXBUFFER_16384)
- adapter->rx_buffer_len = E1000_RXBUFFER_16384;
- }
- }
+ /* NOTE: dev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+ * means we reserve 2 more, this pushes us to allocate from the next
+ * larger slab size
+ * i.e. RXBUFFER_2048 --> size-4096 slab */
+
+ if (max_frame <= E1000_RXBUFFER_256)
+ adapter->rx_buffer_len = E1000_RXBUFFER_256;
+ else if (max_frame <= E1000_RXBUFFER_512)
+ adapter->rx_buffer_len = E1000_RXBUFFER_512;
+ else if (max_frame <= E1000_RXBUFFER_1024)
+ adapter->rx_buffer_len = E1000_RXBUFFER_1024;
+ else if (max_frame <= E1000_RXBUFFER_2048)
+ adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+ else if (max_frame <= E1000_RXBUFFER_4096)
+ adapter->rx_buffer_len = E1000_RXBUFFER_4096;
+ else if (max_frame <= E1000_RXBUFFER_8192)
+ adapter->rx_buffer_len = E1000_RXBUFFER_8192;
+ else if (max_frame <= E1000_RXBUFFER_16384)
+ adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+
+ /* adjust allocation if LPE protects us, and we aren't using SBP */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+ if (!adapter->hw.tbi_compatibility_on &&
+ ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
+ adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
netdev->mtu = new_mtu;
@@ -3058,11 +3045,21 @@ void
e1000_update_stats(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
unsigned long flags;
uint16_t phy_tmp;
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+ /*
+ * Prevent stats update while adapter is being reset, or if the pci
+ * connection is down.
+ */
+ if (adapter->link_speed == 0)
+ return;
+ if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ return;
+
spin_lock_irqsave(&adapter->stats_lock, flags);
/* these counters are modified from e1000_adjust_tbi_stats,
@@ -3163,7 +3160,6 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
adapter->stats.cexterr;
- adapter->net_stats.rx_dropped = 0;
adapter->net_stats.rx_length_errors = adapter->stats.ruc +
adapter->stats.roc;
adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
@@ -3389,13 +3385,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
tx_ring->next_to_clean = i;
- spin_lock(&tx_ring->tx_lock);
-
+#define TX_WAKE_THRESHOLD 32
if (unlikely(cleaned && netif_queue_stopped(netdev) &&
- netif_carrier_ok(netdev)))
- netif_wake_queue(netdev);
-
- spin_unlock(&tx_ring->tx_lock);
+ netif_carrier_ok(netdev))) {
+ spin_lock(&tx_ring->tx_lock);
+ if (netif_queue_stopped(netdev) &&
+ (E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))
+ netif_wake_queue(netdev);
+ spin_unlock(&tx_ring->tx_lock);
+ }
if (adapter->detect_tx_hung) {
/* Detect a transmit hang in hardware, this serializes the
@@ -3443,7 +3441,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
* @sk_buff: socket buffer with received data
**/
-static inline void
+static void
e1000_rx_checksum(struct e1000_adapter *adapter,
uint32_t status_err, uint32_t csum,
struct sk_buff *skb)
@@ -3517,7 +3515,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
buffer_info = &rx_ring->buffer_info[i];
while (rx_desc->status & E1000_RXD_STAT_DD) {
- struct sk_buff *skb, *next_skb;
+ struct sk_buff *skb;
u8 status;
#ifdef CONFIG_E1000_NAPI
if (*work_done >= work_to_do)
@@ -3535,8 +3533,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
prefetch(next_rxd);
next_buffer = &rx_ring->buffer_info[i];
- next_skb = next_buffer->skb;
- prefetch(next_skb->data - NET_IP_ALIGN);
cleaned = TRUE;
cleaned_count++;
@@ -3567,7 +3563,8 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
flags);
length--;
} else {
- dev_kfree_skb_irq(skb);
+ /* recycle */
+ buffer_info->skb = skb;
goto next_desc;
}
}
@@ -3666,7 +3663,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info, *next_buffer;
struct e1000_ps_page *ps_page;
struct e1000_ps_page_dma *ps_page_dma;
- struct sk_buff *skb, *next_skb;
+ struct sk_buff *skb;
unsigned int i, j;
uint32_t length, staterr;
int cleaned_count = 0;
@@ -3675,6 +3672,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+ buffer_info = &rx_ring->buffer_info[i];
while (staterr & E1000_RXD_STAT_DD) {
buffer_info = &rx_ring->buffer_info[i];
@@ -3695,8 +3693,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
prefetch(next_rxd);
next_buffer = &rx_ring->buffer_info[i];
- next_skb = next_buffer->skb;
- prefetch(next_skb->data - NET_IP_ALIGN);
cleaned = TRUE;
cleaned_count++;
@@ -3735,9 +3731,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
/* page alloc/put takes too long and effects small packet
* throughput, so unsplit small packets and save the alloc/put*/
- if (l1 && ((length + l1) < E1000_CB_LENGTH)) {
+ if (l1 && ((length + l1) <= adapter->rx_ps_bsize0)) {
u8 *vaddr;
- /* there is no documentation about how to call
+ /* there is no documentation about how to call
* kmap_atomic, so we can't hold the mapping
* very long */
pci_dma_sync_single_for_cpu(pdev,
@@ -3768,6 +3764,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
ps_page->ps_page[j] = NULL;
skb->len += length;
skb->data_len += length;
+ skb->truesize += length;
}
copydone:
@@ -4156,7 +4153,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
}
- if (adapter->hw.phy_type == e1000_media_type_copper) {
+ if (adapter->hw.media_type == e1000_media_type_copper) {
switch (data->reg_num) {
case PHY_CTRL:
if (mii_reg & MII_CR_POWER_DOWN)
@@ -4515,21 +4512,13 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
E1000_WRITE_REG(&adapter->hw, WUFC, wufc);
- retval = pci_enable_wake(pdev, PCI_D3hot, 1);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 wake\n");
- retval = pci_enable_wake(pdev, PCI_D3cold, 1);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n");
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
} else {
E1000_WRITE_REG(&adapter->hw, WUC, 0);
E1000_WRITE_REG(&adapter->hw, WUFC, 0);
- retval = pci_enable_wake(pdev, PCI_D3hot, 0);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 wake\n");
- retval = pci_enable_wake(pdev, PCI_D3cold, 0);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n");
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
}
if (adapter->hw.mac_type >= e1000_82540 &&
@@ -4538,13 +4527,8 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
if (manc & E1000_MANC_SMBUS_EN) {
manc |= E1000_MANC_ARP_EN;
E1000_WRITE_REG(&adapter->hw, MANC, manc);
- retval = pci_enable_wake(pdev, PCI_D3hot, 1);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 wake\n");
- retval = pci_enable_wake(pdev, PCI_D3cold, 1);
- if (retval)
- DPRINTK(PROBE, ERR,
- "Error enabling D3 cold wake\n");
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
}
}
@@ -4554,9 +4538,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_disable_device(pdev);
- retval = pci_set_power_state(pdev, pci_choose_state(pdev, state));
- if (retval)
- DPRINTK(PROBE, ERR, "Error in setting power state\n");
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
@@ -4567,22 +4549,15 @@ e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- int retval;
uint32_t manc, ret_val;
- retval = pci_set_power_state(pdev, PCI_D0);
- if (retval)
- DPRINTK(PROBE, ERR, "Error in setting power state\n");
+ pci_set_power_state(pdev, PCI_D0);
e1000_pci_restore_state(adapter);
ret_val = pci_enable_device(pdev);
pci_set_master(pdev);
- retval = pci_enable_wake(pdev, PCI_D3hot, 0);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 wake\n");
- retval = pci_enable_wake(pdev, PCI_D3cold, 0);
- if (retval)
- DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n");
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
e1000_reset(adapter);
E1000_WRITE_REG(&adapter->hw, WUS, ~0);
@@ -4610,6 +4585,12 @@ e1000_resume(struct pci_dev *pdev)
return 0;
}
#endif
+
+static void e1000_shutdown(struct pci_dev *pdev)
+{
+ e1000_suspend(pdev, PMSG_SUSPEND);
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
@@ -4630,4 +4611,101 @@ e1000_netpoll(struct net_device *netdev)
}
#endif
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev->priv;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ e1000_down(adapter);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev->priv;
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "e1000: Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, 3, 0);
+ pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+
+ /* Perform card reset only on one instance of the card */
+ if (PCI_FUNC (pdev->devfn) != 0)
+ return PCI_ERS_RESULT_RECOVERED;
+
+ e1000_reset(adapter);
+ E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t manc, swsm;
+
+ if (netif_running(netdev)) {
+ if (e1000_up(adapter)) {
+ printk("e1000: can't bring device back up after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+
+ if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.media_type == e1000_media_type_copper) {
+ manc = E1000_READ_REG(&adapter->hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
+ }
+
+ switch (adapter->hw.mac_type) {
+ case e1000_82573:
+ swsm = E1000_READ_REG(&adapter->hw, SWSM);
+ E1000_WRITE_REG(&adapter->hw, SWSM,
+ swsm | E1000_SWSM_DRV_LOAD);
+ break;
+ default:
+ break;
+ }
+
+ if (netif_running(netdev))
+ mod_timer(&adapter->watchdog_timer, jiffies);
+}
+
/* e1000_main.c */
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 9790db974dc1..048d052be29d 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index e0a4d37d1b85..e55f8969a0fb 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -22,6 +22,7 @@
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 2f7b86837fe8..8d680ce600d7 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -21,15 +21,15 @@
http://www.scyld.com/network/epic100.html
---------------------------------------------------------------------
-
+
Linux kernel-specific changes:
-
+
LK1.1.2 (jgarzik):
* Merge becker version 1.09 (4/08/2000)
LK1.1.3:
* Major bugfix to 1.09 driver (Francis Romieu)
-
+
LK1.1.4 (jgarzik):
* Merge becker test version 1.09 (5/29/2000)
@@ -66,7 +66,7 @@
LK1.1.14 (Kryzsztof Halasa):
* fix spurious bad initializations
* pound phy a la SMSC's app note on the subject
-
+
AC1.1.14ac
* fix power up/down for ethtool that broke in 1.11
@@ -244,7 +244,7 @@ static struct pci_device_id epic_pci_tbl[] = {
};
MODULE_DEVICE_TABLE (pci, epic_pci_tbl);
-
+
#ifndef USE_IO_OPS
#undef inb
#undef inw
@@ -370,7 +370,7 @@ static int epic_close(struct net_device *dev);
static struct net_device_stats *epic_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-
+
static int __devinit epic_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -392,9 +392,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
version, version2, version3);
#endif
-
+
card_idx++;
-
+
ret = pci_enable_device(pdev);
if (ret)
goto out;
@@ -405,7 +405,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ret = -ENODEV;
goto err_out_disable;
}
-
+
pci_set_master(pdev);
ret = pci_request_regions(pdev, DRV_NAME);
@@ -498,7 +498,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ep->pci_dev = pdev;
ep->chip_id = chip_idx;
ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
- ep->irq_mask =
+ ep->irq_mask =
(ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | EpicNapiEvent;
@@ -587,7 +587,7 @@ err_out_disable:
pci_disable_device(pdev);
goto out;
}
-
+
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
@@ -709,7 +709,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
outw(value, ioaddr + MIIData);
outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl);
- for (i = 10000; i > 0; i--) {
+ for (i = 10000; i > 0; i--) {
barrier();
if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
break;
@@ -717,7 +717,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
return;
}
-
+
static int epic_open(struct net_device *dev)
{
struct epic_private *ep = dev->priv;
@@ -760,7 +760,7 @@ static int epic_open(struct net_device *dev)
#endif
udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */
-
+
for (i = 0; i < 3; i++)
outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
@@ -803,7 +803,7 @@ static int epic_open(struct net_device *dev)
/* Enable interrupts by setting the interrupt mask. */
outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
- | CntFull | TxUnderrun
+ | CntFull | TxUnderrun
| RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
if (debug > 1)
@@ -831,7 +831,7 @@ static void epic_pause(struct net_device *dev)
struct epic_private *ep = dev->priv;
netif_stop_queue (dev);
-
+
/* Disable interrupts by clearing the interrupt mask. */
outl(0x00000000, ioaddr + INTMASK);
/* Stop the chip's Tx and Rx DMA processes. */
@@ -987,7 +987,7 @@ static void epic_init_ring(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
ep->rx_ring[i].rxstatus = 0;
ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz);
- ep->rx_ring[i].next = ep->rx_ring_dma +
+ ep->rx_ring[i].next = ep->rx_ring_dma +
(i+1)*sizeof(struct epic_rx_desc);
ep->rx_skbuff[i] = NULL;
}
@@ -1002,7 +1002,7 @@ static void epic_init_ring(struct net_device *dev)
break;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
- ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
+ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
}
@@ -1013,7 +1013,7 @@ static void epic_init_ring(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
ep->tx_skbuff[i] = NULL;
ep->tx_ring[i].txstatus = 0x0000;
- ep->tx_ring[i].next = ep->tx_ring_dma +
+ ep->tx_ring[i].next = ep->tx_ring_dma +
(i+1)*sizeof(struct epic_tx_desc);
}
ep->tx_ring[i-1].next = ep->tx_ring_dma;
@@ -1026,7 +1026,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
int entry, free_count;
u32 ctrl_word;
unsigned long flags;
-
+
if (skb->len < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL)
@@ -1042,7 +1042,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = ep->cur_tx % TX_RING_SIZE;
ep->tx_skbuff[entry] = skb;
- ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data,
+ ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data,
skb->len, PCI_DMA_TODEVICE);
if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
ctrl_word = cpu_to_le32(0x100000); /* No interrupt */
@@ -1126,7 +1126,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep)
/* Free the original skb. */
skb = ep->tx_skbuff[entry];
- pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
+ pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
ep->tx_skbuff[entry] = NULL;
@@ -1281,8 +1281,8 @@ static int epic_rx(struct net_device *dev, int budget)
ep->rx_buf_sz,
PCI_DMA_FROMDEVICE);
} else {
- pci_unmap_single(ep->pci_dev,
- ep->rx_ring[entry].bufaddr,
+ pci_unmap_single(ep->pci_dev,
+ ep->rx_ring[entry].bufaddr,
ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb_put(skb = ep->rx_skbuff[entry], pkt_len);
ep->rx_skbuff[entry] = NULL;
@@ -1307,7 +1307,7 @@ static int epic_rx(struct net_device *dev, int budget)
break;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
+ ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
work_done++;
}
@@ -1403,7 +1403,7 @@ static int epic_close(struct net_device *dev)
ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */
ep->rx_ring[i].buflength = 0;
if (skb) {
- pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr,
+ pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr,
ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
}
@@ -1414,7 +1414,7 @@ static int epic_close(struct net_device *dev)
ep->tx_skbuff[i] = NULL;
if (!skb)
continue;
- pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr,
+ pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
}
@@ -1607,7 +1607,7 @@ static void __devexit epic_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct epic_private *ep = dev->priv;
-
+
pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
unregister_netdev(dev);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 7627a75f4f7c..04a53f1dfdbd 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -105,6 +105,10 @@
* 0.50: 20 Jan 2006: Add 8021pq tagging support.
* 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings.
* 0.52: 20 Jan 2006: Add MSI/MSIX support.
+ * 0.53: 19 Mar 2006: Fix init from low power mode and add hw reset.
+ * 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
+ * 0.55: 22 Mar 2006: Add flow control (pause frame).
+ * 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -116,7 +120,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.52"
+#define FORCEDETH_VERSION "0.56"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -160,6 +164,10 @@
#define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */
#define DEV_HAS_MSI 0x0040 /* device supports MSI */
#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */
+#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */
+#define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */
+#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */
+#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */
enum {
NvRegIrqStatus = 0x000,
@@ -200,18 +208,23 @@ enum {
NvRegMSIIrqMask = 0x030,
#define NVREG_MSI_VECTOR_0_ENABLED 0x01
NvRegMisc1 = 0x080,
+#define NVREG_MISC1_PAUSE_TX 0x01
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
+ NvRegMacReset = 0x3c,
+#define NVREG_MAC_RESET_ASSERT 0x0F3
NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START 0x01
NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY 0x01
NvRegPacketFilterFlags = 0x8c,
-#define NVREG_PFF_ALWAYS 0x7F0008
+#define NVREG_PFF_PAUSE_RX 0x08
+#define NVREG_PFF_ALWAYS 0x7F0000
#define NVREG_PFF_PROMISC 0x80
#define NVREG_PFF_MYADDR 0x20
+#define NVREG_PFF_LOOPBACK 0x10
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
@@ -272,6 +285,9 @@ enum {
#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegTxRingPhysAddrHigh = 0x148,
NvRegRxRingPhysAddrHigh = 0x14C,
+ NvRegTxPauseFrame = 0x170,
+#define NVREG_TX_PAUSEFRAME_DISABLE 0x1ff0080
+#define NVREG_TX_PAUSEFRAME_ENABLE 0x0c00030
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -321,11 +337,42 @@ enum {
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
+ NvRegTxCnt = 0x280,
+ NvRegTxZeroReXmt = 0x284,
+ NvRegTxOneReXmt = 0x288,
+ NvRegTxManyReXmt = 0x28c,
+ NvRegTxLateCol = 0x290,
+ NvRegTxUnderflow = 0x294,
+ NvRegTxLossCarrier = 0x298,
+ NvRegTxExcessDef = 0x29c,
+ NvRegTxRetryErr = 0x2a0,
+ NvRegRxFrameErr = 0x2a4,
+ NvRegRxExtraByte = 0x2a8,
+ NvRegRxLateCol = 0x2ac,
+ NvRegRxRunt = 0x2b0,
+ NvRegRxFrameTooLong = 0x2b4,
+ NvRegRxOverflow = 0x2b8,
+ NvRegRxFCSErr = 0x2bc,
+ NvRegRxFrameAlignErr = 0x2c0,
+ NvRegRxLenErr = 0x2c4,
+ NvRegRxUnicast = 0x2c8,
+ NvRegRxMulticast = 0x2cc,
+ NvRegRxBroadcast = 0x2d0,
+ NvRegTxDef = 0x2d4,
+ NvRegTxFrame = 0x2d8,
+ NvRegRxCnt = 0x2dc,
+ NvRegTxPause = 0x2e0,
+ NvRegRxPause = 0x2e4,
+ NvRegRxDropFrame = 0x2e8,
NvRegVlanControl = 0x300,
#define NVREG_VLANCONTROL_ENABLE 0x2000
NvRegMSIXMap0 = 0x3e0,
NvRegMSIXMap1 = 0x3e4,
NvRegMSIXIrqStatus = 0x3f0,
+
+ NvRegPowerState2 = 0x600,
+#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11
+#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
};
/* Big endian: should work, but is untested */
@@ -414,7 +461,8 @@ typedef union _ring_type {
#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF)
/* Miscelaneous hardware related defines: */
-#define NV_PCI_REGSZ 0x270
+#define NV_PCI_REGSZ_VER1 0x270
+#define NV_PCI_REGSZ_VER2 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -431,6 +479,7 @@ typedef union _ring_type {
#define NV_MIIBUSY_DELAY 50
#define NV_MIIPHY_DELAY 10
#define NV_MIIPHY_DELAYMAX 10000
+#define NV_MAC_RESET_DELAY 64
#define NV_WAKEUPPATTERNS 5
#define NV_WAKEUPMASKENTRIES 4
@@ -438,16 +487,18 @@ typedef union _ring_type {
/* General driver defaults */
#define NV_WATCHDOG_TIMEO (5*HZ)
-#define RX_RING 128
-#define TX_RING 256
-/*
- * If your nic mysteriously hangs then try to reduce the limits
- * to 1/0: It might be required to set NV_TX_LASTPACKET in the
- * last valid ring entry. But this would be impossible to
- * implement - probably a disassembly error.
+#define RX_RING_DEFAULT 128
+#define TX_RING_DEFAULT 256
+#define RX_RING_MIN 128
+#define TX_RING_MIN 64
+#define RING_MAX_DESC_VER_1 1024
+#define RING_MAX_DESC_VER_2_3 16384
+/*
+ * Difference between the get and put pointers for the tx ring.
+ * This is used to throttle the amount of data outstanding in the
+ * tx ring.
*/
-#define TX_LIMIT_STOP 255
-#define TX_LIMIT_START 254
+#define TX_LIMIT_DIFFERENCE 1
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
@@ -461,8 +512,9 @@ typedef union _ring_type {
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
#define LINK_TIMEOUT (3*HZ)
+#define STATS_INTERVAL (10*HZ)
-/*
+/*
* desc_ver values:
* The nic supports three different descriptor types:
* - DESC_VER_1: Original
@@ -495,13 +547,13 @@ typedef union _ring_type {
#define PHY_1000 0x2
#define PHY_HALF 0x100
-/* FIXME: MII defines that should be added to <linux/mii.h> */
-#define MII_1000BT_CR 0x09
-#define MII_1000BT_SR 0x0a
-#define ADVERTISE_1000FULL 0x0200
-#define ADVERTISE_1000HALF 0x0100
-#define LPA_1000FULL 0x0800
-#define LPA_1000HALF 0x0400
+#define NV_PAUSEFRAME_RX_CAPABLE 0x0001
+#define NV_PAUSEFRAME_TX_CAPABLE 0x0002
+#define NV_PAUSEFRAME_RX_ENABLE 0x0004
+#define NV_PAUSEFRAME_TX_ENABLE 0x0008
+#define NV_PAUSEFRAME_RX_REQ 0x0010
+#define NV_PAUSEFRAME_TX_REQ 0x0020
+#define NV_PAUSEFRAME_AUTONEG 0x0040
/* MSI/MSI-X defines */
#define NV_MSI_X_MAX_VECTORS 8
@@ -516,15 +568,110 @@ typedef union _ring_type {
#define NV_MSI_X_VECTOR_TX 0x1
#define NV_MSI_X_VECTOR_OTHER 0x2
+/* statistics */
+struct nv_ethtool_str {
+ char name[ETH_GSTRING_LEN];
+};
+
+static const struct nv_ethtool_str nv_estats_str[] = {
+ { "tx_bytes" },
+ { "tx_zero_rexmt" },
+ { "tx_one_rexmt" },
+ { "tx_many_rexmt" },
+ { "tx_late_collision" },
+ { "tx_fifo_errors" },
+ { "tx_carrier_errors" },
+ { "tx_excess_deferral" },
+ { "tx_retry_error" },
+ { "tx_deferral" },
+ { "tx_packets" },
+ { "tx_pause" },
+ { "rx_frame_error" },
+ { "rx_extra_byte" },
+ { "rx_late_collision" },
+ { "rx_runt" },
+ { "rx_frame_too_long" },
+ { "rx_over_errors" },
+ { "rx_crc_errors" },
+ { "rx_frame_align_error" },
+ { "rx_length_error" },
+ { "rx_unicast" },
+ { "rx_multicast" },
+ { "rx_broadcast" },
+ { "rx_bytes" },
+ { "rx_pause" },
+ { "rx_drop_frame" },
+ { "rx_packets" },
+ { "rx_errors_total" }
+};
+
+struct nv_ethtool_stats {
+ u64 tx_bytes;
+ u64 tx_zero_rexmt;
+ u64 tx_one_rexmt;
+ u64 tx_many_rexmt;
+ u64 tx_late_collision;
+ u64 tx_fifo_errors;
+ u64 tx_carrier_errors;
+ u64 tx_excess_deferral;
+ u64 tx_retry_error;
+ u64 tx_deferral;
+ u64 tx_packets;
+ u64 tx_pause;
+ u64 rx_frame_error;
+ u64 rx_extra_byte;
+ u64 rx_late_collision;
+ u64 rx_runt;
+ u64 rx_frame_too_long;
+ u64 rx_over_errors;
+ u64 rx_crc_errors;
+ u64 rx_frame_align_error;
+ u64 rx_length_error;
+ u64 rx_unicast;
+ u64 rx_multicast;
+ u64 rx_broadcast;
+ u64 rx_bytes;
+ u64 rx_pause;
+ u64 rx_drop_frame;
+ u64 rx_packets;
+ u64 rx_errors_total;
+};
+
+/* diagnostics */
+#define NV_TEST_COUNT_BASE 3
+#define NV_TEST_COUNT_EXTENDED 4
+
+static const struct nv_ethtool_str nv_etests_str[] = {
+ { "link (online/offline)" },
+ { "register (offline) " },
+ { "interrupt (offline) " },
+ { "loopback (offline) " }
+};
+
+struct register_test {
+ u32 reg;
+ u32 mask;
+};
+
+static const struct register_test nv_registers_test[] = {
+ { NvRegUnknownSetupReg6, 0x01 },
+ { NvRegMisc1, 0x03c },
+ { NvRegOffloadConfig, 0x03ff },
+ { NvRegMulticastAddrA, 0xffffffff },
+ { NvRegUnknownSetupReg3, 0x0ff },
+ { NvRegWakeUpFlags, 0x07777 },
+ { 0,0 }
+};
+
/*
* SMP locking:
* All hardware access under dev->priv->lock, except the performance
* critical parts:
* - rx is (pseudo-) lockless: it relies on the single-threading provided
* by the arch code for interrupts.
- * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission
+ * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
* needs dev->priv->lock :-(
- * - set_multicast_list: preparation lockless, relies on dev->xmit_lock.
+ * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
*/
/* in dev: base, irq */
@@ -534,6 +681,7 @@ struct fe_priv {
/* General data:
* Locking: spin_lock(&np->lock); */
struct net_device_stats stats;
+ struct nv_ethtool_stats estats;
int in_shutdown;
u32 linkspeed;
int duplex;
@@ -543,6 +691,7 @@ struct fe_priv {
int wolenabled;
unsigned int phy_oui;
u16 gigabit;
+ int intr_test;
/* General data: RO fields */
dma_addr_t ring_addr;
@@ -552,6 +701,8 @@ struct fe_priv {
u32 desc_ver;
u32 txrxctl_bits;
u32 vlanctl_bits;
+ u32 driver_data;
+ u32 register_size;
void __iomem *base;
@@ -560,13 +711,15 @@ struct fe_priv {
*/
ring_type rx_ring;
unsigned int cur_rx, refill_rx;
- struct sk_buff *rx_skbuff[RX_RING];
- dma_addr_t rx_dma[RX_RING];
+ struct sk_buff **rx_skbuff;
+ dma_addr_t *rx_dma;
unsigned int rx_buf_sz;
unsigned int pkt_limit;
struct timer_list oom_kick;
struct timer_list nic_poll;
+ struct timer_list stats_poll;
u32 nic_poll_irq;
+ int rx_ring_size;
/* media detection workaround.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
@@ -578,10 +731,13 @@ struct fe_priv {
*/
ring_type tx_ring;
unsigned int next_tx, nic_tx;
- struct sk_buff *tx_skbuff[TX_RING];
- dma_addr_t tx_dma[TX_RING];
- unsigned int tx_dma_len[TX_RING];
+ struct sk_buff **tx_skbuff;
+ dma_addr_t *tx_dma;
+ unsigned int *tx_dma_len;
u32 tx_flags;
+ int tx_ring_size;
+ int tx_limit_start;
+ int tx_limit_stop;
/* vlan fields */
struct vlan_group *vlangrp;
@@ -589,6 +745,9 @@ struct fe_priv {
/* msi/msi-x fields */
u32 msi_flags;
struct msix_entry msi_x_entry[NV_MSI_X_MAX_VECTORS];
+
+ /* flow control */
+ u32 pause_flags;
};
/*
@@ -599,12 +758,14 @@ static int max_interrupt_work = 5;
/*
* Optimization can be either throuput mode or cpu mode
- *
+ *
* Throughput Mode: Every tx and rx packet will generate an interrupt.
* CPU Mode: Interrupts are controlled by a timer.
*/
-#define NV_OPTIMIZATION_MODE_THROUGHPUT 0
-#define NV_OPTIMIZATION_MODE_CPU 1
+enum {
+ NV_OPTIMIZATION_MODE_THROUGHPUT,
+ NV_OPTIMIZATION_MODE_CPU
+};
static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
/*
@@ -617,14 +778,31 @@ static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
static int poll_interval = -1;
/*
- * Disable MSI interrupts
+ * MSI interrupts
*/
-static int disable_msi = 0;
+enum {
+ NV_MSI_INT_DISABLED,
+ NV_MSI_INT_ENABLED
+};
+static int msi = NV_MSI_INT_ENABLED;
/*
- * Disable MSIX interrupts
+ * MSIX interrupts
*/
-static int disable_msix = 0;
+enum {
+ NV_MSIX_INT_DISABLED,
+ NV_MSIX_INT_ENABLED
+};
+static int msix = NV_MSIX_INT_ENABLED;
+
+/*
+ * DMA 64bit
+ */
+enum {
+ NV_DMA_64BIT_DISABLED,
+ NV_DMA_64BIT_ENABLED
+};
+static int dma_64bit = NV_DMA_64BIT_ENABLED;
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
@@ -684,7 +862,7 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr);
}
if (rxtx_flags & NV_SETUP_TX_RING) {
- writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+ writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
}
} else {
if (rxtx_flags & NV_SETUP_RX_RING) {
@@ -692,12 +870,103 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh);
}
if (rxtx_flags & NV_SETUP_TX_RING) {
- writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
- writel((u32) (cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh);
+ writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
+ writel((u32) (cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh);
}
}
}
+static void free_rings(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ if(np->rx_ring.orig)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
+ np->rx_ring.orig, np->ring_addr);
+ } else {
+ if (np->rx_ring.ex)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
+ np->rx_ring.ex, np->ring_addr);
+ }
+ if (np->rx_skbuff)
+ kfree(np->rx_skbuff);
+ if (np->rx_dma)
+ kfree(np->rx_dma);
+ if (np->tx_skbuff)
+ kfree(np->tx_skbuff);
+ if (np->tx_dma)
+ kfree(np->tx_dma);
+ if (np->tx_dma_len)
+ kfree(np->tx_dma_len);
+}
+
+static int using_multi_irqs(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+
+ if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
+ ((np->msi_flags & NV_MSI_X_ENABLED) &&
+ ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1)))
+ return 0;
+ else
+ return 1;
+}
+
+static void nv_enable_irq(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+
+ if (!using_multi_irqs(dev)) {
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ enable_irq(dev->irq);
+ } else {
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+ }
+}
+
+static void nv_disable_irq(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+
+ if (!using_multi_irqs(dev)) {
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ disable_irq(dev->irq);
+ } else {
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+ }
+}
+
+/* In MSIX mode, a write to irqmask behaves as XOR */
+static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask)
+{
+ u8 __iomem *base = get_hwbase(dev);
+
+ writel(mask, base + NvRegIrqMask);
+}
+
+static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ if (np->msi_flags & NV_MSI_X_ENABLED) {
+ writel(mask, base + NvRegIrqMask);
+ } else {
+ if (np->msi_flags & NV_MSI_ENABLED)
+ writel(0, base + NvRegMSIIrqMask);
+ writel(0, base + NvRegIrqMask);
+ }
+}
+
#define MII_READ (-1)
/* mii_rw: read/write a register on the PHY.
*
@@ -781,7 +1050,7 @@ static int phy_init(struct net_device *dev)
/* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|0x800|0x400);
+ reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) {
printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
@@ -794,14 +1063,14 @@ static int phy_init(struct net_device *dev)
mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
if (mii_status & PHY_GIGABIT) {
np->gigabit = PHY_GIGABIT;
- mii_control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ mii_control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
mii_control_1000 &= ~ADVERTISE_1000HALF;
if (phyinterface & PHY_RGMII)
mii_control_1000 |= ADVERTISE_1000FULL;
else
mii_control_1000 &= ~ADVERTISE_1000FULL;
- if (mii_rw(dev, np->phyaddr, MII_1000BT_CR, mii_control_1000)) {
+ if (mii_rw(dev, np->phyaddr, MII_CTRL1000, mii_control_1000)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
@@ -839,6 +1108,8 @@ static int phy_init(struct net_device *dev)
return PHY_ERROR;
}
}
+ /* some phys clear out pause advertisment on reset, set it back */
+ mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg);
/* restart auto negotiation */
mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
@@ -919,6 +1190,24 @@ static void nv_txrx_reset(struct net_device *dev)
pci_push(base);
}
+static void nv_mac_reset(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
+ pci_push(base);
+ writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
+ pci_push(base);
+ udelay(NV_MAC_RESET_DELAY);
+ writel(0, base + NvRegMacReset);
+ pci_push(base);
+ udelay(NV_MAC_RESET_DELAY);
+ writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
+ pci_push(base);
+}
+
/*
* nv_get_stats: dev->get_stats function
* Get latest stats value from the nic.
@@ -950,7 +1239,7 @@ static int nv_alloc_rx(struct net_device *dev)
while (np->cur_rx != refill_rx) {
struct sk_buff *skb;
- nr = refill_rx % RX_RING;
+ nr = refill_rx % np->rx_ring_size;
if (np->rx_skbuff[nr] == NULL) {
skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
@@ -979,7 +1268,7 @@ static int nv_alloc_rx(struct net_device *dev)
refill_rx++;
}
np->refill_rx = refill_rx;
- if (np->cur_rx - refill_rx == RX_RING)
+ if (np->cur_rx - refill_rx == np->rx_ring_size)
return 1;
return 0;
}
@@ -989,37 +1278,38 @@ static void nv_do_rx_refill(unsigned long data)
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
-
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
- disable_irq(dev->irq);
+ if (!using_multi_irqs(dev)) {
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ disable_irq(dev->irq);
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
if (nv_alloc_rx(dev)) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
}
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
- enable_irq(dev->irq);
+ if (!using_multi_irqs(dev)) {
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ enable_irq(dev->irq);
} else {
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
}
-static void nv_init_rx(struct net_device *dev)
+static void nv_init_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
- np->cur_rx = RX_RING;
+ np->cur_rx = np->rx_ring_size;
np->refill_rx = 0;
- for (i = 0; i < RX_RING; i++)
+ for (i = 0; i < np->rx_ring_size; i++)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->rx_ring.orig[i].FlagLen = 0;
else
@@ -1032,7 +1322,7 @@ static void nv_init_tx(struct net_device *dev)
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++) {
+ for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
@@ -1076,8 +1366,8 @@ static void nv_drain_tx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
unsigned int i;
-
- for (i = 0; i < TX_RING; i++) {
+
+ for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
@@ -1091,7 +1381,7 @@ static void nv_drain_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
- for (i = 0; i < RX_RING; i++) {
+ for (i = 0; i < np->rx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->rx_ring.orig[i].FlagLen = 0;
else
@@ -1115,7 +1405,7 @@ static void drain_ring(struct net_device *dev)
/*
* nv_start_xmit: dev->hard_start_xmit function
- * Called with dev->xmit_lock held.
+ * Called with netif_tx_lock held.
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -1123,8 +1413,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tx_flags = 0;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
unsigned int fragments = skb_shinfo(skb)->nr_frags;
- unsigned int nr = (np->next_tx - 1) % TX_RING;
- unsigned int start_nr = np->next_tx % TX_RING;
+ unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
+ unsigned int start_nr = np->next_tx % np->tx_ring_size;
unsigned int i;
u32 offset = 0;
u32 bcnt;
@@ -1140,7 +1430,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&np->lock);
- if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
+ if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
spin_unlock_irq(&np->lock);
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
@@ -1149,7 +1439,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* setup the header buffer */
do {
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % TX_RING;
+ nr = (nr + 1) % np->tx_ring_size;
np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
PCI_DMA_TODEVICE);
@@ -1176,7 +1466,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
do {
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % TX_RING;
+ nr = (nr + 1) % np->tx_ring_size;
np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
PCI_DMA_TODEVICE);
@@ -1222,7 +1512,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else {
np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
- }
+ }
dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
dev->name, np->next_tx, entries, tx_flags_extra);
@@ -1258,7 +1548,7 @@ static void nv_tx_done(struct net_device *dev)
struct sk_buff *skb;
while (np->nic_tx != np->next_tx) {
- i = np->nic_tx % TX_RING;
+ i = np->nic_tx % np->tx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
@@ -1297,19 +1587,19 @@ static void nv_tx_done(struct net_device *dev)
} else {
np->stats.tx_packets++;
np->stats.tx_bytes += skb->len;
- }
+ }
}
}
nv_release_txskb(dev, i);
np->nic_tx++;
}
- if (np->next_tx - np->nic_tx < TX_LIMIT_START)
+ if (np->next_tx - np->nic_tx < np->tx_limit_start)
netif_wake_queue(dev);
}
/*
* nv_tx_timeout: dev->tx_timeout function
- * Called with dev->xmit_lock held.
+ * Called with netif_tx_lock held.
*/
static void nv_tx_timeout(struct net_device *dev)
{
@@ -1331,7 +1621,7 @@ static void nv_tx_timeout(struct net_device *dev)
dev->name, (unsigned long)np->ring_addr,
np->next_tx, np->nic_tx);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
- for (i=0;i<0x400;i+= 32) {
+ for (i=0;i<=np->register_size;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
i,
readl(base + i + 0), readl(base + i + 4),
@@ -1340,10 +1630,10 @@ static void nv_tx_timeout(struct net_device *dev)
readl(base + i + 24), readl(base + i + 28));
}
printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
- for (i=0;i<TX_RING;i+= 4) {
+ for (i=0;i<np->tx_ring_size;i+= 4) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
- i,
+ i,
le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
le32_to_cpu(np->tx_ring.orig[i].FlagLen),
le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
@@ -1354,7 +1644,7 @@ static void nv_tx_timeout(struct net_device *dev)
le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
} else {
printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
- i,
+ i,
le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
le32_to_cpu(np->tx_ring.ex[i].FlagLen),
@@ -1452,15 +1742,14 @@ static void nv_rx_process(struct net_device *dev)
u32 Flags;
u32 vlanflags = 0;
-
for (;;) {
struct sk_buff *skb;
int len;
int i;
- if (np->cur_rx - np->refill_rx >= RX_RING)
+ if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
break; /* we scanned the whole ring - do not continue */
- i = np->cur_rx % RX_RING;
+ i = np->cur_rx % np->rx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
@@ -1567,14 +1856,16 @@ static void nv_rx_process(struct net_device *dev)
}
}
}
- Flags &= NV_RX2_CHECKSUMMASK;
- if (Flags == NV_RX2_CHECKSUMOK1 ||
- Flags == NV_RX2_CHECKSUMOK2 ||
- Flags == NV_RX2_CHECKSUMOK3) {
- dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
- np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+ if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
+ Flags &= NV_RX2_CHECKSUMMASK;
+ if (Flags == NV_RX2_CHECKSUMOK1 ||
+ Flags == NV_RX2_CHECKSUMOK2 ||
+ Flags == NV_RX2_CHECKSUMOK3) {
+ dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
+ np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+ }
}
}
/* got a valid packet - forward it to the network core */
@@ -1638,16 +1929,8 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
* guessed, there is probably a simpler approach.
* Changing the MTU is a rare event, it shouldn't matter.
*/
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
- disable_irq(dev->irq);
- } else {
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
- }
- spin_lock_bh(&dev->xmit_lock);
+ nv_disable_irq(dev);
+ netif_tx_lock_bh(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rx(dev);
@@ -1657,18 +1940,15 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
nv_drain_rx(dev);
nv_drain_tx(dev);
/* reinit driver view of the rx queue */
- nv_init_rx(dev);
- nv_init_tx(dev);
- /* alloc new rx buffers */
set_bufsize(dev);
- if (nv_alloc_rx(dev)) {
+ if (nv_init_ring(dev)) {
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
}
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
@@ -1678,16 +1958,8 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
nv_start_rx(dev);
nv_start_tx(dev);
spin_unlock(&np->lock);
- spin_unlock_bh(&dev->xmit_lock);
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
- enable_irq(dev->irq);
- } else {
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
- }
+ netif_tx_unlock_bh(dev);
+ nv_enable_irq(dev);
}
return 0;
}
@@ -1721,7 +1993,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
if (netif_running(dev)) {
- spin_lock_bh(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
/* stop rx engine */
@@ -1733,7 +2005,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
/* restart rx engine */
nv_start_rx(dev);
spin_unlock_irq(&np->lock);
- spin_unlock_bh(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
} else {
nv_copy_mac_to_hw(dev);
}
@@ -1742,7 +2014,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
/*
* nv_set_multicast: dev->set_multicast function
- * Called with dev->xmit_lock held.
+ * Called with netif_tx_lock held.
*/
static void nv_set_multicast(struct net_device *dev)
{
@@ -1750,16 +2022,16 @@ static void nv_set_multicast(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
- u32 pff;
+ u32 pff = readl(base + NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX;
memset(addr, 0, sizeof(addr));
memset(mask, 0, sizeof(mask));
if (dev->flags & IFF_PROMISC) {
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
- pff = NVREG_PFF_PROMISC;
+ pff |= NVREG_PFF_PROMISC;
} else {
- pff = NVREG_PFF_MYADDR;
+ pff |= NVREG_PFF_MYADDR;
if (dev->flags & IFF_ALLMULTI || dev->mc_list) {
u32 alwaysOff[2];
@@ -1804,6 +2076,35 @@ static void nv_set_multicast(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
+void nv_update_pause(struct net_device *dev, u32 pause_flags)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE);
+
+ if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) {
+ u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX;
+ if (pause_flags & NV_PAUSEFRAME_RX_ENABLE) {
+ writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags);
+ np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ } else {
+ writel(pff, base + NvRegPacketFilterFlags);
+ }
+ }
+ if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) {
+ u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX;
+ if (pause_flags & NV_PAUSEFRAME_TX_ENABLE) {
+ writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame);
+ writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1);
+ np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ } else {
+ writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame);
+ writel(regmisc, base + NvRegMisc1);
+ }
+ }
+}
+
/**
* nv_update_linkspeed: Setup the MAC according to the link partner
* @dev: Network device to be configured
@@ -1819,12 +2120,14 @@ static int nv_update_linkspeed(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- int adv, lpa;
+ int adv = 0;
+ int lpa = 0;
+ int adv_lpa, adv_pause, lpa_pause;
int newls = np->linkspeed;
int newdup = np->duplex;
int mii_status;
int retval = 0;
- u32 control_1000, status_1000, phyreg;
+ u32 control_1000, status_1000, phyreg, pause_flags;
/* BMSR_LSTATUS is latched, read it twice:
* we want the current value.
@@ -1870,10 +2173,15 @@ static int nv_update_linkspeed(struct net_device *dev)
goto set_speed;
}
+ adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
+ dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
+ dev->name, adv, lpa);
+
retval = 1;
if (np->gigabit == PHY_GIGABIT) {
- control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
- status_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_SR, MII_READ);
+ control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
+ status_1000 = mii_rw(dev, np->phyaddr, MII_STAT1000, MII_READ);
if ((control_1000 & ADVERTISE_1000FULL) &&
(status_1000 & LPA_1000FULL)) {
@@ -1885,27 +2193,22 @@ static int nv_update_linkspeed(struct net_device *dev)
}
}
- adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
- dev->name, adv, lpa);
-
/* FIXME: handle parallel detection properly */
- lpa = lpa & adv;
- if (lpa & LPA_100FULL) {
+ adv_lpa = lpa & adv;
+ if (adv_lpa & LPA_100FULL) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
newdup = 1;
- } else if (lpa & LPA_100HALF) {
+ } else if (adv_lpa & LPA_100HALF) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
newdup = 0;
- } else if (lpa & LPA_10FULL) {
+ } else if (adv_lpa & LPA_10FULL) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 1;
- } else if (lpa & LPA_10HALF) {
+ } else if (adv_lpa & LPA_10HALF) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
} else {
- dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa);
+ dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, adv_lpa);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
}
@@ -1948,6 +2251,46 @@ set_speed:
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
+ pause_flags = 0;
+ /* setup pause frame */
+ if (np->duplex != 0) {
+ if (np->autoneg && np->pause_flags & NV_PAUSEFRAME_AUTONEG) {
+ adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM);
+ lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
+
+ switch (adv_pause) {
+ case (ADVERTISE_PAUSE_CAP):
+ if (lpa_pause & LPA_PAUSE_CAP) {
+ pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
+ pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
+ break;
+ case (ADVERTISE_PAUSE_ASYM):
+ if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
+ {
+ pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
+ break;
+ case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
+ if (lpa_pause & LPA_PAUSE_CAP)
+ {
+ pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
+ pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
+ if (lpa_pause == LPA_PAUSE_ASYM)
+ {
+ pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ }
+ break;
+ }
+ } else {
+ pause_flags = np->pause_flags;
+ }
+ }
+ nv_update_pause(dev, pause_flags);
+
return retval;
}
@@ -2008,7 +2351,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
spin_lock(&np->lock);
nv_tx_done(dev);
spin_unlock(&np->lock);
-
+
nv_rx_process(dev);
if (nv_alloc_rx(dev)) {
spin_lock(&np->lock);
@@ -2016,7 +2359,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
-
+
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
nv_link_irq(dev);
@@ -2078,16 +2421,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
nv_tx_done(dev);
- spin_unlock(&np->lock);
-
+ spin_unlock_irq(&np->lock);
+
if (events & (NVREG_IRQ_TX_ERR)) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
if (i > max_interrupt_work) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
/* disable interrupts on the nic */
writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -2097,7 +2440,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
break;
}
@@ -2124,17 +2467,17 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
-
+
nv_rx_process(dev);
if (nv_alloc_rx(dev)) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
}
-
+
if (i > max_interrupt_work) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
/* disable interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -2144,7 +2487,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
break;
}
@@ -2171,16 +2514,16 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
-
+
if (events & NVREG_IRQ_LINK) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
nv_link_irq(dev);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
}
if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
nv_linkchange(dev);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
np->link_timeout = jiffies + LINK_TIMEOUT;
}
if (events & (NVREG_IRQ_UNKNOWN)) {
@@ -2188,7 +2531,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
dev->name, events);
}
if (i > max_interrupt_work) {
- spin_lock(&np->lock);
+ spin_lock_irq(&np->lock);
/* disable interrupts on the nic */
writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
pci_push(base);
@@ -2198,7 +2541,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
- spin_unlock(&np->lock);
+ spin_unlock_irq(&np->lock);
break;
}
@@ -2208,6 +2551,175 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
return IRQ_RETVAL(i);
}
+static irqreturn_t nv_nic_irq_test(int foo, void *data, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_test\n", dev->name);
+
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQ_TIMER, base + NvRegIrqStatus);
+ } else {
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus);
+ }
+ pci_push(base);
+ dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+ if (!(events & NVREG_IRQ_TIMER))
+ return IRQ_RETVAL(0);
+
+ spin_lock(&np->lock);
+ np->intr_test = 1;
+ spin_unlock(&np->lock);
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_test completed\n", dev->name);
+
+ return IRQ_RETVAL(1);
+}
+
+static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask)
+{
+ u8 __iomem *base = get_hwbase(dev);
+ int i;
+ u32 msixmap = 0;
+
+ /* Each interrupt bit can be mapped to a MSIX vector (4 bits).
+ * MSIXMap0 represents the first 8 interrupts and MSIXMap1 represents
+ * the remaining 8 interrupts.
+ */
+ for (i = 0; i < 8; i++) {
+ if ((irqmask >> i) & 0x1) {
+ msixmap |= vector << (i << 2);
+ }
+ }
+ writel(readl(base + NvRegMSIXMap0) | msixmap, base + NvRegMSIXMap0);
+
+ msixmap = 0;
+ for (i = 0; i < 8; i++) {
+ if ((irqmask >> (i + 8)) & 0x1) {
+ msixmap |= vector << (i << 2);
+ }
+ }
+ writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1);
+}
+
+static int nv_request_irq(struct net_device *dev, int intr_test)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ int ret = 1;
+ int i;
+
+ if (np->msi_flags & NV_MSI_X_CAPABLE) {
+ for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
+ np->msi_x_entry[i].entry = i;
+ }
+ if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) {
+ np->msi_flags |= NV_MSI_X_ENABLED;
+ if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
+ /* Request irq for rx handling */
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) {
+ printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret);
+ pci_disable_msix(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_X_ENABLED;
+ goto out_err;
+ }
+ /* Request irq for tx handling */
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) {
+ printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret);
+ pci_disable_msix(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_X_ENABLED;
+ goto out_free_rx;
+ }
+ /* Request irq for link and timer handling */
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) {
+ printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret);
+ pci_disable_msix(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_X_ENABLED;
+ goto out_free_tx;
+ }
+ /* map interrupts to their respective vector */
+ writel(0, base + NvRegMSIXMap0);
+ writel(0, base + NvRegMSIXMap1);
+ set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL);
+ set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL);
+ set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
+ } else {
+ /* Request irq for all interrupts */
+ if ((!intr_test &&
+ request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
+ (intr_test &&
+ request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+ printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
+ pci_disable_msix(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_X_ENABLED;
+ goto out_err;
+ }
+
+ /* map interrupts to vector 0 */
+ writel(0, base + NvRegMSIXMap0);
+ writel(0, base + NvRegMSIXMap1);
+ }
+ }
+ }
+ if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
+ if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
+ np->msi_flags |= NV_MSI_ENABLED;
+ if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
+ (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+ printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
+ pci_disable_msi(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_ENABLED;
+ goto out_err;
+ }
+
+ /* map interrupts to vector 0 */
+ writel(0, base + NvRegMSIMap0);
+ writel(0, base + NvRegMSIMap1);
+ /* enable msi vector 0 */
+ writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
+ }
+ }
+ if (ret != 0) {
+ if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
+ (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0))
+ goto out_err;
+
+ }
+
+ return 0;
+out_free_tx:
+ free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, dev);
+out_free_rx:
+ free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, dev);
+out_err:
+ return 1;
+}
+
+static void nv_free_irq(struct net_device *dev)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ int i;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED) {
+ for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
+ free_irq(np->msi_x_entry[i].vector, dev);
+ }
+ pci_disable_msix(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_X_ENABLED;
+ } else {
+ free_irq(np->pci_dev->irq, dev);
+ if (np->msi_flags & NV_MSI_ENABLED) {
+ pci_disable_msi(np->pci_dev);
+ np->msi_flags &= ~NV_MSI_ENABLED;
+ }
+ }
+}
+
static void nv_do_nic_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
@@ -2221,10 +2733,11 @@ static void nv_do_nic_poll(unsigned long data)
* nv_nic_irq because that may decide to do otherwise
*/
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
- disable_irq(dev->irq);
+ if (!using_multi_irqs(dev)) {
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ disable_irq(dev->irq);
mask = np->irqmask;
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
@@ -2243,15 +2756,16 @@ static void nv_do_nic_poll(unsigned long data)
np->nic_poll_irq = 0;
/* FIXME: Do we need synchronize_irq(dev->irq) here? */
-
+
writel(mask, base + NvRegIrqMask);
pci_push(base);
- if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
- ((np->msi_flags & NV_MSI_X_ENABLED) &&
- ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
+ if (!using_multi_irqs(dev)) {
nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
- enable_irq(dev->irq);
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ else
+ enable_irq(dev->irq);
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL);
@@ -2275,6 +2789,56 @@ static void nv_poll_controller(struct net_device *dev)
}
#endif
+static void nv_do_stats_poll(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ np->estats.tx_bytes += readl(base + NvRegTxCnt);
+ np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+ np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+ np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+ np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+ np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+ np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+ np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+ np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+ np->estats.tx_deferral += readl(base + NvRegTxDef);
+ np->estats.tx_packets += readl(base + NvRegTxFrame);
+ np->estats.tx_pause += readl(base + NvRegTxPause);
+ np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+ np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+ np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+ np->estats.rx_runt += readl(base + NvRegRxRunt);
+ np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+ np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+ np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+ np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+ np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+ np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+ np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+ np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+ np->estats.rx_bytes += readl(base + NvRegRxCnt);
+ np->estats.rx_pause += readl(base + NvRegRxPause);
+ np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+ np->estats.rx_packets =
+ np->estats.rx_unicast +
+ np->estats.rx_multicast +
+ np->estats.rx_broadcast;
+ np->estats.rx_errors_total =
+ np->estats.rx_crc_errors +
+ np->estats.rx_over_errors +
+ np->estats.rx_frame_error +
+ (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+ np->estats.rx_late_collision +
+ np->estats.rx_runt +
+ np->estats.rx_frame_too_long;
+
+ if (!np->in_shutdown)
+ mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
+}
+
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct fe_priv *np = netdev_priv(dev);
@@ -2298,17 +2862,19 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 flags = 0;
- spin_lock_irq(&np->lock);
if (wolinfo->wolopts == 0) {
- writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
- }
- if (wolinfo->wolopts & WAKE_MAGIC) {
- writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
+ } else if (wolinfo->wolopts & WAKE_MAGIC) {
np->wolenabled = 1;
+ flags = NVREG_WAKEUPFLAGS_ENABLE;
+ }
+ if (netif_running(dev)) {
+ spin_lock_irq(&np->lock);
+ writel(flags, base + NvRegWakeUpFlags);
+ spin_unlock_irq(&np->lock);
}
- spin_unlock_irq(&np->lock);
return 0;
}
@@ -2322,9 +2888,17 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (!netif_running(dev)) {
/* We do not track link speed / duplex setting if the
* interface is disabled. Force a link check */
- nv_update_linkspeed(dev);
+ if (nv_update_linkspeed(dev)) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ } else {
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+ }
}
- switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) {
+
+ if (netif_carrier_ok(dev)) {
+ switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) {
case NVREG_LINKSPEED_10:
ecmd->speed = SPEED_10;
break;
@@ -2334,10 +2908,14 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
case NVREG_LINKSPEED_1000:
ecmd->speed = SPEED_1000;
break;
+ }
+ ecmd->duplex = DUPLEX_HALF;
+ if (np->duplex)
+ ecmd->duplex = DUPLEX_FULL;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
}
- ecmd->duplex = DUPLEX_HALF;
- if (np->duplex)
- ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = np->autoneg;
@@ -2345,23 +2923,20 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (np->autoneg) {
ecmd->advertising |= ADVERTISED_Autoneg;
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- } else {
- adv = np->fixed_mode;
- }
- if (adv & ADVERTISE_10HALF)
- ecmd->advertising |= ADVERTISED_10baseT_Half;
- if (adv & ADVERTISE_10FULL)
- ecmd->advertising |= ADVERTISED_10baseT_Full;
- if (adv & ADVERTISE_100HALF)
- ecmd->advertising |= ADVERTISED_100baseT_Half;
- if (adv & ADVERTISE_100FULL)
- ecmd->advertising |= ADVERTISED_100baseT_Full;
- if (np->autoneg && np->gigabit == PHY_GIGABIT) {
- adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
- if (adv & ADVERTISE_1000FULL)
- ecmd->advertising |= ADVERTISED_1000baseT_Full;
+ if (adv & ADVERTISE_10HALF)
+ ecmd->advertising |= ADVERTISED_10baseT_Half;
+ if (adv & ADVERTISE_10FULL)
+ ecmd->advertising |= ADVERTISED_10baseT_Full;
+ if (adv & ADVERTISE_100HALF)
+ ecmd->advertising |= ADVERTISED_100baseT_Half;
+ if (adv & ADVERTISE_100FULL)
+ ecmd->advertising |= ADVERTISED_100baseT_Full;
+ if (np->gigabit == PHY_GIGABIT) {
+ adv = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
+ if (adv & ADVERTISE_1000FULL)
+ ecmd->advertising |= ADVERTISED_1000baseT_Full;
+ }
}
-
ecmd->supported = (SUPPORTED_Autoneg |
SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
@@ -2413,7 +2988,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EINVAL;
}
- spin_lock_irq(&np->lock);
+ netif_carrier_off(dev);
+ if (netif_running(dev)) {
+ nv_disable_irq(dev);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock(&np->lock);
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ spin_unlock(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ }
+
if (ecmd->autoneg == AUTONEG_ENABLE) {
int adv, bmcr;
@@ -2421,7 +3007,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
/* advertise only what has been requested */
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
if (ecmd->advertising & ADVERTISED_10baseT_Half)
adv |= ADVERTISE_10HALF;
if (ecmd->advertising & ADVERTISED_10baseT_Full)
@@ -2430,16 +3016,22 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
adv |= ADVERTISE_100HALF;
if (ecmd->advertising & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
+ if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */
+ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
+ adv |= ADVERTISE_PAUSE_ASYM;
mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
if (np->gigabit == PHY_GIGABIT) {
- adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ adv = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
adv &= ~ADVERTISE_1000FULL;
if (ecmd->advertising & ADVERTISED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
- mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv);
+ mii_rw(dev, np->phyaddr, MII_CTRL1000, adv);
}
+ if (netif_running(dev))
+ printk(KERN_INFO "%s: link down.\n", dev->name);
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
@@ -2450,7 +3042,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
np->autoneg = 0;
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF)
adv |= ADVERTISE_10HALF;
if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL)
@@ -2459,40 +3051,59 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
adv |= ADVERTISE_100HALF;
if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL)
adv |= ADVERTISE_100FULL;
+ np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE);
+ if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisments but disable tx pause */
+ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ }
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) {
+ adv |= ADVERTISE_PAUSE_ASYM;
+ np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+ }
mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
np->fixed_mode = adv;
if (np->gigabit == PHY_GIGABIT) {
- adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ adv = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
adv &= ~ADVERTISE_1000FULL;
- mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv);
+ mii_rw(dev, np->phyaddr, MII_CTRL1000, adv);
}
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
- bmcr |= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_FULLDPLX);
- if (adv & (ADVERTISE_10FULL|ADVERTISE_100FULL))
+ bmcr &= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_SPEED1000|BMCR_FULLDPLX);
+ if (np->fixed_mode & (ADVERTISE_10FULL|ADVERTISE_100FULL))
bmcr |= BMCR_FULLDPLX;
- if (adv & (ADVERTISE_100HALF|ADVERTISE_100FULL))
+ if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL))
bmcr |= BMCR_SPEED100;
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
-
- if (netif_running(dev)) {
+ if (np->phy_oui == PHY_OUI_MARVELL) {
+ /* reset the phy */
+ if (phy_reset(dev)) {
+ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ return -EINVAL;
+ }
+ } else if (netif_running(dev)) {
/* Wait a bit and then reconfigure the nic. */
udelay(10);
nv_linkchange(dev);
}
}
- spin_unlock_irq(&np->lock);
+
+ if (netif_running(dev)) {
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ nv_enable_irq(dev);
+ }
return 0;
}
#define FORCEDETH_REGS_VER 1
-#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */
static int nv_get_regs_len(struct net_device *dev)
{
- return FORCEDETH_REGS_SIZE;
+ struct fe_priv *np = netdev_priv(dev);
+ return np->register_size;
}
static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
@@ -2504,7 +3115,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void
regs->version = FORCEDETH_REGS_VER;
spin_lock_irq(&np->lock);
- for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
+ for (i = 0;i <= np->register_size/sizeof(u32); i++)
rbuf[i] = readl(base + i*sizeof(u32));
spin_unlock_irq(&np->lock);
}
@@ -2514,23 +3125,685 @@ static int nv_nway_reset(struct net_device *dev)
struct fe_priv *np = netdev_priv(dev);
int ret;
- spin_lock_irq(&np->lock);
if (np->autoneg) {
int bmcr;
+ netif_carrier_off(dev);
+ if (netif_running(dev)) {
+ nv_disable_irq(dev);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock(&np->lock);
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ spin_unlock(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ printk(KERN_INFO "%s: link down.\n", dev->name);
+ }
+
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ if (netif_running(dev)) {
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ nv_enable_irq(dev);
+ }
ret = 0;
} else {
ret = -EINVAL;
}
+
+ return ret;
+}
+
+static int nv_set_tso(struct net_device *dev, u32 value)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if ((np->driver_data & DEV_HAS_CHECKSUM))
+ return ethtool_op_set_tso(dev, value);
+ else
+ return -EOPNOTSUPP;
+}
+
+static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ ring->rx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->tx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
+
+ ring->rx_pending = np->rx_ring_size;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+ ring->tx_pending = np->tx_ring_size;
+}
+
+static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+ dma_addr_t ring_addr;
+
+ if (ring->rx_pending < RX_RING_MIN ||
+ ring->tx_pending < TX_RING_MIN ||
+ ring->rx_mini_pending != 0 ||
+ ring->rx_jumbo_pending != 0 ||
+ (np->desc_ver == DESC_VER_1 &&
+ (ring->rx_pending > RING_MAX_DESC_VER_1 ||
+ ring->tx_pending > RING_MAX_DESC_VER_1)) ||
+ (np->desc_ver != DESC_VER_1 &&
+ (ring->rx_pending > RING_MAX_DESC_VER_2_3 ||
+ ring->tx_pending > RING_MAX_DESC_VER_2_3))) {
+ return -EINVAL;
+ }
+
+ /* allocate new rings */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ rxtx_ring = pci_alloc_consistent(np->pci_dev,
+ sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
+ &ring_addr);
+ } else {
+ rxtx_ring = pci_alloc_consistent(np->pci_dev,
+ sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
+ &ring_addr);
+ }
+ rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
+ rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
+ tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
+ tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
+ tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
+ if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+ /* fall back to old rings */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ if(rxtx_ring)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
+ rxtx_ring, ring_addr);
+ } else {
+ if (rxtx_ring)
+ pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
+ rxtx_ring, ring_addr);
+ }
+ if (rx_skbuff)
+ kfree(rx_skbuff);
+ if (rx_dma)
+ kfree(rx_dma);
+ if (tx_skbuff)
+ kfree(tx_skbuff);
+ if (tx_dma)
+ kfree(tx_dma);
+ if (tx_dma_len)
+ kfree(tx_dma_len);
+ goto exit;
+ }
+
+ if (netif_running(dev)) {
+ nv_disable_irq(dev);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock(&np->lock);
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ nv_txrx_reset(dev);
+ /* drain queues */
+ nv_drain_rx(dev);
+ nv_drain_tx(dev);
+ /* delete queues */
+ free_rings(dev);
+ }
+
+ /* set new values */
+ np->rx_ring_size = ring->rx_pending;
+ np->tx_ring_size = ring->tx_pending;
+ np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
+ np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
+ np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
+ } else {
+ np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
+ np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
+ }
+ np->rx_skbuff = (struct sk_buff**)rx_skbuff;
+ np->rx_dma = (dma_addr_t*)rx_dma;
+ np->tx_skbuff = (struct sk_buff**)tx_skbuff;
+ np->tx_dma = (dma_addr_t*)tx_dma;
+ np->tx_dma_len = (unsigned int*)tx_dma_len;
+ np->ring_addr = ring_addr;
+
+ memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
+ memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
+ memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
+ memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
+ memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+
+ if (netif_running(dev)) {
+ /* reinit driver view of the queues */
+ set_bufsize(dev);
+ if (nv_init_ring(dev)) {
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ }
+
+ /* reinit nic view of the queues */
+ writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+ setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+ pci_push(base);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ pci_push(base);
+
+ /* restart engines */
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ spin_unlock(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ nv_enable_irq(dev);
+ }
+ return 0;
+exit:
+ return -ENOMEM;
+}
+
+static void nv_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ pause->autoneg = (np->pause_flags & NV_PAUSEFRAME_AUTONEG) != 0;
+ pause->rx_pause = (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) != 0;
+ pause->tx_pause = (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) != 0;
+}
+
+static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ int adv, bmcr;
+
+ if ((!np->autoneg && np->duplex == 0) ||
+ (np->autoneg && !pause->autoneg && np->duplex == 0)) {
+ printk(KERN_INFO "%s: can not set pause settings when forced link is in half duplex.\n",
+ dev->name);
+ return -EINVAL;
+ }
+ if (pause->tx_pause && !(np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)) {
+ printk(KERN_INFO "%s: hardware does not support tx pause frames.\n", dev->name);
+ return -EINVAL;
+ }
+
+ netif_carrier_off(dev);
+ if (netif_running(dev)) {
+ nv_disable_irq(dev);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock(&np->lock);
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ spin_unlock(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ }
+
+ np->pause_flags &= ~(NV_PAUSEFRAME_RX_REQ|NV_PAUSEFRAME_TX_REQ);
+ if (pause->rx_pause)
+ np->pause_flags |= NV_PAUSEFRAME_RX_REQ;
+ if (pause->tx_pause)
+ np->pause_flags |= NV_PAUSEFRAME_TX_REQ;
+
+ if (np->autoneg && pause->autoneg) {
+ np->pause_flags |= NV_PAUSEFRAME_AUTONEG;
+
+ adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+ if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */
+ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
+
+ if (netif_running(dev))
+ printk(KERN_INFO "%s: link down.\n", dev->name);
+ bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ } else {
+ np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE);
+ if (pause->rx_pause)
+ np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
+ if (pause->tx_pause)
+ np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
+
+ if (!netif_running(dev))
+ nv_update_linkspeed(dev);
+ else
+ nv_update_pause(dev, np->pause_flags);
+ }
+
+ if (netif_running(dev)) {
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ nv_enable_irq(dev);
+ }
+ return 0;
+}
+
+static u32 nv_get_rx_csum(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ return (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) != 0;
+}
+
+static int nv_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ int retcode = 0;
+
+ if (np->driver_data & DEV_HAS_CHECKSUM) {
+
+ if (((np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && data) ||
+ (!(np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && !data)) {
+ /* already set or unset */
+ return 0;
+ }
+
+ if (data) {
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+ } else if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) {
+ np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
+ } else {
+ printk(KERN_INFO "Can not disable rx checksum if vlan is enabled\n");
+ return -EINVAL;
+ }
+
+ if (netif_running(dev)) {
+ spin_lock_irq(&np->lock);
+ writel(np->txrxctl_bits, base + NvRegTxRxControl);
+ spin_unlock_irq(&np->lock);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return retcode;
+}
+
+static int nv_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (np->driver_data & DEV_HAS_CHECKSUM)
+ return ethtool_op_set_tx_hw_csum(dev, data);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int nv_set_sg(struct net_device *dev, u32 data)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (np->driver_data & DEV_HAS_CHECKSUM)
+ return ethtool_op_set_sg(dev, data);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int nv_get_stats_count(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (np->driver_data & DEV_HAS_STATISTICS)
+ return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
+ else
+ return 0;
+}
+
+static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ /* update stats */
+ nv_do_stats_poll((unsigned long)dev);
+
+ memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64));
+}
+
+static int nv_self_test_count(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (np->driver_data & DEV_HAS_TEST_EXTENDED)
+ return NV_TEST_COUNT_EXTENDED;
+ else
+ return NV_TEST_COUNT_BASE;
+}
+
+static int nv_link_test(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ int mii_status;
+
+ mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+ mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+
+ /* check phy link status */
+ if (!(mii_status & BMSR_LSTATUS))
+ return 0;
+ else
+ return 1;
+}
+
+static int nv_register_test(struct net_device *dev)
+{
+ u8 __iomem *base = get_hwbase(dev);
+ int i = 0;
+ u32 orig_read, new_read;
+
+ do {
+ orig_read = readl(base + nv_registers_test[i].reg);
+
+ /* xor with mask to toggle bits */
+ orig_read ^= nv_registers_test[i].mask;
+
+ writel(orig_read, base + nv_registers_test[i].reg);
+
+ new_read = readl(base + nv_registers_test[i].reg);
+
+ if ((new_read & nv_registers_test[i].mask) != (orig_read & nv_registers_test[i].mask))
+ return 0;
+
+ /* restore original value */
+ orig_read ^= nv_registers_test[i].mask;
+ writel(orig_read, base + nv_registers_test[i].reg);
+
+ } while (nv_registers_test[++i].reg != 0);
+
+ return 1;
+}
+
+static int nv_interrupt_test(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ int ret = 1;
+ int testcnt;
+ u32 save_msi_flags, save_poll_interval = 0;
+
+ if (netif_running(dev)) {
+ /* free current irq */
+ nv_free_irq(dev);
+ save_poll_interval = readl(base+NvRegPollingInterval);
+ }
+
+ /* flag to test interrupt handler */
+ np->intr_test = 0;
+
+ /* setup test irq */
+ save_msi_flags = np->msi_flags;
+ np->msi_flags &= ~NV_MSI_X_VECTORS_MASK;
+ np->msi_flags |= 0x001; /* setup 1 vector */
+ if (nv_request_irq(dev, 1))
+ return 0;
+
+ /* setup timer interrupt */
+ writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval);
+ writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
+
+ nv_enable_hw_interrupts(dev, NVREG_IRQ_TIMER);
+
+ /* wait for at least one interrupt */
+ msleep(100);
+
+ spin_lock_irq(&np->lock);
+
+ /* flag should be set within ISR */
+ testcnt = np->intr_test;
+ if (!testcnt)
+ ret = 2;
+
+ nv_disable_hw_interrupts(dev, NVREG_IRQ_TIMER);
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ else
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+
spin_unlock_irq(&np->lock);
+ nv_free_irq(dev);
+
+ np->msi_flags = save_msi_flags;
+
+ if (netif_running(dev)) {
+ writel(save_poll_interval, base + NvRegPollingInterval);
+ writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
+ /* restore original irq */
+ if (nv_request_irq(dev, 0))
+ return 0;
+ }
+
return ret;
}
+static int nv_loopback_test(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ struct sk_buff *tx_skb, *rx_skb;
+ dma_addr_t test_dma_addr;
+ u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+ u32 Flags;
+ int len, i, pkt_len;
+ u8 *pkt_data;
+ u32 filter_flags = 0;
+ u32 misc1_flags = 0;
+ int ret = 1;
+
+ if (netif_running(dev)) {
+ nv_disable_irq(dev);
+ filter_flags = readl(base + NvRegPacketFilterFlags);
+ misc1_flags = readl(base + NvRegMisc1);
+ } else {
+ nv_txrx_reset(dev);
+ }
+
+ /* reinit driver view of the rx queue */
+ set_bufsize(dev);
+ nv_init_ring(dev);
+
+ /* setup hardware for loopback */
+ writel(NVREG_MISC1_FORCE, base + NvRegMisc1);
+ writel(NVREG_PFF_ALWAYS | NVREG_PFF_LOOPBACK, base + NvRegPacketFilterFlags);
+
+ /* reinit nic view of the rx queue */
+ writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+ setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+ pci_push(base);
+
+ /* restart rx engine */
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+
+ /* setup packet for tx */
+ pkt_len = ETH_DATA_LEN;
+ tx_skb = dev_alloc_skb(pkt_len);
+ pkt_data = skb_put(tx_skb, pkt_len);
+ for (i = 0; i < pkt_len; i++)
+ pkt_data[i] = (u8)(i & 0xff);
+ test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data,
+ tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
+ np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ } else {
+ np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
+ np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+ np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ }
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ pci_push(get_hwbase(dev));
+
+ msleep(500);
+
+ /* check for rx of the packet */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
+ len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
+
+ } else {
+ Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
+ len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
+ }
+
+ if (Flags & NV_RX_AVAIL) {
+ ret = 0;
+ } else if (np->desc_ver == DESC_VER_1) {
+ if (Flags & NV_RX_ERROR)
+ ret = 0;
+ } else {
+ if (Flags & NV_RX2_ERROR) {
+ ret = 0;
+ }
+ }
+
+ if (ret) {
+ if (len != pkt_len) {
+ ret = 0;
+ dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
+ dev->name, len, pkt_len);
+ } else {
+ rx_skb = np->rx_skbuff[0];
+ for (i = 0; i < pkt_len; i++) {
+ if (rx_skb->data[i] != (u8)(i & 0xff)) {
+ ret = 0;
+ dprintk(KERN_DEBUG "%s: loopback pattern check failed on byte %d\n",
+ dev->name, i);
+ break;
+ }
+ }
+ }
+ } else {
+ dprintk(KERN_DEBUG "%s: loopback - did not receive test packet\n", dev->name);
+ }
+
+ pci_unmap_page(np->pci_dev, test_dma_addr,
+ tx_skb->end-tx_skb->data,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(tx_skb);
+
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ nv_txrx_reset(dev);
+ /* drain rx queue */
+ nv_drain_rx(dev);
+ nv_drain_tx(dev);
+
+ if (netif_running(dev)) {
+ writel(misc1_flags, base + NvRegMisc1);
+ writel(filter_flags, base + NvRegPacketFilterFlags);
+ nv_enable_irq(dev);
+ }
+
+ return ret;
+}
+
+static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 *buffer)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ int result;
+ memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64));
+
+ if (!nv_link_test(dev)) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ buffer[0] = 1;
+ }
+
+ if (test->flags & ETH_TEST_FL_OFFLINE) {
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock_irq(&np->lock);
+ nv_disable_hw_interrupts(dev, np->irqmask);
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ } else {
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+ }
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ nv_txrx_reset(dev);
+ /* drain rx queue */
+ nv_drain_rx(dev);
+ nv_drain_tx(dev);
+ spin_unlock_irq(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ }
+
+ if (!nv_register_test(dev)) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ buffer[1] = 1;
+ }
+
+ result = nv_interrupt_test(dev);
+ if (result != 1) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ buffer[2] = 1;
+ }
+ if (result == 0) {
+ /* bail out */
+ return;
+ }
+
+ if (!nv_loopback_test(dev)) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ buffer[3] = 1;
+ }
+
+ if (netif_running(dev)) {
+ /* reinit driver view of the rx queue */
+ set_bufsize(dev);
+ if (nv_init_ring(dev)) {
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ }
+ /* reinit nic view of the rx queue */
+ writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+ setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+ pci_push(base);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ pci_push(base);
+ /* restart rx engine */
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ netif_start_queue(dev);
+ nv_enable_hw_interrupts(dev, np->irqmask);
+ }
+ }
+}
+
+static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str));
+ break;
+ case ETH_SS_TEST:
+ memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str));
+ break;
+ }
+}
+
static struct ethtool_ops ops = {
.get_drvinfo = nv_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -2542,6 +3815,23 @@ static struct ethtool_ops ops = {
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
.get_perm_addr = ethtool_op_get_perm_addr,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = nv_set_tso,
+ .get_ringparam = nv_get_ringparam,
+ .set_ringparam = nv_set_ringparam,
+ .get_pauseparam = nv_get_pauseparam,
+ .set_pauseparam = nv_set_pauseparam,
+ .get_rx_csum = nv_get_rx_csum,
+ .set_rx_csum = nv_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = nv_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = nv_set_sg,
+ .get_strings = nv_get_strings,
+ .get_stats_count = nv_get_stats_count,
+ .get_ethtool_stats = nv_get_ethtool_stats,
+ .self_test_count = nv_self_test_count,
+ .self_test = nv_self_test,
};
static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
@@ -2572,32 +3862,6 @@ static void nv_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
/* nothing to do */
};
-static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask)
-{
- u8 __iomem *base = get_hwbase(dev);
- int i;
- u32 msixmap = 0;
-
- /* Each interrupt bit can be mapped to a MSIX vector (4 bits).
- * MSIXMap0 represents the first 8 interrupts and MSIXMap1 represents
- * the remaining 8 interrupts.
- */
- for (i = 0; i < 8; i++) {
- if ((irqmask >> i) & 0x1) {
- msixmap |= vector << (i << 2);
- }
- }
- writel(readl(base + NvRegMSIXMap0) | msixmap, base + NvRegMSIXMap0);
-
- msixmap = 0;
- for (i = 0; i < 8; i++) {
- if ((irqmask >> (i + 8)) & 0x1) {
- msixmap |= vector << (i << 2);
- }
- }
- writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1);
-}
-
static int nv_open(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
@@ -2608,6 +3872,8 @@ static int nv_open(struct net_device *dev)
dprintk(KERN_DEBUG "nv_open: begin\n");
/* 1) erase previous misconfiguration */
+ if (np->driver_data & DEV_HAS_POWER_CNTRL)
+ nv_mac_reset(dev);
/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
@@ -2620,6 +3886,9 @@ static int nv_open(struct net_device *dev)
writel(0, base + NvRegAdapterControl);
+ if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
+ writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame);
+
/* 2) initialize descriptor rings */
set_bufsize(dev);
oom = nv_init_ring(dev);
@@ -2636,7 +3905,7 @@ static int nv_open(struct net_device *dev)
/* 4) give hw rings */
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
+ writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
/* 5) continue setup */
@@ -2678,7 +3947,8 @@ static int nv_open(struct net_device *dev)
base + NvRegAdapterControl);
writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed);
writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4);
- writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags);
+ if (np->wolenabled)
+ writel(NVREG_WAKEUPFLAGS_ENABLE , base + NvRegWakeUpFlags);
i = readl(base + NvRegPowerState);
if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0)
@@ -2688,86 +3958,18 @@ static int nv_open(struct net_device *dev)
udelay(10);
writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState);
- writel(0, base + NvRegIrqMask);
+ nv_disable_hw_interrupts(dev, np->irqmask);
pci_push(base);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
- if (np->msi_flags & NV_MSI_X_CAPABLE) {
- for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
- np->msi_x_entry[i].entry = i;
- }
- if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) {
- np->msi_flags |= NV_MSI_X_ENABLED;
- if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) {
- /* Request irq for rx handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret);
- pci_disable_msix(np->pci_dev);
- np->msi_flags &= ~NV_MSI_X_ENABLED;
- goto out_drain;
- }
- /* Request irq for tx handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret);
- pci_disable_msix(np->pci_dev);
- np->msi_flags &= ~NV_MSI_X_ENABLED;
- goto out_drain;
- }
- /* Request irq for link and timer handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret);
- pci_disable_msix(np->pci_dev);
- np->msi_flags &= ~NV_MSI_X_ENABLED;
- goto out_drain;
- }
-
- /* map interrupts to their respective vector */
- writel(0, base + NvRegMSIXMap0);
- writel(0, base + NvRegMSIXMap1);
- set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL);
- set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL);
- set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
- } else {
- /* Request irq for all interrupts */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
- pci_disable_msix(np->pci_dev);
- np->msi_flags &= ~NV_MSI_X_ENABLED;
- goto out_drain;
- }
-
- /* map interrupts to vector 0 */
- writel(0, base + NvRegMSIXMap0);
- writel(0, base + NvRegMSIXMap1);
- }
- }
- }
- if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
- if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
- np->msi_flags |= NV_MSI_ENABLED;
- if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
- pci_disable_msi(np->pci_dev);
- np->msi_flags &= ~NV_MSI_ENABLED;
- goto out_drain;
- }
-
- /* map interrupts to vector 0 */
- writel(0, base + NvRegMSIMap0);
- writel(0, base + NvRegMSIMap1);
- /* enable msi vector 0 */
- writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
- }
- }
- if (ret != 0) {
- if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0)
- goto out_drain;
+ if (nv_request_irq(dev, 0)) {
+ goto out_drain;
}
/* ask for interrupts */
- writel(np->irqmask, base + NvRegIrqMask);
+ nv_enable_hw_interrupts(dev, np->irqmask);
spin_lock_irq(&np->lock);
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
@@ -2799,6 +4001,11 @@ static int nv_open(struct net_device *dev)
}
if (oom)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+
+ /* start statistics timer */
+ if (np->driver_data & DEV_HAS_STATISTICS)
+ mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
+
spin_unlock_irq(&np->lock);
return 0;
@@ -2811,7 +4018,6 @@ static int nv_close(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base;
- int i;
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
@@ -2820,6 +4026,7 @@ static int nv_close(struct net_device *dev)
del_timer_sync(&np->oom_kick);
del_timer_sync(&np->nic_poll);
+ del_timer_sync(&np->stats_poll);
netif_stop_queue(dev);
spin_lock_irq(&np->lock);
@@ -2829,31 +4036,13 @@ static int nv_close(struct net_device *dev)
/* disable interrupts on the nic or we will lock up */
base = get_hwbase(dev);
- if (np->msi_flags & NV_MSI_X_ENABLED) {
- writel(np->irqmask, base + NvRegIrqMask);
- } else {
- if (np->msi_flags & NV_MSI_ENABLED)
- writel(0, base + NvRegMSIIrqMask);
- writel(0, base + NvRegIrqMask);
- }
+ nv_disable_hw_interrupts(dev, np->irqmask);
pci_push(base);
dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);
spin_unlock_irq(&np->lock);
- if (np->msi_flags & NV_MSI_X_ENABLED) {
- for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
- free_irq(np->msi_x_entry[i].vector, dev);
- }
- pci_disable_msix(np->pci_dev);
- np->msi_flags &= ~NV_MSI_X_ENABLED;
- } else {
- free_irq(np->pci_dev->irq, dev);
- if (np->msi_flags & NV_MSI_ENABLED) {
- pci_disable_msi(np->pci_dev);
- np->msi_flags &= ~NV_MSI_ENABLED;
- }
- }
+ nv_free_irq(dev);
drain_ring(dev);
@@ -2878,6 +4067,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
unsigned long addr;
u8 __iomem *base;
int err, i;
+ u32 powerstate;
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -2896,6 +4086,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
init_timer(&np->nic_poll);
np->nic_poll.data = (unsigned long) dev;
np->nic_poll.function = &nv_do_nic_poll; /* timer handler */
+ init_timer(&np->stats_poll);
+ np->stats_poll.data = (unsigned long) dev;
+ np->stats_poll.function = &nv_do_stats_poll; /* timer handler */
err = pci_enable_device(pci_dev);
if (err) {
@@ -2910,6 +4103,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (err < 0)
goto out_disable;
+ if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+ np->register_size = NV_PCI_REGSZ_VER2;
+ else
+ np->register_size = NV_PCI_REGSZ_VER1;
+
err = -EINVAL;
addr = 0;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -2918,7 +4116,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
pci_resource_len(pci_dev, i),
pci_resource_flags(pci_dev, i));
if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
- pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) {
+ pci_resource_len(pci_dev, i) >= np->register_size) {
addr = pci_resource_start(pci_dev, i);
break;
}
@@ -2929,24 +4127,27 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_relreg;
}
+ /* copy of driver data */
+ np->driver_data = id->driver_data;
+
/* handle different descriptor versions */
if (id->driver_data & DEV_HAS_HIGH_DMA) {
/* packet format 3: supports 40-bit addressing */
np->desc_ver = DESC_VER_3;
- if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {
- printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
- pci_name(pci_dev));
- } else {
- if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
- printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n",
- pci_name(pci_dev));
- goto out_relreg;
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
+ if (dma_64bit) {
+ if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {
+ printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
+ pci_name(pci_dev));
} else {
dev->features |= NETIF_F_HIGHDMA;
printk(KERN_INFO "forcedeth: using HIGHDMA\n");
}
+ if (pci_set_consistent_dma_mask(pci_dev, DMA_39BIT_MASK)) {
+ printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed, using 32-bit ring buffers for device %s.\n",
+ pci_name(pci_dev));
+ }
}
- np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
/* packet format 2: supports jumbo frames */
np->desc_ver = DESC_VER_2;
@@ -2978,36 +4179,59 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
}
np->msi_flags = 0;
- if ((id->driver_data & DEV_HAS_MSI) && !disable_msi) {
+ if ((id->driver_data & DEV_HAS_MSI) && msi) {
np->msi_flags |= NV_MSI_CAPABLE;
}
- if ((id->driver_data & DEV_HAS_MSI_X) && !disable_msix) {
+ if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
np->msi_flags |= NV_MSI_X_CAPABLE;
}
+ np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
+ if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) {
+ np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ;
+ }
+
+
err = -ENOMEM;
- np->base = ioremap(addr, NV_PCI_REGSZ);
+ np->base = ioremap(addr, np->register_size);
if (!np->base)
goto out_relreg;
dev->base_addr = (unsigned long)np->base;
dev->irq = pci_dev->irq;
+ np->rx_ring_size = RX_RING_DEFAULT;
+ np->tx_ring_size = TX_RING_DEFAULT;
+ np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
+ np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
+
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
- sizeof(struct ring_desc) * (RX_RING + TX_RING),
+ sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
&np->ring_addr);
if (!np->rx_ring.orig)
goto out_unmap;
- np->tx_ring.orig = &np->rx_ring.orig[RX_RING];
+ np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
} else {
np->rx_ring.ex = pci_alloc_consistent(pci_dev,
- sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
+ sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
&np->ring_addr);
if (!np->rx_ring.ex)
goto out_unmap;
- np->tx_ring.ex = &np->rx_ring.ex[RX_RING];
+ np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
+ np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
+ np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
+ np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
+ np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
+ np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
+ if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+ goto out_freering;
+ memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
+ memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
+ memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
+ memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
+ memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
@@ -3062,6 +4286,20 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
+ if (id->driver_data & DEV_HAS_POWER_CNTRL) {
+ u8 revision_id;
+ pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id);
+
+ /* take phy and nic out of low power mode */
+ powerstate = readl(base + NvRegPowerState2);
+ powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
+ if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+ id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) &&
+ revision_id >= 0xA3)
+ powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
+ writel(powerstate, base + NvRegPowerState2);
+ }
+
if (np->desc_ver == DESC_VER_1) {
np->tx_flags = NV_TX_VALID;
} else {
@@ -3115,9 +4353,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (i == 33) {
printk(KERN_INFO "%s: open: Could not find a valid PHY.\n",
pci_name(pci_dev));
- goto out_freering;
+ goto out_error;
}
-
+
/* reset it */
phy_init(dev);
@@ -3129,7 +4367,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
err = register_netdev(dev);
if (err) {
printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err);
- goto out_freering;
+ goto out_error;
}
printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n",
dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device,
@@ -3137,14 +4375,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
return 0;
-out_freering:
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
- np->rx_ring.orig, np->ring_addr);
- else
- pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
- np->rx_ring.ex, np->ring_addr);
+out_error:
pci_set_drvdata(pci_dev, NULL);
+out_freering:
+ free_rings(dev);
out_unmap:
iounmap(get_hwbase(dev));
out_relreg:
@@ -3160,15 +4394,11 @@ out:
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
- struct fe_priv *np = netdev_priv(dev);
unregister_netdev(dev);
/* free all structures */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr);
- else
- pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr);
+ free_rings(dev);
iounmap(get_hwbase(dev));
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
@@ -3223,19 +4453,51 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP61 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP61 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP61 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP61 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP65 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP65 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP65 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
+ },
+ { /* MCP65 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED,
},
{0,},
};
@@ -3265,10 +4527,12 @@ module_param(optimization_mode, int, 0);
MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
module_param(poll_interval, int, 0);
MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
-module_param(disable_msi, int, 0);
-MODULE_PARM_DESC(disable_msi, "Disable MSI interrupts by setting to 1.");
-module_param(disable_msix, int, 0);
-MODULE_PARM_DESC(disable_msix, "Disable MSIX interrupts by setting to 1.");
+module_param(msi, int, 0);
+MODULE_PARM_DESC(msi, "MSI interrupts are enabled by setting to 1 and disabled by setting to 0.");
+module_param(msix, int, 0);
+MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0.");
+module_param(dma_64bit, int, 0);
+MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0.");
MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 771e25d8c417..218d31764c52 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -210,7 +210,8 @@ static int gfar_probe(struct platform_device *pdev)
goto regs_fail;
}
- spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->txlock);
+ spin_lock_init(&priv->rxlock);
platform_set_drvdata(pdev, dev);
@@ -515,11 +516,13 @@ void stop_gfar(struct net_device *dev)
phy_stop(priv->phydev);
/* Lock it down */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
gfar_halt(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
/* Free the IRQs */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -605,14 +608,15 @@ void gfar_start(struct net_device *dev)
tempval |= DMACTRL_INIT_SETTINGS;
gfar_write(&priv->regs->dmactrl, tempval);
- /* Clear THLT, so that the DMA starts polling now */
- gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
-
/* Make sure we aren't stopped */
tempval = gfar_read(&priv->regs->dmactrl);
tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
gfar_write(&priv->regs->dmactrl, tempval);
+ /* Clear THLT/RHLT, so that the DMA starts polling now */
+ gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+ gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
+
/* Unmask the interrupts we look for */
gfar_write(&regs->imask, IMASK_DEFAULT);
}
@@ -928,12 +932,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct txfcb *fcb = NULL;
struct txbd8 *txbdp;
u16 status;
+ unsigned long flags;
/* Update transmit stats */
priv->stats.tx_bytes += skb->len;
/* Lock priv now */
- spin_lock_irq(&priv->lock);
+ spin_lock_irqsave(&priv->txlock, flags);
/* Point at the first free tx descriptor */
txbdp = priv->cur_tx;
@@ -1004,7 +1009,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
/* Unlock priv */
- spin_unlock_irq(&priv->lock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
return 0;
}
@@ -1049,7 +1054,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
unsigned long flags;
u32 tempval;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->rxlock, flags);
priv->vlgrp = grp;
@@ -1076,7 +1081,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
gfar_write(&priv->regs->rctrl, tempval);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
}
@@ -1085,12 +1090,12 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
struct gfar_private *priv = netdev_priv(dev);
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->rxlock, flags);
if (priv->vlgrp)
priv->vlgrp->vlan_devices[vid] = NULL;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
}
@@ -1179,7 +1184,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
/* Lock priv */
- spin_lock(&priv->lock);
+ spin_lock(&priv->txlock);
bdp = priv->dirty_tx;
while ((bdp->status & TXBD_READY) == 0) {
/* If dirty_tx and cur_tx are the same, then either the */
@@ -1224,7 +1229,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
else
gfar_write(&priv->regs->txic, 0);
- spin_unlock(&priv->lock);
+ spin_unlock(&priv->txlock);
return IRQ_HANDLED;
}
@@ -1305,9 +1310,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
-
#ifdef CONFIG_GFAR_NAPI
u32 tempval;
+#else
+ unsigned long flags;
#endif
/* Clear IEVENT, so rx interrupt isn't called again
@@ -1330,7 +1336,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
}
#else
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->rxlock, flags);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
/* If we are coalescing interrupts, update the timer */
@@ -1341,7 +1347,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
else
gfar_write(&priv->regs->rxic, 0);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
#endif
return IRQ_HANDLED;
@@ -1490,13 +1496,6 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
/* Update the current rxbd pointer to be the next one */
priv->cur_rx = bdp;
- /* If no packets have arrived since the
- * last one we processed, clear the IEVENT RX and
- * BSY bits so that another interrupt won't be
- * generated when we set IMASK */
- if (bdp->status & RXBD_EMPTY)
- gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
-
return howmany;
}
@@ -1516,7 +1515,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
rx_work_limit -= howmany;
*budget -= howmany;
- if (rx_work_limit >= 0) {
+ if (rx_work_limit > 0) {
netif_rx_complete(dev);
/* Clear the halt bit in RSTAT */
@@ -1533,7 +1532,8 @@ static int gfar_poll(struct net_device *dev, int *budget)
gfar_write(&priv->regs->rxic, 0);
}
- return (rx_work_limit < 0) ? 1 : 0;
+ /* Return 1 if there's more work to do */
+ return (rx_work_limit > 0) ? 0 : 1;
}
#endif
@@ -1629,7 +1629,7 @@ static void adjust_link(struct net_device *dev)
struct phy_device *phydev = priv->phydev;
int new_state = 0;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
if (phydev->link) {
u32 tempval = gfar_read(&regs->maccfg2);
u32 ecntrl = gfar_read(&regs->ecntrl);
@@ -1694,7 +1694,7 @@ static void adjust_link(struct net_device *dev)
if (new_state && netif_msg_link(priv))
phy_print_status(phydev);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->txlock, flags);
}
/* Update the hash table based on the current list of multicast
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index d37d5401be6e..127c98cf3336 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -656,43 +656,62 @@ struct gfar {
* the buffer descriptor determines the actual condition.
*/
struct gfar_private {
- /* pointers to arrays of skbuffs for tx and rx */
+ /* Fields controlled by TX lock */
+ spinlock_t txlock;
+
+ /* Pointer to the array of skbuffs */
struct sk_buff ** tx_skbuff;
- struct sk_buff ** rx_skbuff;
- /* indices pointing to the next free sbk in skb arrays */
+ /* next free skb in the array */
u16 skb_curtx;
- u16 skb_currx;
- /* index of the first skb which hasn't been transmitted
- * yet. */
+ /* First skb in line to be transmitted */
u16 skb_dirtytx;
/* Configuration info for the coalescing features */
unsigned char txcoalescing;
unsigned short txcount;
unsigned short txtime;
+
+ /* Buffer descriptor pointers */
+ struct txbd8 *tx_bd_base; /* First tx buffer descriptor */
+ struct txbd8 *cur_tx; /* Next free ring entry */
+ struct txbd8 *dirty_tx; /* First buffer in line
+ to be transmitted */
+ unsigned int tx_ring_size;
+
+ /* RX Locked fields */
+ spinlock_t rxlock;
+
+ /* skb array and index */
+ struct sk_buff ** rx_skbuff;
+ u16 skb_currx;
+
+ /* RX Coalescing values */
unsigned char rxcoalescing;
unsigned short rxcount;
unsigned short rxtime;
- /* GFAR addresses */
- struct rxbd8 *rx_bd_base; /* Base addresses of Rx and Tx Buffers */
- struct txbd8 *tx_bd_base;
+ struct rxbd8 *rx_bd_base; /* First Rx buffers */
struct rxbd8 *cur_rx; /* Next free rx ring entry */
- struct txbd8 *cur_tx; /* Next free ring entry */
- struct txbd8 *dirty_tx; /* The Ring entry to be freed. */
- struct gfar __iomem *regs; /* Pointer to the GFAR memory mapped Registers */
- u32 __iomem *hash_regs[16];
- int hash_width;
- struct net_device_stats stats; /* linux network statistics */
- struct gfar_extra_stats extra_stats;
- spinlock_t lock;
+
+ /* RX parameters */
+ unsigned int rx_ring_size;
unsigned int rx_buffer_size;
unsigned int rx_stash_size;
unsigned int rx_stash_index;
- unsigned int tx_ring_size;
- unsigned int rx_ring_size;
+
+ struct vlan_group *vlgrp;
+
+ /* Unprotected fields */
+ /* Pointer to the GFAR memory mapped Registers */
+ struct gfar __iomem *regs;
+
+ /* Hash registers and their width */
+ u32 __iomem *hash_regs[16];
+ int hash_width;
+
+ /* global parameters */
unsigned int fifo_threshold;
unsigned int fifo_starve;
unsigned int fifo_starve_off;
@@ -702,13 +721,15 @@ struct gfar_private {
extended_hash:1,
bd_stash_en:1;
unsigned short padding;
- struct vlan_group *vlgrp;
- /* Info structure initialized by board setup code */
+
unsigned int interruptTransmit;
unsigned int interruptReceive;
unsigned int interruptError;
+
+ /* info structure initialized by platform code */
struct gianfar_platform_data *einfo;
+ /* PHY stuff */
struct phy_device *phydev;
struct mii_bus *mii_bus;
int oldspeed;
@@ -716,6 +737,10 @@ struct gfar_private {
int oldlink;
uint32_t msg_enable;
+
+ /* Network Statistics */
+ struct net_device_stats stats;
+ struct gfar_extra_stats extra_stats;
};
static inline u32 gfar_read(volatile unsigned __iomem *addr)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 5de7b2e259dc..d69698c695ef 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -455,10 +455,14 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
/* Halt TX and RX, and process the frames which
* have already been received */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
+
gfar_halt(dev);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
- spin_unlock_irqrestore(&priv->lock, flags);
+
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
@@ -488,10 +492,14 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
/* Halt TX and RX, and process the frames which
* have already been received */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
+
gfar_halt(dev);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
- spin_unlock_irqrestore(&priv->lock, flags);
+
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
@@ -523,7 +531,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
return -EOPNOTSUPP;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
gfar_halt(dev);
if (data)
@@ -532,7 +540,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
dev->features &= ~NETIF_F_IP_CSUM;
gfar_start(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->txlock, flags);
return 0;
}
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index 51ef181b1368..a6d5c43199cb 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -82,7 +82,7 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev,
else
return count;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->rxlock, flags);
/* Set the new stashing value */
priv->bd_stash_en = new_setting;
@@ -96,7 +96,7 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev,
gfar_write(&priv->regs->attr, temp);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
return count;
}
@@ -118,7 +118,7 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
u32 temp;
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->rxlock, flags);
if (length > priv->rx_buffer_size)
return count;
@@ -142,7 +142,7 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
gfar_write(&priv->regs->attr, temp);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
return count;
}
@@ -166,7 +166,7 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
u32 temp;
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->rxlock, flags);
if (index > priv->rx_stash_size)
return count;
@@ -180,7 +180,7 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
temp |= ATTRELI_EI(index);
gfar_write(&priv->regs->attreli, flags);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->rxlock, flags);
return count;
}
@@ -205,7 +205,7 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
if (length > GFAR_MAX_FIFO_THRESHOLD)
return count;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
priv->fifo_threshold = length;
@@ -214,7 +214,7 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
temp |= length;
gfar_write(&priv->regs->fifo_tx_thr, temp);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->txlock, flags);
return count;
}
@@ -240,7 +240,7 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
if (num > GFAR_MAX_FIFO_STARVE)
return count;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
priv->fifo_starve = num;
@@ -249,7 +249,7 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve, temp);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->txlock, flags);
return count;
}
@@ -274,7 +274,7 @@ static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev,
if (num > GFAR_MAX_FIFO_STARVE_OFF)
return count;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->txlock, flags);
priv->fifo_starve_off = num;
@@ -283,7 +283,7 @@ static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev,
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->txlock, flags);
return count;
}
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 102c1f0b90da..d12605f0ac7c 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr_ax25 *sa = addr;
- spin_lock_irq(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
- spin_unlock_irq(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
return 0;
}
@@ -767,9 +767,9 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
break;
}
- spin_lock_irq(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
- spin_unlock_irq(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
err = 0;
break;
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 79a8fbcf5f93..0d5fccc984bb 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -582,7 +582,6 @@ static int __init setup_adapter(int card_base, int type, int n)
INIT_WORK(&priv->rx_work, rx_bh, priv);
dev->priv = priv;
sprintf(dev->name, "dmascc%i", 2 * n + i);
- SET_MODULE_OWNER(dev);
dev->base_addr = card_base;
dev->irq = irq;
dev->open = scc_open;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d81a8e1eeb8d..3ebbbe56b6e9 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr_ax25 *sa = addr;
- spin_lock_irq(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
- spin_unlock_irq(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
return 0;
}
@@ -886,9 +886,9 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
break;
}
- spin_lock_irq(&dev->xmit_lock);
+ netif_tx_lock_bh(dev);
memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
- spin_unlock_irq(&dev->xmit_lock);
+ netif_tx_unlock_bh(dev);
err = 0;
break;
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 6ace0e914fd1..5927784df3f9 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1550,7 +1550,6 @@ static unsigned char ax25_nocall[AX25_ADDR_LEN] =
static void scc_net_setup(struct net_device *dev)
{
- SET_MODULE_OWNER(dev);
dev->tx_queue_len = 16; /* should be enough... */
dev->open = scc_net_open;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index fe22479eb202..b49884048caa 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -1098,7 +1098,6 @@ static void yam_setup(struct net_device *dev)
dev->base_addr = yp->iobase;
dev->irq = yp->irq;
- SET_MODULE_OWNER(dev);
dev->open = yam_open;
dev->stop = yam_close;
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 0d7a6250e346..e26a3e407d70 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -446,7 +446,7 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
+int __init
init_module(void)
{
struct net_device *dev;
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index cf9fb3698a6b..551a71b3c5fd 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -384,7 +384,7 @@ hp_block_output(struct net_device *dev, int count,
}
/* This function resets the ethercard if something screws up. */
-static void
+static void __init
hp_init_card(struct net_device *dev)
{
int irq = dev->irq;
@@ -409,7 +409,7 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
+int __init
init_module(void)
{
struct net_device *dev;
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 01ad904215a1..51fd51609ea9 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -1,4 +1,4 @@
-/*
+/*
net-3-driver for the IBM LAN Adapter/A
This is an extension to the Linux operating system, and is covered by the
@@ -11,9 +11,9 @@ This driver is based both on the SK_MCA driver, which is itself based on the
SK_G16 and 3C523 driver.
paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
+ 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
Hans-Peter Messmer for the basic Microchannel stuff
-
+
'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
for help on Ethernet driver programming
@@ -27,14 +27,14 @@ paper sources:
special acknowledgements to:
- Bob Eager for helping me out with documentation from IBM
- - Jim Shorney for his endless patience with me while I was using
+ - Jim Shorney for his endless patience with me while I was using
him as a beta tester to trace down the address filter bug ;-)
Missing things:
-> set debug level via ioctl instead of compile-time switches
-> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
+ assumptions about which things changed with which kernel version
are probably nonsense
History:
@@ -275,7 +275,7 @@ static void InitDscrs(struct net_device *dev)
priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
-
+
for (z = 0; z < priv->rxbufcnt; z++) {
rra.startlo = baddr;
rra.starthi = 0;
@@ -570,7 +570,7 @@ static void irqrx_handler(struct net_device *dev)
lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
- /* iron out upper word halves of fields we use - SONIC will duplicate
+ /* iron out upper word halves of fields we use - SONIC will duplicate
bits 0..15 to 16..31 */
rda.status &= 0xffff;
@@ -836,9 +836,9 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
memcpy_toio(priv->base + baddr, skb->data, skb->len);
- /* copy filler into RAM - in case we're filling up...
+ /* copy filler into RAM - in case we're filling up...
we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger...
+ since the buffer is far larger...
Sorry Linus for the filler string but I couldn't resist ;-) */
if (tmplen > skb->len) {
@@ -952,7 +952,7 @@ static int ibmlana_probe(struct net_device *dev)
priv->realirq = irq;
priv->medium = medium;
spin_lock_init(&priv->lock);
-
+
/* set base + irq for this device (irq not allocated so far) */
diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
index 458ee226e537..6b58bab9e308 100644
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ibmlana.h
@@ -17,7 +17,7 @@
/* media enumeration - defined in a way that it fits onto the LAN/A's
POS registers... */
-typedef enum {
+typedef enum {
Media_10BaseT, Media_10Base5,
Media_Unknown, Media_10Base2, Media_Count
} ibmlana_medium;
@@ -27,7 +27,7 @@ typedef enum {
typedef struct {
unsigned int slot; /* MCA-Slot-# */
struct net_device_stats stat; /* packet statistics */
- int realirq; /* memorizes actual IRQ, even when
+ int realirq; /* memorizes actual IRQ, even when
currently not allocated */
ibmlana_medium medium; /* physical cannector */
u32 tdastart, txbufstart, /* addresses */
@@ -41,7 +41,7 @@ typedef struct {
spinlock_t lock;
} ibmlana_priv;
-/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
+/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
a full 64K I/O range... */
#define IBM_LANA_IORANGE 0xa0
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 52d01027d9e7..666346f6469e 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -24,7 +24,7 @@
/* for use with IBM i/pSeries LPAR Linux. It utilizes the logical LAN */
/* option of the RS/6000 Platform Architechture to interface with virtual */
/* ethernet NICs that are presented to the partition by the hypervisor. */
-/* */
+/* */
/**************************************************************************/
/*
TODO:
@@ -79,7 +79,7 @@
#else
#define ibmveth_debug_printk_no_adapter(fmt, args...)
#define ibmveth_debug_printk(fmt, args...)
-#define ibmveth_assert(expr)
+#define ibmveth_assert(expr)
#endif
static int ibmveth_open(struct net_device *dev);
@@ -96,6 +96,7 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+static struct kobj_type ktype_veth_pool;
#ifdef CONFIG_PROC_FS
#define IBMVETH_PROC_DIR "net/ibmveth"
@@ -133,12 +134,13 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
}
/* setup the initial settings for a buffer pool */
-static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size)
+static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
{
pool->size = pool_size;
pool->index = pool_index;
pool->buff_size = buff_size;
pool->threshold = pool_size / 2;
+ pool->active = pool_active;
}
/* allocate and setup an buffer pool - called during open */
@@ -146,13 +148,13 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
{
int i;
- pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL);
+ pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL);
if(!pool->free_map) {
return -1;
}
- pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL);
+ pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL);
if(!pool->dma_addr) {
kfree(pool->free_map);
pool->free_map = NULL;
@@ -180,7 +182,6 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
atomic_set(&pool->available, 0);
pool->producer_index = 0;
pool->consumer_index = 0;
- pool->active = 0;
return 0;
}
@@ -214,7 +215,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
free_index = pool->consumer_index++ % pool->size;
index = pool->free_map[free_index];
-
+
ibmveth_assert(index != IBM_VETH_INVALID_MAP);
ibmveth_assert(pool->skbuff[index] == NULL);
@@ -231,10 +232,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
desc.desc = 0;
desc.fields.valid = 1;
desc.fields.length = pool->buff_size;
- desc.fields.address = dma_addr;
+ desc.fields.address = dma_addr;
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
-
+
if(lpar_rc != H_SUCCESS) {
pool->free_map[free_index] = index;
pool->skbuff[index] = NULL;
@@ -250,13 +251,13 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
adapter->replenish_add_buff_success++;
}
}
-
+
mb();
atomic_add(buffers_added, &(pool->available));
}
/* replenish routine */
-static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
+static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
{
int i;
@@ -264,7 +265,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
for(i = 0; i < IbmVethNumBufferPools; i++)
if(adapter->rx_buff_pool[i].active)
- ibmveth_replenish_buffer_pool(adapter,
+ ibmveth_replenish_buffer_pool(adapter,
&adapter->rx_buff_pool[i]);
adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
@@ -301,7 +302,6 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm
kfree(pool->skbuff);
pool->skbuff = NULL;
}
- pool->active = 0;
}
/* remove a buffer from a pool */
@@ -372,7 +372,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index];
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
-
+
if(lpar_rc != H_SUCCESS) {
ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc);
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
@@ -407,7 +407,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
}
free_page((unsigned long)adapter->buffer_list_addr);
adapter->buffer_list_addr = NULL;
- }
+ }
if(adapter->filter_list_addr != NULL) {
if(!dma_mapping_error(adapter->filter_list_dma)) {
@@ -433,7 +433,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
}
for(i = 0; i<IbmVethNumBufferPools; i++)
- ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[i]);
+ if (adapter->rx_buff_pool[i].active)
+ ibmveth_free_buffer_pool(adapter,
+ &adapter->rx_buff_pool[i]);
}
static int ibmveth_open(struct net_device *netdev)
@@ -450,10 +452,10 @@ static int ibmveth_open(struct net_device *netdev)
for(i = 0; i<IbmVethNumBufferPools; i++)
rxq_entries += adapter->rx_buff_pool[i].size;
-
+
adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
-
+
if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
ibmveth_cleanup(adapter);
@@ -489,9 +491,6 @@ static int ibmveth_open(struct net_device *netdev)
adapter->rx_queue.num_slots = rxq_entries;
adapter->rx_queue.toggle = 1;
- /* call change_mtu to init the buffer pools based in initial mtu */
- ibmveth_change_mtu(netdev, netdev->mtu);
-
memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
mac_address = mac_address >> 16;
@@ -504,7 +503,7 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr);
-
+
lpar_rc = h_register_logical_lan(adapter->vdev->unit_address,
adapter->buffer_list_dma,
rxq_desc.desc,
@@ -519,7 +518,18 @@ static int ibmveth_open(struct net_device *netdev)
rxq_desc.desc,
mac_address);
ibmveth_cleanup(adapter);
- return -ENONET;
+ return -ENONET;
+ }
+
+ for(i = 0; i<IbmVethNumBufferPools; i++) {
+ if(!adapter->rx_buff_pool[i].active)
+ continue;
+ if (ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[i])) {
+ ibmveth_error_printk("unable to alloc pool\n");
+ adapter->rx_buff_pool[i].active = 0;
+ ibmveth_cleanup(adapter);
+ return -ENOMEM ;
+ }
}
ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq);
@@ -547,10 +557,11 @@ static int ibmveth_close(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
long lpar_rc;
-
+
ibmveth_debug_printk("close starting\n");
- netif_stop_queue(netdev);
+ if (!adapter->pool_config)
+ netif_stop_queue(netdev);
free_irq(netdev->irq, netdev);
@@ -694,7 +705,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
desc[5].desc,
correlator);
} while ((lpar_rc == H_BUSY) && (retry_count--));
-
+
if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
int i;
ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
@@ -780,7 +791,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget)
/* more work to do - return that we are not done yet */
netdev->quota -= frames_processed;
*budget -= frames_processed;
- return 1;
+ return 1;
}
/* we think we are done - reenable interrupts, then check once more to make sure we are done */
@@ -806,7 +817,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget)
}
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
+{
struct net_device *netdev = dev_instance;
struct ibmveth_adapter *adapter = netdev->priv;
unsigned long lpar_rc;
@@ -862,7 +873,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc);
}
}
-
+
/* re-enable filtering */
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastEnableFiltering,
@@ -876,46 +887,22 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
{
struct ibmveth_adapter *adapter = dev->priv;
+ int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH;
int i;
- int prev_smaller = 1;
- if ((new_mtu < 68) ||
- (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH))
+ if (new_mtu < IBMVETH_MAX_MTU)
return -EINVAL;
+ /* Look for an active buffer pool that can hold the new MTU */
for(i = 0; i<IbmVethNumBufferPools; i++) {
- int activate = 0;
- if (new_mtu > (pool_size[i] - IBMVETH_BUFF_OH)) {
- activate = 1;
- prev_smaller= 1;
- } else {
- if (prev_smaller)
- activate = 1;
- prev_smaller= 0;
+ if (!adapter->rx_buff_pool[i].active)
+ continue;
+ if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
+ dev->mtu = new_mtu;
+ return 0;
}
-
- if (activate && !adapter->rx_buff_pool[i].active) {
- struct ibmveth_buff_pool *pool =
- &adapter->rx_buff_pool[i];
- if(ibmveth_alloc_buffer_pool(pool)) {
- ibmveth_error_printk("unable to alloc pool\n");
- return -ENOMEM;
- }
- adapter->rx_buff_pool[i].active = 1;
- } else if (!activate && adapter->rx_buff_pool[i].active) {
- adapter->rx_buff_pool[i].active = 0;
- h_free_logical_lan_buffer(adapter->vdev->unit_address,
- (u64)pool_size[i]);
- }
-
}
-
- /* kick the interrupt handler so that the new buffer pools get
- replenished or deallocated */
- ibmveth_interrupt(dev->irq, dev, NULL);
-
- dev->mtu = new_mtu;
- return 0;
+ return -EINVAL;
}
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
@@ -928,7 +915,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
unsigned int *mcastFilterSize_p;
- ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
+ ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
dev->unit_address);
mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
@@ -937,7 +924,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
"attribute\n", __FILE__, __LINE__);
return 0;
}
-
+
mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
if(!mcastFilterSize_p) {
printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
@@ -945,7 +932,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
__FILE__, __LINE__);
return 0;
}
-
+
netdev = alloc_etherdev(sizeof(struct ibmveth_adapter));
if(!netdev)
@@ -960,13 +947,14 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
adapter->vdev = dev;
adapter->netdev = netdev;
adapter->mcastFilterSize= *mcastFilterSize_p;
-
+ adapter->pool_config = 0;
+
/* Some older boxes running PHYP non-natively have an OF that
- returns a 8-byte local-mac-address field (and the first
+ returns a 8-byte local-mac-address field (and the first
2 bytes have to be ignored) while newer boxes' OF return
- a 6-byte field. Note that IEEE 1275 specifies that
+ a 6-byte field. Note that IEEE 1275 specifies that
local-mac-address must be a 6-byte field.
- The RPA doc specifies that the first byte must be 10b, so
+ The RPA doc specifies that the first byte must be 10b, so
we'll just look for it to solve this 8 vs. 6 byte field issue */
if ((*mac_addr_p & 0x3) != 0x02)
@@ -976,7 +964,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
memcpy(&adapter->mac_addr, mac_addr_p, 6);
adapter->liobn = dev->iommu_table->it_index;
-
+
netdev->irq = dev->irq;
netdev->open = ibmveth_open;
netdev->poll = ibmveth_poll;
@@ -989,14 +977,21 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
netdev->ethtool_ops = &netdev_ethtool_ops;
netdev->change_mtu = ibmveth_change_mtu;
SET_NETDEV_DEV(netdev, &dev->dev);
- netdev->features |= NETIF_F_LLTX;
+ netdev->features |= NETIF_F_LLTX;
spin_lock_init(&adapter->stats_lock);
memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
- for(i = 0; i<IbmVethNumBufferPools; i++)
- ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
- pool_count[i], pool_size[i]);
+ for(i = 0; i<IbmVethNumBufferPools; i++) {
+ struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
+ ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
+ pool_count[i], pool_size[i],
+ pool_active[i]);
+ kobj->parent = &dev->dev.kobj;
+ sprintf(kobj->name, "pool%d", i);
+ kobj->ktype = &ktype_veth_pool;
+ kobject_register(kobj);
+ }
ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
@@ -1025,6 +1020,10 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
{
struct net_device *netdev = dev->dev.driver_data;
struct ibmveth_adapter *adapter = netdev->priv;
+ int i;
+
+ for(i = 0; i<IbmVethNumBufferPools; i++)
+ kobject_unregister(&adapter->rx_buff_pool[i].kobj);
unregister_netdev(netdev);
@@ -1048,7 +1047,7 @@ static void ibmveth_proc_unregister_driver(void)
remove_proc_entry(IBMVETH_PROC_DIR, NULL);
}
-static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
+static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
{
if (*pos == 0) {
return (void *)1;
@@ -1063,18 +1062,18 @@ static void *ibmveth_seq_next(struct seq_file *seq, void *v, loff_t *pos)
return NULL;
}
-static void ibmveth_seq_stop(struct seq_file *seq, void *v)
+static void ibmveth_seq_stop(struct seq_file *seq, void *v)
{
}
-static int ibmveth_seq_show(struct seq_file *seq, void *v)
+static int ibmveth_seq_show(struct seq_file *seq, void *v)
{
struct ibmveth_adapter *adapter = seq->private;
char *current_mac = ((char*) &adapter->netdev->dev_addr);
char *firmware_mac = ((char*) &adapter->mac_addr) ;
seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
-
+
seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
seq_printf(seq, "LIOBN: 0x%lx\n", adapter->liobn);
seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1083,7 +1082,7 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
firmware_mac[0], firmware_mac[1], firmware_mac[2],
firmware_mac[3], firmware_mac[4], firmware_mac[5]);
-
+
seq_printf(seq, "\nAdapter Statistics:\n");
seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized);
seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send);
@@ -1095,7 +1094,7 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, " add buffer failures: %ld\n", adapter->replenish_add_buff_failure);
seq_printf(seq, " invalid buffers: %ld\n", adapter->rx_invalid_buffer);
seq_printf(seq, " no buffers: %ld\n", adapter->rx_no_buffer);
-
+
return 0;
}
static struct seq_operations ibmveth_seq_ops = {
@@ -1153,11 +1152,11 @@ static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
}
#else /* CONFIG_PROC_FS */
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
+static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
{
}
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
+static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
{
}
static void ibmveth_proc_register_driver(void)
@@ -1169,6 +1168,132 @@ static void ibmveth_proc_unregister_driver(void)
}
#endif /* CONFIG_PROC_FS */
+static struct attribute veth_active_attr;
+static struct attribute veth_num_attr;
+static struct attribute veth_size_attr;
+
+static ssize_t veth_pool_show(struct kobject * kobj,
+ struct attribute * attr, char * buf)
+{
+ struct ibmveth_buff_pool *pool = container_of(kobj,
+ struct ibmveth_buff_pool,
+ kobj);
+
+ if (attr == &veth_active_attr)
+ return sprintf(buf, "%d\n", pool->active);
+ else if (attr == &veth_num_attr)
+ return sprintf(buf, "%d\n", pool->size);
+ else if (attr == &veth_size_attr)
+ return sprintf(buf, "%d\n", pool->buff_size);
+ return 0;
+}
+
+static ssize_t veth_pool_store(struct kobject * kobj, struct attribute * attr,
+const char * buf, size_t count)
+{
+ struct ibmveth_buff_pool *pool = container_of(kobj,
+ struct ibmveth_buff_pool,
+ kobj);
+ struct net_device *netdev =
+ container_of(kobj->parent, struct device, kobj)->driver_data;
+ struct ibmveth_adapter *adapter = netdev->priv;
+ long value = simple_strtol(buf, NULL, 10);
+ long rc;
+
+ if (attr == &veth_active_attr) {
+ if (value && !pool->active) {
+ if(ibmveth_alloc_buffer_pool(pool)) {
+ ibmveth_error_printk("unable to alloc pool\n");
+ return -ENOMEM;
+ }
+ pool->active = 1;
+ adapter->pool_config = 1;
+ ibmveth_close(netdev);
+ adapter->pool_config = 0;
+ if ((rc = ibmveth_open(netdev)))
+ return rc;
+ } else if (!value && pool->active) {
+ int mtu = netdev->mtu + IBMVETH_BUFF_OH;
+ int i;
+ /* Make sure there is a buffer pool with buffers that
+ can hold a packet of the size of the MTU */
+ for(i = 0; i<IbmVethNumBufferPools; i++) {
+ if (pool == &adapter->rx_buff_pool[i])
+ continue;
+ if (!adapter->rx_buff_pool[i].active)
+ continue;
+ if (mtu < adapter->rx_buff_pool[i].buff_size) {
+ pool->active = 0;
+ h_free_logical_lan_buffer(adapter->
+ vdev->
+ unit_address,
+ pool->
+ buff_size);
+ }
+ }
+ if (pool->active) {
+ ibmveth_error_printk("no active pool >= MTU\n");
+ return -EPERM;
+ }
+ }
+ } else if (attr == &veth_num_attr) {
+ if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT)
+ return -EINVAL;
+ else {
+ adapter->pool_config = 1;
+ ibmveth_close(netdev);
+ adapter->pool_config = 0;
+ pool->size = value;
+ if ((rc = ibmveth_open(netdev)))
+ return rc;
+ }
+ } else if (attr == &veth_size_attr) {
+ if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE)
+ return -EINVAL;
+ else {
+ adapter->pool_config = 1;
+ ibmveth_close(netdev);
+ adapter->pool_config = 0;
+ pool->buff_size = value;
+ if ((rc = ibmveth_open(netdev)))
+ return rc;
+ }
+ }
+
+ /* kick the interrupt handler to allocate/deallocate pools */
+ ibmveth_interrupt(netdev->irq, netdev, NULL);
+ return count;
+}
+
+
+#define ATTR(_name, _mode) \
+ struct attribute veth_##_name##_attr = { \
+ .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \
+ };
+
+static ATTR(active, 0644);
+static ATTR(num, 0644);
+static ATTR(size, 0644);
+
+static struct attribute * veth_pool_attrs[] = {
+ &veth_active_attr,
+ &veth_num_attr,
+ &veth_size_attr,
+ NULL,
+};
+
+static struct sysfs_ops veth_pool_ops = {
+ .show = veth_pool_show,
+ .store = veth_pool_store,
+};
+
+static struct kobj_type ktype_veth_pool = {
+ .release = NULL,
+ .sysfs_ops = &veth_pool_ops,
+ .default_attrs = veth_pool_attrs,
+};
+
+
static struct vio_device_id ibmveth_device_table[] __devinitdata= {
{ "network", "IBM,l-lan"},
{ "", "" }
@@ -1198,7 +1323,7 @@ static void __exit ibmveth_module_exit(void)
{
vio_unregister_driver(&ibmveth_driver);
ibmveth_proc_unregister_driver();
-}
+}
module_init(ibmveth_module_init);
module_exit(ibmveth_module_exit);
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index 46919a814fca..8385bf836507 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -75,10 +75,13 @@
#define IbmVethNumBufferPools 5
#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */
+#define IBMVETH_MAX_MTU 68
+#define IBMVETH_MAX_POOL_COUNT 4096
+#define IBMVETH_MAX_BUF_SIZE (1024 * 128)
-/* pool_size should be sorted */
static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 };
static int pool_count[] = { 256, 768, 256, 256, 256 };
+static int pool_active[] = { 1, 1, 0, 0, 0};
#define IBM_VETH_INVALID_MAP ((u16)0xffff)
@@ -94,6 +97,7 @@ struct ibmveth_buff_pool {
dma_addr_t *dma_addr;
struct sk_buff **skbuff;
int active;
+ struct kobject kobj;
};
struct ibmveth_rx_q {
@@ -118,6 +122,7 @@ struct ibmveth_adapter {
dma_addr_t filter_list_dma;
struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
struct ibmveth_rx_q rx_queue;
+ int pool_config;
/* adapter specific stats */
u64 replenish_task_cycles;
@@ -134,7 +139,7 @@ struct ibmveth_adapter {
spinlock_t stats_lock;
};
-struct ibmveth_buf_desc_fields {
+struct ibmveth_buf_desc_fields {
u32 valid : 1;
u32 toggle : 1;
u32 reserved : 6;
@@ -143,7 +148,7 @@ struct ibmveth_buf_desc_fields {
};
union ibmveth_buf_desc {
- u64 desc;
+ u64 desc;
struct ibmveth_buf_desc_fields fields;
};
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 31fb2d75dc44..2e222ef91e22 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev)
dp->st_task_enter++;
if ((skb = skb_peek(&dp->tq)) == NULL) {
dp->st_txq_refl_try++;
- if (spin_trylock(&_dev->xmit_lock)) {
+ if (netif_tx_trylock(_dev)) {
dp->st_rxq_enter++;
while ((skb = skb_dequeue(&dp->rq)) != NULL) {
skb_queue_tail(&dp->tq, skb);
dp->st_rx2tx_tran++;
}
- spin_unlock(&_dev->xmit_lock);
+ netif_tx_unlock(_dev);
} else {
/* reschedule */
dp->st_rxq_notenter++;
@@ -110,7 +110,7 @@ static void ri_tasklet(unsigned long dev)
}
}
- if (spin_trylock(&_dev->xmit_lock)) {
+ if (netif_tx_trylock(_dev)) {
dp->st_rxq_check++;
if ((skb = skb_peek(&dp->rq)) == NULL) {
dp->tasklet_pending = 0;
@@ -118,10 +118,10 @@ static void ri_tasklet(unsigned long dev)
netif_wake_queue(_dev);
} else {
dp->st_rxq_rsch++;
- spin_unlock(&_dev->xmit_lock);
+ netif_tx_unlock(_dev);
goto resched;
}
- spin_unlock(&_dev->xmit_lock);
+ netif_tx_unlock(_dev);
} else {
resched:
dp->tasklet_pending = 1;
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 5e6d00752990..d2ce4896abff 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -33,7 +33,7 @@ config DONGLE
config ESI_DONGLE
tristate "ESI JetEye PC dongle"
- depends on DONGLE && IRDA
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Extended Systems
JetEye PC dongle. To compile it as a module, choose M here. The ESI
@@ -44,7 +44,7 @@ config ESI_DONGLE
config ACTISYS_DONGLE
tristate "ACTiSYS IR-220L and IR220L+ dongle"
- depends on DONGLE && IRDA
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-220L and
IR220L+ dongles. To compile it as a module, choose M here. The
@@ -55,7 +55,7 @@ config ACTISYS_DONGLE
config TEKRAM_DONGLE
tristate "Tekram IrMate 210B dongle"
- depends on DONGLE && IRDA
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Tekram IrMate 210B
dongle. To compile it as a module, choose M here. The Tekram dongle
@@ -66,7 +66,7 @@ config TEKRAM_DONGLE
config TOIM3232_DONGLE
tristate "TOIM3232 IrDa dongle"
- depends on DONGLE && IRDA
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Vishay/Temic
TOIM3232 and TOIM4232 based dongles.
@@ -74,7 +74,7 @@ config TOIM3232_DONGLE
config LITELINK_DONGLE
tristate "Parallax LiteLink dongle"
- depends on DONGLE && IRDA
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Parallax Litelink
dongle. To compile it as a module, choose M here. The Parallax
@@ -85,7 +85,7 @@ config LITELINK_DONGLE
config MA600_DONGLE
tristate "Mobile Action MA600 dongle"
- depends on DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Mobile Action MA600
dongle. To compile it as a module, choose M here. The MA600 dongle
@@ -98,7 +98,7 @@ config MA600_DONGLE
config GIRBIL_DONGLE
tristate "Greenwich GIrBIL dongle"
- depends on DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Greenwich GIrBIL
dongle. If you want to compile it as a module, choose M here.
@@ -109,7 +109,7 @@ config GIRBIL_DONGLE
config MCP2120_DONGLE
tristate "Microchip MCP2120"
- depends on DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Microchip MCP2120
dongle. If you want to compile it as a module, choose M here.
@@ -123,7 +123,7 @@ config MCP2120_DONGLE
config OLD_BELKIN_DONGLE
tristate "Old Belkin dongle"
- depends on DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Adaptec Airport 1000
and 2000 dongles. If you want to compile it as a module, choose
@@ -132,7 +132,7 @@ config OLD_BELKIN_DONGLE
config ACT200L_DONGLE
tristate "ACTiSYS IR-200L dongle"
- depends on DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the ACTiSYS IR-200L
dongle. If you want to compile it as a module, choose M here.
@@ -417,5 +417,20 @@ config PXA_FICP
available capabilities may vary from one PXA2xx target to
another.
+config MCS_FIR
+ tristate "MosChip MCS7780 IrDA-USB dongle"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the MosChip
+ MCS7780 IrDA-USB bridge device driver.
+
+ USB bridge based on the MosChip MCS7780 don't conform to the
+ IrDA-USB device class specification, and therefore need their
+ own specific driver. Those dongles support SIR and FIR (4Mbps)
+ speeds.
+
+ To compile it as a module, choose M here: the module will be called
+ mcs7780.
+
endmenu
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 27ab75f20799..5be09f1b9ee2 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_ALI_FIR) += ali-ircc.o
obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
obj-$(CONFIG_VIA_FIR) += via-ircc.o
obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o
+obj-$(CONFIG_MCS_FIR) += mcs7780.o
# Old dongle drivers for old SIR drivers
obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o
obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o
@@ -46,4 +47,4 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
# The SIR helper module
-sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o
+sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 2e7882eb7d6f..bf1fca5a3fa0 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -34,14 +34,12 @@
#include <linux/rtnetlink.h>
#include <linux/serial_reg.h>
#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
@@ -51,7 +49,19 @@
#define CHIP_IO_EXTENT 8
#define BROKEN_DONGLE_ID
-static char *driver_name = "ali-ircc";
+#define ALI_IRCC_DRIVER_NAME "ali-ircc"
+
+/* Power Management */
+static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state);
+static int ali_ircc_resume(struct platform_device *dev);
+
+static struct platform_driver ali_ircc_driver = {
+ .suspend = ali_ircc_suspend,
+ .resume = ali_ircc_resume,
+ .driver = {
+ .name = ALI_IRCC_DRIVER_NAME,
+ },
+};
/* Module parameters */
static int qos_mtt_bits = 0x07; /* 1 ms or more */
@@ -97,10 +107,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self);
static int ali_ircc_net_open(struct net_device *dev);
static int ali_ircc_net_close(struct net_device *dev);
static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);
-static void ali_ircc_suspend(struct ali_ircc_cb *self);
-static void ali_ircc_wakeup(struct ali_ircc_cb *self);
static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev);
/* SIR function */
@@ -145,6 +152,14 @@ static int __init ali_ircc_init(void)
int i = 0;
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
+
+ ret = platform_driver_register(&ali_ircc_driver);
+ if (ret) {
+ IRDA_ERROR("%s, Can't register driver!\n",
+ ALI_IRCC_DRIVER_NAME);
+ return ret;
+ }
+
/* Probe for all the ALi chipsets we know about */
for (chip= chips; chip->name; chip++, i++)
@@ -214,6 +229,10 @@ static int __init ali_ircc_init(void)
}
IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
+
+ if (ret)
+ platform_driver_unregister(&ali_ircc_driver);
+
return ret;
}
@@ -228,14 +247,14 @@ static void __exit ali_ircc_cleanup(void)
int i;
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
-
- pm_unregister_all(ali_ircc_pmproc);
for (i=0; i < 4; i++) {
if (dev_self[i])
ali_ircc_close(dev_self[i]);
}
+ platform_driver_unregister(&ali_ircc_driver);
+
IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
}
@@ -249,7 +268,6 @@ static int ali_ircc_open(int i, chipio_t *info)
{
struct net_device *dev;
struct ali_ircc_cb *self;
- struct pm_dev *pmdev;
int dongle_id;
int err;
@@ -284,7 +302,8 @@ static int ali_ircc_open(int i, chipio_t *info)
self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */
/* Reserve the ioports that we need */
- if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
+ if (!request_region(self->io.fir_base, self->io.fir_ext,
+ ALI_IRCC_DRIVER_NAME)) {
IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__,
self->io.fir_base);
err = -ENODEV;
@@ -354,13 +373,10 @@ static int ali_ircc_open(int i, chipio_t *info)
/* Check dongle id */
dongle_id = ali_ircc_read_dongle_id(i, info);
- IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]);
+ IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__,
+ ALI_IRCC_DRIVER_NAME, dongle_types[dongle_id]);
self->io.dongle_id = dongle_id;
-
- pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ali_ircc_pmproc);
- if (pmdev)
- pmdev->data = self;
IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
@@ -548,12 +564,11 @@ static int ali_ircc_setup(chipio_t *info)
/* Should be 0x00 in the M1535/M1535D */
if(version != 0x00)
{
- IRDA_ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+ IRDA_ERROR("%s, Wrong chip version %02x\n",
+ ALI_IRCC_DRIVER_NAME, version);
return -1;
}
- // IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base);
-
/* Set FIR FIFO Threshold Register */
switch_bank(iobase, BANK1);
outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR);
@@ -583,7 +598,8 @@ static int ali_ircc_setup(chipio_t *info)
/* Switch to SIR space */
FIR2SIR(iobase);
- IRDA_MESSAGE("%s, driver loaded (Benjamin Kong)\n", driver_name);
+ IRDA_MESSAGE("%s, driver loaded (Benjamin Kong)\n",
+ ALI_IRCC_DRIVER_NAME);
/* Enable receive interrupts */
// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
@@ -647,7 +663,8 @@ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id,
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
if (!dev) {
- IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+ IRDA_WARNING("%s: irq %d for unknown device.\n",
+ ALI_IRCC_DRIVER_NAME, irq);
return IRQ_NONE;
}
@@ -1328,7 +1345,8 @@ static int ali_ircc_net_open(struct net_device *dev)
/* Request IRQ and install Interrupt Handler */
if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev))
{
- IRDA_WARNING("%s, unable to allocate irq=%d\n", driver_name,
+ IRDA_WARNING("%s, unable to allocate irq=%d\n",
+ ALI_IRCC_DRIVER_NAME,
self->io.irq);
return -EAGAIN;
}
@@ -1338,7 +1356,8 @@ static int ali_ircc_net_open(struct net_device *dev)
* failure.
*/
if (request_dma(self->io.dma, dev->name)) {
- IRDA_WARNING("%s, unable to allocate dma=%d\n", driver_name,
+ IRDA_WARNING("%s, unable to allocate dma=%d\n",
+ ALI_IRCC_DRIVER_NAME,
self->io.dma);
free_irq(self->io.irq, self);
return -EAGAIN;
@@ -2108,61 +2127,38 @@ static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev)
return &self->stats;
}
-static void ali_ircc_suspend(struct ali_ircc_cb *self)
+static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state)
{
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
+ struct ali_ircc_cb *self = platform_get_drvdata(dev);
- IRDA_MESSAGE("%s, Suspending\n", driver_name);
+ IRDA_MESSAGE("%s, Suspending\n", ALI_IRCC_DRIVER_NAME);
if (self->io.suspended)
- return;
+ return 0;
ali_ircc_net_close(self->netdev);
self->io.suspended = 1;
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ );
+ return 0;
}
-static void ali_ircc_wakeup(struct ali_ircc_cb *self)
+static int ali_ircc_resume(struct platform_device *dev)
{
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
+ struct ali_ircc_cb *self = platform_get_drvdata(dev);
if (!self->io.suspended)
- return;
+ return 0;
ali_ircc_net_open(self->netdev);
- IRDA_MESSAGE("%s, Waking up\n", driver_name);
+ IRDA_MESSAGE("%s, Waking up\n", ALI_IRCC_DRIVER_NAME);
self->io.suspended = 0;
-
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ );
-}
-static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- struct ali_ircc_cb *self = (struct ali_ircc_cb*) dev->data;
-
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ );
-
- if (self) {
- switch (rqst) {
- case PM_SUSPEND:
- ali_ircc_suspend(self);
- break;
- case PM_RESUME:
- ali_ircc_wakeup(self);
- break;
- }
- }
-
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ );
-
return 0;
}
-
/* ALi Chip Function */
static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable)
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 96bdb73c2283..844fa74ac9ec 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -83,9 +83,9 @@ static struct usb_device_id dongles[] = {
/* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */
{ USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
/* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */
- { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
- { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
- { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
+ { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
+ { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
+ { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
.bInterfaceClass = USB_CLASS_APP_SPEC,
@@ -154,7 +154,7 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
* and if either speed or xbofs (or both) needs
* to be changed.
*/
- if (self->capability & IUC_STIR_4210 &&
+ if (self->capability & IUC_STIR421X &&
((self->new_speed != -1) || (self->new_xbofs != -1))) {
/* With STIR421x, speed and xBOFs must be set at the same
@@ -318,7 +318,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
/* Set the new speed and xbofs in this fake frame */
irda_usb_build_header(self, frame, 1);
- if ( self->capability & IUC_STIR_4210 ) {
+ if (self->capability & IUC_STIR421X) {
if (frame[0] == 0) return ; // do nothing if no change
frame[1] = 0; // other parameters don't change here
frame[2] = 0;
@@ -455,7 +455,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Change setting for next frame */
- if ( self->capability & IUC_STIR_4210 ) {
+ if (self->capability & IUC_STIR421X) {
__u8 turnaround_time;
__u8* frame;
turnaround_time = get_turnaround_time( skb );
@@ -897,10 +897,13 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
/* Allocate a new skb */
- if ( self->capability & IUC_STIR_4210 )
- newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER);
+ if (self->capability & IUC_STIR421X)
+ newskb = dev_alloc_skb(docopy ? urb->actual_length :
+ IRDA_SKB_MAX_MTU +
+ USB_IRDA_STIR421X_HEADER);
else
- newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+ newskb = dev_alloc_skb(docopy ? urb->actual_length :
+ IRDA_SKB_MAX_MTU);
if (!newskb) {
self->stats.rx_dropped++;
@@ -1022,188 +1025,140 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self)
return 0; /* For now */
}
-
-#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: "
-#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: "
-#define STIR421X_PATCH_DATA_TAG_STR "STMP"
-#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */
-#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */
-#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */
+#define STIR421X_PATCH_PRODUCT_VER "Product Version: "
+#define STIR421X_PATCH_STMP_TAG "STMP"
+#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here */
+/* marks end of patch file header (PC DOS text file EOF character) */
+#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A
+#define STIR421X_PATCH_BLOCK_SIZE 1023
/*
- * Known firmware patches for STIR421x dongles
+ * Function stir421x_fwupload (struct irda_usb_cb *self,
+ * unsigned char *patch,
+ * const unsigned int patch_len)
+ *
+ * Upload firmware code to SigmaTel 421X IRDA-USB dongle
*/
-static char * stir421x_patches[] = {
- "42101001.sb",
- "42101002.sb",
-};
-
-static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len)
+static int stir421x_fw_upload(struct irda_usb_cb *self,
+ unsigned char *patch,
+ const unsigned int patch_len)
{
- unsigned int version_offset;
- unsigned long version_major, version_minor, version_build;
- unsigned char * version_start;
- int version_found = 0;
-
- for (version_offset = 0;
- version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG;
- version_offset++) {
- if (!memcmp(patch + version_offset,
- STIR421X_PATCH_PRODUCT_VERSION_STR,
- sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) {
- version_found = 1;
- version_start = patch +
- version_offset +
- sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1;
- break;
- }
+ int ret = -ENOMEM;
+ int actual_len = 0;
+ unsigned int i;
+ unsigned int block_size = 0;
+ unsigned char *patch_block;
+
+ patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL);
+ if (patch_block == NULL)
+ return -ENOMEM;
+
+ /* break up patch into 1023-byte sections */
+ for (i = 0; i < patch_len; i += block_size) {
+ block_size = patch_len - i;
+
+ if (block_size > STIR421X_PATCH_BLOCK_SIZE)
+ block_size = STIR421X_PATCH_BLOCK_SIZE;
+
+ /* upload the patch section */
+ memcpy(patch_block, patch + i, block_size);
+
+ ret = usb_bulk_msg(self->usbdev,
+ usb_sndbulkpipe(self->usbdev,
+ self->bulk_out_ep),
+ patch_block, block_size,
+ &actual_len, msecs_to_jiffies(500));
+ IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n",
+ __FUNCTION__, actual_len, ret);
+
+ if (ret < 0)
+ break;
}
- /* We couldn't find a product version on this patch */
- if (!version_found)
- return -EINVAL;
-
- /* Let's check if the product version is dotted */
- if (version_start[3] != '.' ||
- version_start[7] != '.')
- return -EINVAL;
-
- version_major = simple_strtoul(version_start, NULL, 10);
- version_minor = simple_strtoul(version_start + 4, NULL, 10);
- version_build = simple_strtoul(version_start + 8, NULL, 10);
-
- IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n",
- __FUNCTION__,
- version_major, version_minor, version_build);
-
- return (((version_major) << 12) +
- ((version_minor) << 8) +
- ((version_build / 10) << 4) +
- (version_build % 10));
-
-}
-
-
-static int stir421x_upload_patch (struct irda_usb_cb *self,
- unsigned char * patch,
- const unsigned int patch_len)
-{
- int retval = 0;
- int actual_len;
- unsigned int i = 0, download_amount = 0;
- unsigned char * patch_chunk;
-
- IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__);
-
- patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL);
- if (patch_chunk == NULL)
- return -ENOMEM;
-
- /* break up patch into 1023-byte sections */
- for (i = 0; retval >= 0 && i < patch_len; i += download_amount) {
- download_amount = patch_len - i;
- if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE)
- download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE;
-
- /* download the patch section */
- memcpy(patch_chunk, patch + i, download_amount);
-
- retval = usb_bulk_msg (self->usbdev,
- usb_sndbulkpipe (self->usbdev,
- self->bulk_out_ep),
- patch_chunk, download_amount,
- &actual_len, msecs_to_jiffies (500));
- IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__,
- actual_len);
- if (retval == 0)
- mdelay(10);
- }
-
- kfree(patch_chunk);
-
- if (i != patch_len) {
- IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n",
- __FUNCTION__, i, patch_len);
- retval = -EIO;
- }
-
- if (retval < 0)
- /* todo - mark device as not ready */
- IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n",
- __FUNCTION__, retval);
-
- return retval;
-}
+ kfree(patch_block);
+ return ret;
+ }
+/*
+ * Function stir421x_patch_device(struct irda_usb_cb *self)
+ *
+ * Get a firmware code from userspase using hotplug request_firmware() call
+ */
static int stir421x_patch_device(struct irda_usb_cb *self)
{
- unsigned int i, patch_found = 0, data_found = 0, data_offset;
- int patch_version, ret = 0;
- const struct firmware *fw_entry;
-
- for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) {
- if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) {
- IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]);
- continue;
- }
-
- /* We found a patch from userspace */
- patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size);
-
- if (patch_version < 0) {
- /* Couldn't fetch a version, let's move on to the next file */
- IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__);
- ret = patch_version;
- release_firmware(fw_entry);
- continue;
- }
-
- if (patch_version != self->usbdev->descriptor.bcdDevice) {
- /* Patch version and device don't match */
- IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n",
- __FUNCTION__,
- patch_version, self->usbdev->descriptor.bcdDevice);
- ret = -EINVAL;
- release_firmware(fw_entry);
- continue;
- }
-
- /* If we're here, we've found a correct patch */
- patch_found = 1;
- break;
-
- }
-
- /* We couldn't find a valid firmware, let's leave */
- if (!patch_found)
- return ret;
-
- /* The actual image starts after the "STMP" keyword */
- for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) {
- if (!memcmp(fw_entry->data + data_offset,
- STIR421X_PATCH_DATA_TAG_STR,
- sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) {
- IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n",
- __FUNCTION__, data_offset);
- data_found = 1;
- break;
- }
- }
-
- /* We couldn't find "STMP" from the header */
- if (!data_found)
- return -EINVAL;
-
- /* Let's upload the patch to the target */
- ret = stir421x_upload_patch(self,
- &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)],
- fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)));
-
- release_firmware(fw_entry);
-
- return ret;
-
+ unsigned int i;
+ int ret;
+ char stir421x_fw_name[11];
+ const struct firmware *fw;
+ unsigned char *fw_version_ptr; /* pointer to version string */
+ unsigned long fw_version = 0;
+
+ /*
+ * Known firmware patch file names for STIR421x dongles
+ * are "42101001.sb" or "42101002.sb"
+ */
+ sprintf(stir421x_fw_name, "4210%4X.sb",
+ self->usbdev->descriptor.bcdDevice);
+ ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev);
+ if (ret < 0)
+ return ret;
+
+ /* We get a patch from userspace */
+ IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
+ __FUNCTION__, stir421x_fw_name, fw->size);
+
+ ret = -EINVAL;
+
+ /* Get the bcd product version */
+ if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER,
+ sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) {
+ fw_version_ptr = fw->data +
+ sizeof(STIR421X_PATCH_PRODUCT_VER) - 1;
+
+ /* Let's check if the product version is dotted */
+ if (fw_version_ptr[3] == '.' &&
+ fw_version_ptr[7] == '.') {
+ unsigned long major, minor, build;
+ major = simple_strtoul(fw_version_ptr, NULL, 10);
+ minor = simple_strtoul(fw_version_ptr + 4, NULL, 10);
+ build = simple_strtoul(fw_version_ptr + 8, NULL, 10);
+
+ fw_version = (major << 12)
+ + (minor << 8)
+ + ((build / 10) << 4)
+ + (build % 10);
+
+ IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n",
+ __FUNCTION__, fw_version);
+ }
+ }
+
+ if (self->usbdev->descriptor.bcdDevice == fw_version) {
+ /*
+ * If we're here, we've found a correct patch
+ * The actual image starts after the "STMP" keyword
+ * so forward to the firmware header tag
+ */
+ for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG)
+ && (i < fw->size); i++) ;
+ /* here we check for the out of buffer case */
+ if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i])
+ && (i < STIR421X_PATCH_CODE_OFFSET)) {
+ if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,
+ sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {
+
+ /* We can upload the patch to the target */
+ i += sizeof(STIR421X_PATCH_STMP_TAG);
+ ret = stir421x_fw_upload(self, &fw->data[i],
+ fw->size - i);
+ }
+ }
+ }
+
+ release_firmware(fw);
+
+ return ret;
}
@@ -1702,12 +1657,12 @@ static int irda_usb_probe(struct usb_interface *intf,
init_timer(&self->rx_defer_timer);
self->capability = id->driver_info;
- self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ;
+ self->needspatch = ((self->capability & IUC_STIR421X) != 0);
/* Create all of the needed urbs */
- if (self->capability & IUC_STIR_4210) {
+ if (self->capability & IUC_STIR421X) {
self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;
- self->header_length = USB_IRDA_SIGMATEL_HEADER;
+ self->header_length = USB_IRDA_STIR421X_HEADER;
} else {
self->max_rx_urb = IU_MAX_RX_URBS;
self->header_length = USB_IRDA_HEADER;
@@ -1778,7 +1733,7 @@ static int irda_usb_probe(struct usb_interface *intf,
if (self->needspatch) {
ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),
- 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500));
+ 0x02, 0x40, 0, 0, NULL, 0, 500);
if (ret < 0) {
IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret);
goto err_out_3;
@@ -1813,8 +1768,8 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Now we fetch and upload the firmware patch */
ret = stir421x_patch_device(self);
self->needspatch = (ret < 0);
- if (ret < 0) {
- printk("patch_device failed\n");
+ if (self->needspatch) {
+ IRDA_ERROR("STIR421X: Couldn't upload patch\n");
goto err_out_5;
}
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index d833db52cebf..6b2271f18e77 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -34,9 +34,6 @@
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> /* struct irlap_cb */
-#define PATCH_FILE_SIZE_MAX 65536
-#define PATCH_FILE_SIZE_MIN 80
-
#define RX_COPY_THRESHOLD 200
#define IRDA_USB_MAX_MTU 2051
#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */
@@ -107,14 +104,15 @@
#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */
-#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */
+#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */
/* USB class definitions */
#define USB_IRDA_HEADER 0x01
#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
#define USB_DT_IRDA 0x21
-#define USB_IRDA_SIGMATEL_HEADER 0x03
-#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER)
+#define USB_IRDA_STIR421X_HEADER 0x03
+#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \
+ USB_IRDA_STIR421X_HEADER)
struct irda_class_desc {
__u8 bLength;
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
new file mode 100644
index 000000000000..754297fc8f22
--- /dev/null
+++ b/drivers/net/irda/mcs7780.c
@@ -0,0 +1,1009 @@
+/*****************************************************************************
+*
+* Filename: mcs7780.c
+* Version: 0.4-alpha
+* Description: Irda MosChip USB Dongle Driver
+* Authors: Lukasz Stelmach <stlman@poczta.fm>
+* Brian Pugh <bpugh@cs.pdx.edu>
+* Judy Fischbach <jfisch@cs.pdx.edu>
+*
+* Based on stir4200 driver, but some things done differently.
+* Based on earlier driver by Paul Stewart <stewart@parc.com>
+*
+* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
+* Copyright (C) 2001, Dag Brattli <dag@brattli.net>
+* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
+* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
+* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu>
+*
+* 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.
+*
+*****************************************************************************/
+
+/*
+ * MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither
+ * compatibile with irda-usb nor with stir4200. Although it is quite
+ * similar to the later as far as general idea of operation is concerned.
+ * That is it requires the software to do all the framing job at SIR speeds.
+ * The hardware does take care of the framing at MIR and FIR speeds.
+ * It supports all speeds from 2400 through 4Mbps
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#include "mcs7780.h"
+
+#define MCS_VENDOR_ID 0x9710
+#define MCS_PRODUCT_ID 0x7780
+
+static struct usb_device_id mcs_table[] = {
+ /* MosChip Corp., MCS7780 FIR-USB Adapter */
+ {USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)},
+ {},
+};
+
+MODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780");
+MODULE_VERSION("0.3alpha");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(usb, mcs_table);
+
+static int qos_mtt_bits = 0x07 /* > 1ms */ ;
+module_param(qos_mtt_bits, int, 0);
+MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
+
+static int receive_mode = 0x1;
+module_param(receive_mode, int, 0);
+MODULE_PARM_DESC(receive_mode,
+ "Receive mode of the device (1:fast, 0:slow, default:1)");
+
+static int sir_tweak = 1;
+module_param(sir_tweak, int, 0444);
+MODULE_PARM_DESC(sir_tweak,
+ "Default pulse width (1:1.6us, 0:3/16 bit, default:1).");
+
+static int transceiver_type = MCS_TSC_VISHAY;
+module_param(transceiver_type, int, 0444);
+MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h.");
+
+struct usb_driver mcs_driver = {
+ .name = "mcs7780",
+ .probe = mcs_probe,
+ .disconnect = mcs_disconnect,
+ .id_table = mcs_table,
+};
+
+/* speed flag selection by direct addressing.
+addr = (speed >> 8) & 0x0f
+
+0x1 57600 0x2 115200 0x4 1152000 0x5 9600
+0x6 38400 0x9 2400 0xa 576000 0xb 19200
+
+4Mbps (or 2400) must be checked separately. Since it also has
+to be programmed in a different manner that is not a big problem.
+*/
+static __u16 mcs_speed_set[16] = { 0,
+ MCS_SPEED_57600,
+ MCS_SPEED_115200,
+ 0,
+ MCS_SPEED_1152000,
+ MCS_SPEED_9600,
+ MCS_SPEED_38400,
+ 0, 0,
+ MCS_SPEED_2400,
+ MCS_SPEED_576000,
+ MCS_SPEED_19200,
+ 0, 0, 0,
+};
+
+/* Set given 16 bit register with a 16 bit value. Send control message
+ * to set dongle register. */
+static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val)
+{
+ struct usb_device *dev = mcs->usbdev;
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, val, reg, NULL, 0,
+ msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+}
+
+/* Get 16 bit register value. Send contol message to read dongle register. */
+static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
+{
+ struct usb_device *dev = mcs->usbdev;
+ int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, reg, val, 2,
+ msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+
+ return ret;
+}
+
+/* Setup a communication between mcs7780 and TFDU chips. It is described
+ * in more detail in the data sheet. The setup sequence puts the the
+ * vishay tranceiver into high speed mode. It will also receive SIR speed
+ * packets but at reduced sensitivity.
+ */
+
+/* 0: OK 1:ERROR */
+static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs)
+{
+ int ret = 0;
+ __u16 rval;
+
+ /* mcs_get_reg should read exactly two bytes from the dongle */
+ ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
+ if (unlikely(ret != 2)) {
+ ret = -EIO;
+ goto error;
+ }
+
+ /* The MCS_XCVR_CONF bit puts the transceiver into configuration
+ * mode. The MCS_MODE0 bit must start out high (1) and then
+ * transition to low and the MCS_STFIR and MCS_MODE1 bits must
+ * be low.
+ */
+ rval |= (MCS_MODE0 | MCS_XCVR_CONF);
+ rval &= ~MCS_STFIR;
+ rval &= ~MCS_MODE1;
+ ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
+ if (unlikely(ret))
+ goto error;
+
+ rval &= ~MCS_MODE0;
+ ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
+ if (unlikely(ret))
+ goto error;
+
+ rval &= ~MCS_XCVR_CONF;
+ ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
+ if (unlikely(ret))
+ goto error;
+
+ ret = 0;
+ error:
+ return ret;
+}
+
+/* Setup a communication between mcs7780 and agilent chip. */
+static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs)
+{
+ IRDA_WARNING("This transceiver type is not supported yet.");
+ return 1;
+}
+
+/* Setup a communication between mcs7780 and sharp chip. */
+static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs)
+{
+ IRDA_WARNING("This transceiver type is not supported yet.");
+ return 1;
+}
+
+/* Common setup for all transceivers */
+static inline int mcs_setup_transceiver(struct mcs_cb *mcs)
+{
+ int ret = 0;
+ __u16 rval;
+ char *msg;
+
+ msg = "Basic transceiver setup error.";
+
+ /* read value of MODE Register, set the DRIVER and RESET bits
+ * and write value back out to MODE Register
+ */
+ ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
+ if(unlikely(ret != 2))
+ goto error;
+ rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */
+ ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
+ if(unlikely(ret))
+ goto error;
+
+ rval = 0; /* set min pulse width to 0 initially. */
+ ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval);
+ if(unlikely(ret))
+ goto error;
+
+ ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
+ if(unlikely(ret != 2))
+ goto error;
+
+ rval &= ~MCS_FIR; /* turn off fir mode. */
+ if(mcs->sir_tweak)
+ rval |= MCS_SIR16US; /* 1.6us pulse width */
+ else
+ rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */
+
+ /* make sure ask mode and back to back packets are off. */
+ rval &= ~(MCS_BBTG | MCS_ASK);
+
+ rval &= ~MCS_SPEED_MASK;
+ rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */
+ mcs->speed = 9600;
+ mcs->new_speed = 0; /* new_speed is set to 0 */
+ rval &= ~MCS_PLLPWDN; /* disable power down. */
+
+ /* make sure device determines direction and that the auto send sip
+ * pulse are on.
+ */
+ rval |= MCS_DTD | MCS_SIPEN;
+
+ ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
+ if(unlikely(ret))
+ goto error;
+
+ msg = "transceiver model specific setup error.";
+ switch (mcs->transceiver_type) {
+ case MCS_TSC_VISHAY:
+ ret = mcs_setup_transceiver_vishay(mcs);
+ break;
+
+ case MCS_TSC_SHARP:
+ ret = mcs_setup_transceiver_sharp(mcs);
+ break;
+
+ case MCS_TSC_AGILENT:
+ ret = mcs_setup_transceiver_agilent(mcs);
+ break;
+
+ default:
+ IRDA_WARNING("Unknown transceiver type: %d",
+ mcs->transceiver_type);
+ ret = 1;
+ }
+ if (unlikely(ret))
+ goto error;
+
+ /* If transceiver is not SHARP, then if receive mode set
+ * on the RXFAST bit in the XCVR Register otherwise unset it
+ */
+ if (mcs->transceiver_type != MCS_TSC_SHARP) {
+
+ ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
+ if (unlikely(ret != 2))
+ goto error;
+ if (mcs->receive_mode)
+ rval |= MCS_RXFAST;
+ else
+ rval &= ~MCS_RXFAST;
+ ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
+ if (unlikely(ret))
+ goto error;
+ }
+
+ msg = "transceiver reset.";
+
+ ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
+ if (unlikely(ret != 2))
+ goto error;
+
+ /* reset the mcs7780 so all changes take effect. */
+ rval &= ~MCS_RESET;
+ ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
+ if (unlikely(ret))
+ goto error;
+ else
+ return ret;
+
+error:
+ IRDA_ERROR("%s", msg);
+ return ret;
+}
+
+/* Wraps the data in format for SIR */
+static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf)
+{
+ int wraplen;
+
+ /* 2: full frame length, including "the length" */
+ wraplen = async_wrap_skb(skb, buf + 2, 4094);
+
+ wraplen += 2;
+ buf[0] = wraplen & 0xff;
+ buf[1] = (wraplen >> 8) & 0xff;
+
+ return wraplen;
+}
+
+/* Wraps the data in format for FIR */
+static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf)
+{
+ unsigned int len = 0;
+ __u32 fcs = ~(crc32_le(~0, skb->data, skb->len));
+
+ /* add 2 bytes for length value and 4 bytes for fcs. */
+ len = skb->len + 6;
+
+ /* The mcs7780 requires that the first two bytes are the packet
+ * length in little endian order. Note: the length value includes
+ * the two bytes for the length value itself.
+ */
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ /* copy the data into the tx buffer. */
+ memcpy(buf+2, skb->data, skb->len);
+ /* put the fcs in the last four bytes in little endian order. */
+ buf[len - 4] = fcs & 0xff;
+ buf[len - 3] = (fcs >> 8) & 0xff;
+ buf[len - 2] = (fcs >> 16) & 0xff;
+ buf[len - 1] = (fcs >> 24) & 0xff;
+
+ return len;
+}
+
+/* Wraps the data in format for MIR */
+static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf)
+{
+ __u16 fcs = 0;
+ int len = skb->len + 4;
+
+ fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len));
+ /* put the total packet length in first. Note: packet length
+ * value includes the two bytes that hold the packet length
+ * itself.
+ */
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ /* copy the data */
+ memcpy(buf+2, skb->data, skb->len);
+ /* put the fcs in last two bytes in little endian order. */
+ buf[len - 2] = fcs & 0xff;
+ buf[len - 1] = (fcs >> 8) & 0xff;
+
+ return len;
+}
+
+/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is
+ * used for the fcs. When performed over the entire packet the result
+ * should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA
+ * layer via a sk_buff.
+ */
+static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
+{
+ __u16 fcs;
+ int new_len;
+ struct sk_buff *skb;
+
+ /* Assume that the frames are going to fill a single packet
+ * rather than span multiple packets.
+ */
+
+ new_len = len - 2;
+ if(unlikely(new_len <= 0)) {
+ IRDA_ERROR("%s short frame length %d\n",
+ mcs->netdev->name, new_len);
+ ++mcs->stats.rx_errors;
+ ++mcs->stats.rx_length_errors;
+ return;
+ }
+ fcs = 0;
+ fcs = irda_calc_crc16(~fcs, buf, len);
+
+ if(fcs != GOOD_FCS) {
+ IRDA_ERROR("crc error calc 0x%x len %d\n",
+ fcs, new_len);
+ mcs->stats.rx_errors++;
+ mcs->stats.rx_crc_errors++;
+ return;
+ }
+
+ skb = dev_alloc_skb(new_len + 1);
+ if(unlikely(!skb)) {
+ ++mcs->stats.rx_dropped;
+ return;
+ }
+
+ skb_reserve(skb, 1);
+ memcpy(skb->data, buf, new_len);
+ skb_put(skb, new_len);
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ skb->dev = mcs->netdev;
+
+ netif_rx(skb);
+
+ mcs->stats.rx_packets++;
+ mcs->stats.rx_bytes += new_len;
+
+ return;
+}
+
+/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is
+ * used for the fcs. Hands the unwrapped data off to the IrDA
+ * layer via a sk_buff.
+ */
+static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
+{
+ __u32 fcs;
+ int new_len;
+ struct sk_buff *skb;
+
+ /* Assume that the frames are going to fill a single packet
+ * rather than span multiple packets. This is most likely a false
+ * assumption.
+ */
+
+ new_len = len - 4;
+ if(unlikely(new_len <= 0)) {
+ IRDA_ERROR("%s short frame length %d\n",
+ mcs->netdev->name, new_len);
+ ++mcs->stats.rx_errors;
+ ++mcs->stats.rx_length_errors;
+ return;
+ }
+
+ fcs = ~(crc32_le(~0, buf, new_len));
+ if(fcs != le32_to_cpu(get_unaligned((u32 *)(buf+new_len)))) {
+ IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
+ mcs->stats.rx_errors++;
+ mcs->stats.rx_crc_errors++;
+ return;
+ }
+
+ skb = dev_alloc_skb(new_len + 1);
+ if(unlikely(!skb)) {
+ ++mcs->stats.rx_dropped;
+ return;
+ }
+
+ skb_reserve(skb, 1);
+ memcpy(skb->data, buf, new_len);
+ skb_put(skb, new_len);
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ skb->dev = mcs->netdev;
+
+ netif_rx(skb);
+
+ mcs->stats.rx_packets++;
+ mcs->stats.rx_bytes += new_len;
+
+ return;
+}
+
+
+/* Allocates urbs for both receive and transmit.
+ * If alloc fails return error code 0 (fail) otherwise
+ * return error code 1 (success).
+ */
+static inline int mcs_setup_urbs(struct mcs_cb *mcs)
+{
+ mcs->rx_urb = NULL;
+
+ mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mcs->tx_urb)
+ return 0;
+
+ mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mcs->rx_urb)
+ return 0;
+
+ return 1;
+}
+
+/* Sets up state to be initially outside frame, gets receive urb,
+ * sets status to successful and then submits the urb to start
+ * receiving the data.
+ */
+static inline int mcs_receive_start(struct mcs_cb *mcs)
+{
+ mcs->rx_buff.in_frame = FALSE;
+ mcs->rx_buff.state = OUTSIDE_FRAME;
+
+ usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev,
+ usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in),
+ mcs->in_buf, 4096, mcs_receive_irq, mcs);
+
+ mcs->rx_urb->status = 0;
+ return usb_submit_urb(mcs->rx_urb, GFP_KERNEL);
+}
+
+/* Finds the in and out endpoints for the mcs control block */
+static inline int mcs_find_endpoints(struct mcs_cb *mcs,
+ struct usb_host_endpoint *ep, int epnum)
+{
+ int i;
+ int ret = 0;
+
+ /* If no place to store the endpoints just return */
+ if (!ep)
+ return ret;
+
+ /* cycle through all endpoints, find the first two that are DIR_IN */
+ for (i = 0; i < epnum; i++) {
+ if (ep[i].desc.bEndpointAddress & USB_DIR_IN)
+ mcs->ep_in = ep[i].desc.bEndpointAddress;
+ else
+ mcs->ep_out = ep[i].desc.bEndpointAddress;
+
+ /* MosChip says that the chip has only two bulk
+ * endpoints. Find one for each direction and move on.
+ */
+ if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void mcs_speed_work(void *arg)
+{
+ struct mcs_cb *mcs = arg;
+ struct net_device *netdev = mcs->netdev;
+
+ mcs_speed_change(mcs);
+ netif_wake_queue(netdev);
+}
+
+/* Function to change the speed of the mcs7780. Fully supports SIR,
+ * MIR, and FIR speeds.
+ */
+static int mcs_speed_change(struct mcs_cb *mcs)
+{
+ int ret = 0;
+ int rst = 0;
+ int cnt = 0;
+ __u16 nspeed;
+ __u16 rval;
+
+ nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f];
+
+ do {
+ mcs_get_reg(mcs, MCS_RESV_REG, &rval);
+ } while(cnt++ < 100 && (rval & MCS_IRINTX));
+
+ if(cnt >= 100) {
+ IRDA_ERROR("unable to change speed");
+ ret = -EIO;
+ goto error;
+ }
+
+ mcs_get_reg(mcs, MCS_MODE_REG, &rval);
+
+ /* MINRXPW values recomended by MosChip */
+ if (mcs->new_speed <= 115200) {
+ rval &= ~MCS_FIR;
+
+ if ((rst = (mcs->speed > 115200)))
+ mcs_set_reg(mcs, MCS_MINRXPW_REG, 0);
+
+ } else if (mcs->new_speed <= 1152000) {
+ rval &= ~MCS_FIR;
+
+ if ((rst = !(mcs->speed == 576000 || mcs->speed == 1152000)))
+ mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
+
+ } else {
+ rval |= MCS_FIR;
+
+ if ((rst = (mcs->speed != 4000000)))
+ mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
+
+ }
+
+ rval &= ~MCS_SPEED_MASK;
+ rval |= nspeed;
+
+ ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
+ if (unlikely(ret))
+ goto error;
+
+ if (rst)
+ switch (mcs->transceiver_type) {
+ case MCS_TSC_VISHAY:
+ ret = mcs_setup_transceiver_vishay(mcs);
+ break;
+
+ case MCS_TSC_SHARP:
+ ret = mcs_setup_transceiver_sharp(mcs);
+ break;
+
+ case MCS_TSC_AGILENT:
+ ret = mcs_setup_transceiver_agilent(mcs);
+ break;
+
+ default:
+ ret = 1;
+ IRDA_WARNING("Unknown transceiver type: %d",
+ mcs->transceiver_type);
+ }
+ if (unlikely(ret))
+ goto error;
+
+ mcs_get_reg(mcs, MCS_MODE_REG, &rval);
+ rval &= ~MCS_RESET;
+ ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
+
+ mcs->speed = mcs->new_speed;
+ error:
+ mcs->new_speed = 0;
+ return ret;
+}
+
+/* Ioctl calls not supported at this time. Can be an area of future work. */
+static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ /* struct if_irda_req *irq = (struct if_irda_req *)rq; */
+ /* struct mcs_cb *mcs = netdev_priv(netdev); */
+ int ret = 0;
+
+ switch (cmd) {
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/* Network device is taken down, done by "ifconfig irda0 down" */
+static int mcs_net_close(struct net_device *netdev)
+{
+ int ret = 0;
+ struct mcs_cb *mcs = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* kill and free the receive and transmit URBs */
+ usb_kill_urb(mcs->rx_urb);
+ usb_free_urb(mcs->rx_urb);
+ usb_kill_urb(mcs->tx_urb);
+ usb_free_urb(mcs->tx_urb);
+
+ /* Stop and remove instance of IrLAP */
+ if (mcs->irlap)
+ irlap_close(mcs->irlap);
+
+ mcs->irlap = NULL;
+ return ret;
+}
+
+/* Network device is taken up, done by "ifconfig irda0 up" */
+static int mcs_net_open(struct net_device *netdev)
+{
+ struct mcs_cb *mcs = netdev_priv(netdev);
+ char hwname[16];
+ int ret = 0;
+
+ ret = usb_clear_halt(mcs->usbdev,
+ usb_sndbulkpipe(mcs->usbdev, mcs->ep_in));
+ if (ret)
+ goto error1;
+ ret = usb_clear_halt(mcs->usbdev,
+ usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out));
+ if (ret)
+ goto error1;
+
+ ret = mcs_setup_transceiver(mcs);
+ if (ret)
+ goto error1;
+
+ ret = -ENOMEM;
+
+ /* Initialize for SIR/FIR to copy data directly into skb. */
+ mcs->receiving = 0;
+ mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+ mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!mcs->rx_buff.skb)
+ goto error1;
+
+ skb_reserve(mcs->rx_buff.skb, 1);
+ mcs->rx_buff.head = mcs->rx_buff.skb->data;
+ do_gettimeofday(&mcs->rx_time);
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ * Note : will send immediately a speed change...
+ */
+ sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
+ mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
+ if (!mcs->irlap) {
+ IRDA_ERROR("mcs7780: irlap_open failed");
+ goto error2;
+ }
+
+ if (!mcs_setup_urbs(mcs))
+ goto error3;
+
+ ret = mcs_receive_start(mcs);
+ if (ret)
+ goto error3;
+
+ netif_start_queue(netdev);
+ return 0;
+
+ error3:
+ irlap_close(mcs->irlap);
+ error2:
+ kfree_skb(mcs->rx_buff.skb);
+ error1:
+ return ret;
+}
+
+
+/* Get device stats for /proc/net/dev and ifconfig */
+static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev)
+{
+ struct mcs_cb *mcs = netdev_priv(netdev);
+ return &mcs->stats;
+}
+
+/* Receive callback function. */
+static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs)
+{
+ __u8 *bytes;
+ struct mcs_cb *mcs = urb->context;
+ int i;
+ int ret;
+
+ if (!netif_running(mcs->netdev))
+ return;
+
+ if (urb->status)
+ return;
+
+ if (urb->actual_length > 0) {
+ bytes = urb->transfer_buffer;
+
+ /* MCS returns frames without BOF and EOF
+ * I assume it returns whole frames.
+ */
+ /* SIR speed */
+ if(mcs->speed < 576000) {
+ async_unwrap_char(mcs->netdev, &mcs->stats,
+ &mcs->rx_buff, 0xc0);
+
+ for (i = 0; i < urb->actual_length; i++)
+ async_unwrap_char(mcs->netdev, &mcs->stats,
+ &mcs->rx_buff, bytes[i]);
+
+ async_unwrap_char(mcs->netdev, &mcs->stats,
+ &mcs->rx_buff, 0xc1);
+ }
+ /* MIR speed */
+ else if(mcs->speed == 576000 || mcs->speed == 1152000) {
+ mcs_unwrap_mir(mcs, urb->transfer_buffer,
+ urb->actual_length);
+ }
+ /* FIR speed */
+ else {
+ mcs_unwrap_fir(mcs, urb->transfer_buffer,
+ urb->actual_length);
+ }
+ mcs->netdev->last_rx = jiffies;
+ do_gettimeofday(&mcs->rx_time);
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/* Transmit callback funtion. */
+static void mcs_send_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct mcs_cb *mcs = urb->context;
+ struct net_device *ndev = mcs->netdev;
+
+ if (unlikely(mcs->new_speed))
+ schedule_work(&mcs->work);
+ else
+ netif_wake_queue(ndev);
+}
+
+/* Transmit callback funtion. */
+static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ unsigned long flags;
+ struct mcs_cb *mcs;
+ int wraplen;
+ int ret = 0;
+
+
+ if (skb == NULL || ndev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(ndev);
+ mcs = netdev_priv(ndev);
+
+ spin_lock_irqsave(&mcs->lock, flags);
+
+ mcs->new_speed = irda_get_next_speed(skb);
+ if (likely(mcs->new_speed == mcs->speed))
+ mcs->new_speed = 0;
+
+ /* SIR speed */
+ if(mcs->speed < 576000) {
+ wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf);
+ }
+ /* MIR speed */
+ else if(mcs->speed == 576000 || mcs->speed == 1152000) {
+ wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf);
+ }
+ /* FIR speed */
+ else {
+ wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf);
+ }
+ usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev,
+ usb_sndbulkpipe(mcs->usbdev, mcs->ep_out),
+ mcs->out_buf, wraplen, mcs_send_irq, mcs);
+
+ if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {
+ IRDA_ERROR("failed tx_urb: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ mcs->stats.tx_errors++;
+ netif_start_queue(ndev);
+ }
+ } else {
+ mcs->stats.tx_packets++;
+ mcs->stats.tx_bytes += skb->len;
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&mcs->lock, flags);
+ return ret;
+}
+
+/*
+ * This function is called by the USB subsystem for each new device in the
+ * system. Need to verify the device and if it is, then start handling it.
+ */
+static int mcs_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct net_device *ndev = NULL;
+ struct mcs_cb *mcs;
+ int ret = -ENOMEM;
+
+ ndev = alloc_irdadev(sizeof(*mcs));
+ if (!ndev)
+ goto error1;
+
+ IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.", udev->devnum);
+
+ /* what is it realy for? */
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &intf->dev);
+
+ ret = usb_reset_configuration(udev);
+ if (ret != 0) {
+ IRDA_ERROR("mcs7780: usb reset configuration failed");
+ goto error2;
+ }
+
+ mcs = netdev_priv(ndev);
+ mcs->usbdev = udev;
+ mcs->netdev = ndev;
+ spin_lock_init(&mcs->lock);
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&mcs->qos);
+
+ /* That's the Rx capability. */
+ mcs->qos.baud_rate.bits &=
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200
+ | IR_576000 | IR_1152000 | (IR_4000000 << 8);
+
+
+ mcs->qos.min_turn_time.bits &= qos_mtt_bits;
+ irda_qos_bits_to_value(&mcs->qos);
+
+ /* Speed change work initialisation*/
+ INIT_WORK(&mcs->work, mcs_speed_work, mcs);
+
+ /* Override the network functions we need to use */
+ ndev->hard_start_xmit = mcs_hard_xmit;
+ ndev->open = mcs_net_open;
+ ndev->stop = mcs_net_close;
+ ndev->get_stats = mcs_net_get_stats;
+ ndev->do_ioctl = mcs_net_ioctl;
+
+ if (!intf->cur_altsetting)
+ goto error2;
+
+ ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint,
+ intf->cur_altsetting->desc.bNumEndpoints);
+ if (!ret) {
+ ret = -ENODEV;
+ goto error2;
+ }
+
+ ret = register_netdev(ndev);
+ if (ret != 0)
+ goto error2;
+
+ IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s",
+ ndev->name);
+
+ mcs->transceiver_type = transceiver_type;
+ mcs->sir_tweak = sir_tweak;
+ mcs->receive_mode = receive_mode;
+
+ usb_set_intfdata(intf, mcs);
+ return 0;
+
+ error2:
+ free_netdev(ndev);
+
+ error1:
+ return ret;
+}
+
+/* The current device is removed, the USB layer tells us to shut down. */
+static void mcs_disconnect(struct usb_interface *intf)
+{
+ struct mcs_cb *mcs = usb_get_intfdata(intf);
+
+ if (!mcs)
+ return;
+
+ flush_scheduled_work();
+
+ unregister_netdev(mcs->netdev);
+ free_netdev(mcs->netdev);
+
+ usb_set_intfdata(intf, NULL);
+ IRDA_DEBUG(0, "MCS7780 now disconnected.");
+}
+
+/* Module insertion */
+static int __init mcs_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&mcs_driver);
+ if (result)
+ IRDA_ERROR("usb_register failed. Error number %d", result);
+
+ return result;
+}
+module_init(mcs_init);
+
+/* Module removal */
+static void __exit mcs_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&mcs_driver);
+}
+module_exit(mcs_exit);
+
diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h
new file mode 100644
index 000000000000..1a723d725c2a
--- /dev/null
+++ b/drivers/net/irda/mcs7780.h
@@ -0,0 +1,167 @@
+/*****************************************************************************
+*
+* Filename: mcs7780.h
+* Version: 0.2-alpha
+* Description: Irda MosChip USB Dongle
+* Status: Experimental
+* Authors: Lukasz Stelmach <stlman@poczta.fm>
+* Brian Pugh <bpugh@cs.pdx.edu>
+*
+* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
+* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
+*
+* 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.
+*
+*****************************************************************************/
+#ifndef _MCS7780_H
+#define _MCS7780_H
+
+#define MCS_MODE_SIR 0
+#define MCS_MODE_MIR 1
+#define MCS_MODE_FIR 2
+
+#define MCS_CTRL_TIMEOUT 500
+#define MCS_XMIT_TIMEOUT 500
+/* Possible transceiver types */
+#define MCS_TSC_VISHAY 0 /* Vishay TFD, default choice */
+#define MCS_TSC_AGILENT 1 /* Agilent 3602/3600 */
+#define MCS_TSC_SHARP 2 /* Sharp GP2W1000YP */
+
+/* Requests */
+#define MCS_RD_RTYPE 0xC0
+#define MCS_WR_RTYPE 0x40
+#define MCS_RDREQ 0x0F
+#define MCS_WRREQ 0x0E
+
+/* Register 0x00 */
+#define MCS_MODE_REG 0
+#define MCS_FIR ((__u16)0x0001)
+#define MCS_SIR16US ((__u16)0x0002)
+#define MCS_BBTG ((__u16)0x0004)
+#define MCS_ASK ((__u16)0x0008)
+#define MCS_PARITY ((__u16)0x0010)
+
+/* SIR/MIR speed constants */
+#define MCS_SPEED_SHIFT 5
+#define MCS_SPEED_MASK ((__u16)0x00E0)
+#define MCS_SPEED(x) ((x & MCS_SPEED_MASK) >> MCS_SPEED_SHIFT)
+#define MCS_SPEED_2400 ((0 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_9600 ((1 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_19200 ((2 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_38400 ((3 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_57600 ((4 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_115200 ((5 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_576000 ((6 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+#define MCS_SPEED_1152000 ((7 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
+
+#define MCS_PLLPWDN ((__u16)0x0100)
+#define MCS_DRIVER ((__u16)0x0200)
+#define MCS_DTD ((__u16)0x0400)
+#define MCS_DIR ((__u16)0x0800)
+#define MCS_SIPEN ((__u16)0x1000)
+#define MCS_SENDSIP ((__u16)0x2000)
+#define MCS_CHGDIR ((__u16)0x4000)
+#define MCS_RESET ((__u16)0x8000)
+
+/* Register 0x02 */
+#define MCS_XCVR_REG 2
+#define MCS_MODE0 ((__u16)0x0001)
+#define MCS_STFIR ((__u16)0x0002)
+#define MCS_XCVR_CONF ((__u16)0x0004)
+#define MCS_RXFAST ((__u16)0x0008)
+/* TXCUR [6:4] */
+#define MCS_TXCUR_SHIFT 4
+#define MCS_TXCUR_MASK ((__u16)0x0070)
+#define MCS_TXCUR(x) ((x & MCS_TXCUR_MASK) >> MCS_TXCUR_SHIFT)
+#define MCS_SETTXCUR(x,y) \
+ ((x & ~MCS_TXCUR_MASK) | (y << MCS_TXCUR_SHIFT) & MCS_TXCUR_MASK)
+
+#define MCS_MODE1 ((__u16)0x0080)
+#define MCS_SMODE0 ((__u16)0x0100)
+#define MCS_SMODE1 ((__u16)0x0200)
+#define MCS_INVTX ((__u16)0x0400)
+#define MCS_INVRX ((__u16)0x0800)
+
+#define MCS_MINRXPW_REG 4
+
+#define MCS_RESV_REG 7
+#define MCS_IRINTX ((__u16)0x0001)
+#define MCS_IRINRX ((__u16)0x0002)
+
+struct mcs_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+ unsigned int speed; /* Current speed */
+ unsigned int new_speed; /* new speed */
+
+ struct work_struct work; /* Change speed work */
+
+ struct sk_buff *tx_pending;
+ char in_buf[4096]; /* transmit/receive buffer */
+ char out_buf[4096]; /* transmit/receive buffer */
+ __u8 *fifo_status;
+
+ iobuff_t rx_buff; /* receive unwrap state machine */
+ struct timeval rx_time;
+ spinlock_t lock;
+ int receiving;
+
+ __u8 ep_in;
+ __u8 ep_out;
+
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+
+ int transceiver_type;
+ int sir_tweak;
+ int receive_mode;
+};
+
+static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val);
+static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val);
+
+static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs);
+static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs);
+static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs);
+static inline int mcs_setup_transceiver(struct mcs_cb *mcs);
+static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf);
+static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf);
+static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf);
+static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len);
+static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len);
+static inline int mcs_setup_urbs(struct mcs_cb *mcs);
+static inline int mcs_receive_start(struct mcs_cb *mcs);
+static inline int mcs_find_endpoints(struct mcs_cb *mcs,
+ struct usb_host_endpoint *ep, int epnum);
+
+static int mcs_speed_change(struct mcs_cb *mcs);
+
+static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
+static int mcs_net_close(struct net_device *netdev);
+static int mcs_net_open(struct net_device *netdev);
+static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev);
+
+static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs);
+static void mcs_send_irq(struct urb *urb, struct pt_regs *regs);
+static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev);
+
+static int mcs_probe(struct usb_interface *intf,
+ const struct usb_device_id *id);
+static void mcs_disconnect(struct usb_interface *intf);
+
+#endif /* _MCS7780_H */
diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h
index f69fb4cec76f..9fa294a546d6 100644
--- a/drivers/net/irda/sir-dev.h
+++ b/drivers/net/irda/sir-dev.h
@@ -15,23 +15,14 @@
#define IRDA_SIR_H
#include <linux/netdevice.h>
+#include <linux/workqueue.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> // iobuff_t
-/* FIXME: unify irda_request with sir_fsm! */
-
-struct irda_request {
- struct list_head lh_request;
- unsigned long pending;
- void (*func)(void *);
- void *data;
- struct timer_list timer;
-};
-
struct sir_fsm {
struct semaphore sem;
- struct irda_request rq;
+ struct work_struct work;
unsigned state, substate;
int param;
int result;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index ea7c9464d46a..3b5854d10c17 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -23,6 +23,298 @@
#include "sir-dev.h"
+
+static struct workqueue_struct *irda_sir_wq;
+
+/* STATE MACHINE */
+
+/* substate handler of the config-fsm to handle the cases where we want
+ * to wait for transmit completion before changing the port configuration
+ */
+
+static int sirdev_tx_complete_fsm(struct sir_dev *dev)
+{
+ struct sir_fsm *fsm = &dev->fsm;
+ unsigned next_state, delay;
+ unsigned bytes_left;
+
+ do {
+ next_state = fsm->substate; /* default: stay in current substate */
+ delay = 0;
+
+ switch(fsm->substate) {
+
+ case SIRDEV_STATE_WAIT_XMIT:
+ if (dev->drv->chars_in_buffer)
+ bytes_left = dev->drv->chars_in_buffer(dev);
+ else
+ bytes_left = 0;
+ if (!bytes_left) {
+ next_state = SIRDEV_STATE_WAIT_UNTIL_SENT;
+ break;
+ }
+
+ if (dev->speed > 115200)
+ delay = (bytes_left*8*10000) / (dev->speed/100);
+ else if (dev->speed > 0)
+ delay = (bytes_left*10*10000) / (dev->speed/100);
+ else
+ delay = 0;
+ /* expected delay (usec) until remaining bytes are sent */
+ if (delay < 100) {
+ udelay(delay);
+ delay = 0;
+ break;
+ }
+ /* sleep some longer delay (msec) */
+ delay = (delay+999) / 1000;
+ break;
+
+ case SIRDEV_STATE_WAIT_UNTIL_SENT:
+ /* block until underlaying hardware buffer are empty */
+ if (dev->drv->wait_until_sent)
+ dev->drv->wait_until_sent(dev);
+ next_state = SIRDEV_STATE_TX_DONE;
+ break;
+
+ case SIRDEV_STATE_TX_DONE:
+ return 0;
+
+ default:
+ IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ fsm->substate = next_state;
+ } while (delay == 0);
+ return delay;
+}
+
+/*
+ * Function sirdev_config_fsm
+ *
+ * State machine to handle the configuration of the device (and attached dongle, if any).
+ * This handler is scheduled for execution in kIrDAd context, so we can sleep.
+ * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too
+ * long. Instead, for longer delays we start a timer to reschedule us later.
+ * On entry, fsm->sem is always locked and the netdev xmit queue stopped.
+ * Both must be unlocked/restarted on completion - but only on final exit.
+ */
+
+static void sirdev_config_fsm(void *data)
+{
+ struct sir_dev *dev = data;
+ struct sir_fsm *fsm = &dev->fsm;
+ int next_state;
+ int ret = -1;
+ unsigned delay;
+
+ IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies);
+
+ do {
+ IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
+ __FUNCTION__, fsm->state, fsm->substate);
+
+ next_state = fsm->state;
+ delay = 0;
+
+ switch(fsm->state) {
+
+ case SIRDEV_STATE_DONGLE_OPEN:
+ if (dev->dongle_drv != NULL) {
+ ret = sirdev_put_dongle(dev);
+ if (ret) {
+ fsm->result = -EINVAL;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+ }
+
+ /* Initialize dongle */
+ ret = sirdev_get_dongle(dev, fsm->param);
+ if (ret) {
+ fsm->result = ret;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+
+ /* Dongles are powered through the modem control lines which
+ * were just set during open. Before resetting, let's wait for
+ * the power to stabilize. This is what some dongle drivers did
+ * in open before, while others didn't - should be safe anyway.
+ */
+
+ delay = 50;
+ fsm->substate = SIRDEV_STATE_DONGLE_RESET;
+ next_state = SIRDEV_STATE_DONGLE_RESET;
+
+ fsm->param = 9600;
+
+ break;
+
+ case SIRDEV_STATE_DONGLE_CLOSE:
+ /* shouldn't we just treat this as success=? */
+ if (dev->dongle_drv == NULL) {
+ fsm->result = -EINVAL;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+
+ ret = sirdev_put_dongle(dev);
+ if (ret) {
+ fsm->result = ret;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+ next_state = SIRDEV_STATE_DONE;
+ break;
+
+ case SIRDEV_STATE_SET_DTR_RTS:
+ ret = sirdev_set_dtr_rts(dev,
+ (fsm->param&0x02) ? TRUE : FALSE,
+ (fsm->param&0x01) ? TRUE : FALSE);
+ next_state = SIRDEV_STATE_DONE;
+ break;
+
+ case SIRDEV_STATE_SET_SPEED:
+ fsm->substate = SIRDEV_STATE_WAIT_XMIT;
+ next_state = SIRDEV_STATE_DONGLE_CHECK;
+ break;
+
+ case SIRDEV_STATE_DONGLE_CHECK:
+ ret = sirdev_tx_complete_fsm(dev);
+ if (ret < 0) {
+ fsm->result = ret;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+ if ((delay=ret) != 0)
+ break;
+
+ if (dev->dongle_drv) {
+ fsm->substate = SIRDEV_STATE_DONGLE_RESET;
+ next_state = SIRDEV_STATE_DONGLE_RESET;
+ }
+ else {
+ dev->speed = fsm->param;
+ next_state = SIRDEV_STATE_PORT_SPEED;
+ }
+ break;
+
+ case SIRDEV_STATE_DONGLE_RESET:
+ if (dev->dongle_drv->reset) {
+ ret = dev->dongle_drv->reset(dev);
+ if (ret < 0) {
+ fsm->result = ret;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+ }
+ else
+ ret = 0;
+ if ((delay=ret) == 0) {
+ /* set serial port according to dongle default speed */
+ if (dev->drv->set_speed)
+ dev->drv->set_speed(dev, dev->speed);
+ fsm->substate = SIRDEV_STATE_DONGLE_SPEED;
+ next_state = SIRDEV_STATE_DONGLE_SPEED;
+ }
+ break;
+
+ case SIRDEV_STATE_DONGLE_SPEED:
+ if (dev->dongle_drv->reset) {
+ ret = dev->dongle_drv->set_speed(dev, fsm->param);
+ if (ret < 0) {
+ fsm->result = ret;
+ next_state = SIRDEV_STATE_ERROR;
+ break;
+ }
+ }
+ else
+ ret = 0;
+ if ((delay=ret) == 0)
+ next_state = SIRDEV_STATE_PORT_SPEED;
+ break;
+
+ case SIRDEV_STATE_PORT_SPEED:
+ /* Finally we are ready to change the serial port speed */
+ if (dev->drv->set_speed)
+ dev->drv->set_speed(dev, dev->speed);
+ dev->new_speed = 0;
+ next_state = SIRDEV_STATE_DONE;
+ break;
+
+ case SIRDEV_STATE_DONE:
+ /* Signal network layer so it can send more frames */
+ netif_wake_queue(dev->netdev);
+ next_state = SIRDEV_STATE_COMPLETE;
+ break;
+
+ default:
+ IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
+ fsm->result = -EINVAL;
+ /* fall thru */
+
+ case SIRDEV_STATE_ERROR:
+ IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result);
+
+#if 0 /* don't enable this before we have netdev->tx_timeout to recover */
+ netif_stop_queue(dev->netdev);
+#else
+ netif_wake_queue(dev->netdev);
+#endif
+ /* fall thru */
+
+ case SIRDEV_STATE_COMPLETE:
+ /* config change finished, so we are not busy any longer */
+ sirdev_enable_rx(dev);
+ up(&fsm->sem);
+ return;
+ }
+ fsm->state = next_state;
+ } while(!delay);
+
+ queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay));
+}
+
+/* schedule some device configuration task for execution by kIrDAd
+ * on behalf of the above state machine.
+ * can be called from process or interrupt/tasklet context.
+ */
+
+int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param)
+{
+ struct sir_fsm *fsm = &dev->fsm;
+
+ IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param);
+
+ if (down_trylock(&fsm->sem)) {
+ if (in_interrupt() || in_atomic() || irqs_disabled()) {
+ IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__);
+ return -EWOULDBLOCK;
+ } else
+ down(&fsm->sem);
+ }
+
+ if (fsm->state == SIRDEV_STATE_DEAD) {
+ /* race with sirdev_close should never happen */
+ IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__);
+ up(&fsm->sem);
+ return -ESTALE; /* or better EPIPE? */
+ }
+
+ netif_stop_queue(dev->netdev);
+ atomic_set(&dev->enable_rx, 0);
+
+ fsm->state = initial_state;
+ fsm->param = param;
+ fsm->result = 0;
+
+ INIT_WORK(&fsm->work, sirdev_config_fsm, dev);
+ queue_work(irda_sir_wq, &fsm->work);
+ return 0;
+}
+
+
/***************************************************************************/
void sirdev_enable_rx(struct sir_dev *dev)
@@ -619,10 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
spin_lock_init(&dev->tx_lock);
init_MUTEX(&dev->fsm.sem);
- INIT_LIST_HEAD(&dev->fsm.rq.lh_request);
- dev->fsm.rq.pending = 0;
- init_timer(&dev->fsm.rq.timer);
-
dev->drv = drv;
dev->netdev = ndev;
@@ -682,3 +970,22 @@ int sirdev_put_instance(struct sir_dev *dev)
}
EXPORT_SYMBOL(sirdev_put_instance);
+static int __init sir_wq_init(void)
+{
+ irda_sir_wq = create_singlethread_workqueue("irda_sir_wq");
+ if (!irda_sir_wq)
+ return -ENOMEM;
+ return 0;
+}
+
+static void __exit sir_wq_exit(void)
+{
+ destroy_workqueue(irda_sir_wq);
+}
+
+module_init(sir_wq_init);
+module_exit(sir_wq_exit);
+
+MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
+MODULE_DESCRIPTION("IrDA SIR core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c
deleted file mode 100644
index e3904d6bfecd..000000000000
--- a/drivers/net/irda/sir_kthread.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*********************************************************************
- *
- * sir_kthread.c: dedicated thread to process scheduled
- * sir device setup requests
- *
- * Copyright (c) 2002 Martin Diehl
- *
- * 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-/**************************************************************************
- *
- * kIrDAd kernel thread and config state machine
- *
- */
-
-struct irda_request_queue {
- struct list_head request_list;
- spinlock_t lock;
- task_t *thread;
- struct completion exit;
- wait_queue_head_t kick, done;
- atomic_t num_pending;
-};
-
-static struct irda_request_queue irda_rq_queue;
-
-static int irda_queue_request(struct irda_request *rq)
-{
- int ret = 0;
- unsigned long flags;
-
- if (!test_and_set_bit(0, &rq->pending)) {
- spin_lock_irqsave(&irda_rq_queue.lock, flags);
- list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
- wake_up(&irda_rq_queue.kick);
- atomic_inc(&irda_rq_queue.num_pending);
- spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
- ret = 1;
- }
- return ret;
-}
-
-static void irda_request_timer(unsigned long data)
-{
- struct irda_request *rq = (struct irda_request *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&irda_rq_queue.lock, flags);
- list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
- wake_up(&irda_rq_queue.kick);
- spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
-}
-
-static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay)
-{
- int ret = 0;
- struct timer_list *timer = &rq->timer;
-
- if (!test_and_set_bit(0, &rq->pending)) {
- timer->expires = jiffies + delay;
- timer->function = irda_request_timer;
- timer->data = (unsigned long)rq;
- atomic_inc(&irda_rq_queue.num_pending);
- add_timer(timer);
- ret = 1;
- }
- return ret;
-}
-
-static void run_irda_queue(void)
-{
- unsigned long flags;
- struct list_head *entry, *tmp;
- struct irda_request *rq;
-
- spin_lock_irqsave(&irda_rq_queue.lock, flags);
- list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) {
- rq = list_entry(entry, struct irda_request, lh_request);
- list_del_init(entry);
- spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
-
- clear_bit(0, &rq->pending);
- rq->func(rq->data);
-
- if (atomic_dec_and_test(&irda_rq_queue.num_pending))
- wake_up(&irda_rq_queue.done);
-
- spin_lock_irqsave(&irda_rq_queue.lock, flags);
- }
- spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
-}
-
-static int irda_thread(void *startup)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- daemonize("kIrDAd");
-
- irda_rq_queue.thread = current;
-
- complete((struct completion *)startup);
-
- while (irda_rq_queue.thread != NULL) {
-
- /* We use TASK_INTERRUPTIBLE, rather than
- * TASK_UNINTERRUPTIBLE. Andrew Morton made this
- * change ; he told me that it is safe, because "signal
- * blocking is now handled in daemonize()", he added
- * that the problem is that "uninterruptible sleep
- * contributes to load average", making user worry.
- * Jean II */
- set_task_state(current, TASK_INTERRUPTIBLE);
- add_wait_queue(&irda_rq_queue.kick, &wait);
- if (list_empty(&irda_rq_queue.request_list))
- schedule();
- else
- __set_task_state(current, TASK_RUNNING);
- remove_wait_queue(&irda_rq_queue.kick, &wait);
-
- /* make swsusp happy with our thread */
- try_to_freeze();
-
- run_irda_queue();
- }
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35)
- reparent_to_init();
-#endif
- complete_and_exit(&irda_rq_queue.exit, 0);
- /* never reached */
- return 0;
-}
-
-
-static void flush_irda_queue(void)
-{
- if (atomic_read(&irda_rq_queue.num_pending)) {
-
- DECLARE_WAITQUEUE(wait, current);
-
- if (!list_empty(&irda_rq_queue.request_list))
- run_irda_queue();
-
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- add_wait_queue(&irda_rq_queue.done, &wait);
- if (atomic_read(&irda_rq_queue.num_pending))
- schedule();
- else
- __set_task_state(current, TASK_RUNNING);
- remove_wait_queue(&irda_rq_queue.done, &wait);
- }
-}
-
-/* substate handler of the config-fsm to handle the cases where we want
- * to wait for transmit completion before changing the port configuration
- */
-
-static int irda_tx_complete_fsm(struct sir_dev *dev)
-{
- struct sir_fsm *fsm = &dev->fsm;
- unsigned next_state, delay;
- unsigned bytes_left;
-
- do {
- next_state = fsm->substate; /* default: stay in current substate */
- delay = 0;
-
- switch(fsm->substate) {
-
- case SIRDEV_STATE_WAIT_XMIT:
- if (dev->drv->chars_in_buffer)
- bytes_left = dev->drv->chars_in_buffer(dev);
- else
- bytes_left = 0;
- if (!bytes_left) {
- next_state = SIRDEV_STATE_WAIT_UNTIL_SENT;
- break;
- }
-
- if (dev->speed > 115200)
- delay = (bytes_left*8*10000) / (dev->speed/100);
- else if (dev->speed > 0)
- delay = (bytes_left*10*10000) / (dev->speed/100);
- else
- delay = 0;
- /* expected delay (usec) until remaining bytes are sent */
- if (delay < 100) {
- udelay(delay);
- delay = 0;
- break;
- }
- /* sleep some longer delay (msec) */
- delay = (delay+999) / 1000;
- break;
-
- case SIRDEV_STATE_WAIT_UNTIL_SENT:
- /* block until underlaying hardware buffer are empty */
- if (dev->drv->wait_until_sent)
- dev->drv->wait_until_sent(dev);
- next_state = SIRDEV_STATE_TX_DONE;
- break;
-
- case SIRDEV_STATE_TX_DONE:
- return 0;
-
- default:
- IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
- return -EINVAL;
- }
- fsm->substate = next_state;
- } while (delay == 0);
- return delay;
-}
-
-/*
- * Function irda_config_fsm
- *
- * State machine to handle the configuration of the device (and attached dongle, if any).
- * This handler is scheduled for execution in kIrDAd context, so we can sleep.
- * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too
- * long. Instead, for longer delays we start a timer to reschedule us later.
- * On entry, fsm->sem is always locked and the netdev xmit queue stopped.
- * Both must be unlocked/restarted on completion - but only on final exit.
- */
-
-static void irda_config_fsm(void *data)
-{
- struct sir_dev *dev = data;
- struct sir_fsm *fsm = &dev->fsm;
- int next_state;
- int ret = -1;
- unsigned delay;
-
- IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies);
-
- do {
- IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
- __FUNCTION__, fsm->state, fsm->substate);
-
- next_state = fsm->state;
- delay = 0;
-
- switch(fsm->state) {
-
- case SIRDEV_STATE_DONGLE_OPEN:
- if (dev->dongle_drv != NULL) {
- ret = sirdev_put_dongle(dev);
- if (ret) {
- fsm->result = -EINVAL;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
-
- /* Initialize dongle */
- ret = sirdev_get_dongle(dev, fsm->param);
- if (ret) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
-
- /* Dongles are powered through the modem control lines which
- * were just set during open. Before resetting, let's wait for
- * the power to stabilize. This is what some dongle drivers did
- * in open before, while others didn't - should be safe anyway.
- */
-
- delay = 50;
- fsm->substate = SIRDEV_STATE_DONGLE_RESET;
- next_state = SIRDEV_STATE_DONGLE_RESET;
-
- fsm->param = 9600;
-
- break;
-
- case SIRDEV_STATE_DONGLE_CLOSE:
- /* shouldn't we just treat this as success=? */
- if (dev->dongle_drv == NULL) {
- fsm->result = -EINVAL;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
-
- ret = sirdev_put_dongle(dev);
- if (ret) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_SET_DTR_RTS:
- ret = sirdev_set_dtr_rts(dev,
- (fsm->param&0x02) ? TRUE : FALSE,
- (fsm->param&0x01) ? TRUE : FALSE);
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_SET_SPEED:
- fsm->substate = SIRDEV_STATE_WAIT_XMIT;
- next_state = SIRDEV_STATE_DONGLE_CHECK;
- break;
-
- case SIRDEV_STATE_DONGLE_CHECK:
- ret = irda_tx_complete_fsm(dev);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- if ((delay=ret) != 0)
- break;
-
- if (dev->dongle_drv) {
- fsm->substate = SIRDEV_STATE_DONGLE_RESET;
- next_state = SIRDEV_STATE_DONGLE_RESET;
- }
- else {
- dev->speed = fsm->param;
- next_state = SIRDEV_STATE_PORT_SPEED;
- }
- break;
-
- case SIRDEV_STATE_DONGLE_RESET:
- if (dev->dongle_drv->reset) {
- ret = dev->dongle_drv->reset(dev);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
- else
- ret = 0;
- if ((delay=ret) == 0) {
- /* set serial port according to dongle default speed */
- if (dev->drv->set_speed)
- dev->drv->set_speed(dev, dev->speed);
- fsm->substate = SIRDEV_STATE_DONGLE_SPEED;
- next_state = SIRDEV_STATE_DONGLE_SPEED;
- }
- break;
-
- case SIRDEV_STATE_DONGLE_SPEED:
- if (dev->dongle_drv->reset) {
- ret = dev->dongle_drv->set_speed(dev, fsm->param);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
- else
- ret = 0;
- if ((delay=ret) == 0)
- next_state = SIRDEV_STATE_PORT_SPEED;
- break;
-
- case SIRDEV_STATE_PORT_SPEED:
- /* Finally we are ready to change the serial port speed */
- if (dev->drv->set_speed)
- dev->drv->set_speed(dev, dev->speed);
- dev->new_speed = 0;
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_DONE:
- /* Signal network layer so it can send more frames */
- netif_wake_queue(dev->netdev);
- next_state = SIRDEV_STATE_COMPLETE;
- break;
-
- default:
- IRDA_ERROR("%s - undefined state\n", __FUNCTION__);
- fsm->result = -EINVAL;
- /* fall thru */
-
- case SIRDEV_STATE_ERROR:
- IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result);
-
-#if 0 /* don't enable this before we have netdev->tx_timeout to recover */
- netif_stop_queue(dev->netdev);
-#else
- netif_wake_queue(dev->netdev);
-#endif
- /* fall thru */
-
- case SIRDEV_STATE_COMPLETE:
- /* config change finished, so we are not busy any longer */
- sirdev_enable_rx(dev);
- up(&fsm->sem);
- return;
- }
- fsm->state = next_state;
- } while(!delay);
-
- irda_queue_delayed_request(&fsm->rq, msecs_to_jiffies(delay));
-}
-
-/* schedule some device configuration task for execution by kIrDAd
- * on behalf of the above state machine.
- * can be called from process or interrupt/tasklet context.
- */
-
-int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param)
-{
- struct sir_fsm *fsm = &dev->fsm;
- int xmit_was_down;
-
- IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param);
-
- if (down_trylock(&fsm->sem)) {
- if (in_interrupt() || in_atomic() || irqs_disabled()) {
- IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__);
- return -EWOULDBLOCK;
- } else
- down(&fsm->sem);
- }
-
- if (fsm->state == SIRDEV_STATE_DEAD) {
- /* race with sirdev_close should never happen */
- IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__);
- up(&fsm->sem);
- return -ESTALE; /* or better EPIPE? */
- }
-
- xmit_was_down = netif_queue_stopped(dev->netdev);
- netif_stop_queue(dev->netdev);
- atomic_set(&dev->enable_rx, 0);
-
- fsm->state = initial_state;
- fsm->param = param;
- fsm->result = 0;
-
- INIT_LIST_HEAD(&fsm->rq.lh_request);
- fsm->rq.pending = 0;
- fsm->rq.func = irda_config_fsm;
- fsm->rq.data = dev;
-
- if (!irda_queue_request(&fsm->rq)) { /* returns 0 on error! */
- atomic_set(&dev->enable_rx, 1);
- if (!xmit_was_down)
- netif_wake_queue(dev->netdev);
- up(&fsm->sem);
- return -EAGAIN;
- }
- return 0;
-}
-
-static int __init irda_thread_create(void)
-{
- struct completion startup;
- int pid;
-
- spin_lock_init(&irda_rq_queue.lock);
- irda_rq_queue.thread = NULL;
- INIT_LIST_HEAD(&irda_rq_queue.request_list);
- init_waitqueue_head(&irda_rq_queue.kick);
- init_waitqueue_head(&irda_rq_queue.done);
- atomic_set(&irda_rq_queue.num_pending, 0);
-
- init_completion(&startup);
- pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES);
- if (pid <= 0)
- return -EAGAIN;
- else
- wait_for_completion(&startup);
-
- return 0;
-}
-
-static void __exit irda_thread_join(void)
-{
- if (irda_rq_queue.thread) {
- flush_irda_queue();
- init_completion(&irda_rq_queue.exit);
- irda_rq_queue.thread = NULL;
- wake_up(&irda_rq_queue.kick);
- wait_for_completion(&irda_rq_queue.exit);
- }
-}
-
-module_init(irda_thread_create);
-module_exit(irda_thread_join);
-
-MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
-MODULE_DESCRIPTION("IrDA SIR core");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 58f76cefbc83..a4674044bd6f 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -54,6 +54,7 @@
#include <linux/rtnetlink.h>
#include <linux/serial_reg.h>
#include <linux/dma-mapping.h>
+#include <linux/pnp.h>
#include <linux/platform_device.h>
#include <asm/io.h>
@@ -358,6 +359,16 @@ static inline void register_bank(int iobase, int bank)
iobase + IRCC_MASTER);
}
+#ifdef CONFIG_PNP
+/* PNP hotplug support */
+static const struct pnp_device_id smsc_ircc_pnp_table[] = {
+ { .id = "SMCf010", .driver_data = 0 },
+ /* and presumably others */
+ { }
+};
+MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
+#endif
+
/*******************************************************************************
*
@@ -2072,7 +2083,8 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
/* PROBING
*
- *
+ * REVISIT we can be told about the device by PNP, and should use that info
+ * instead of probing hardware and creating a platform_device ...
*/
static int __init smsc_ircc_look_for_chips(void)
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 31867e4b891b..d61b208b52a2 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -50,6 +50,7 @@
#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/crc32.h>
+#include <linux/kthread.h>
#include <net/irda/irda.h>
#include <net/irda/irlap.h>
#include <net/irda/irda_device.h>
@@ -173,9 +174,7 @@ struct stir_cb {
struct qos_info qos;
unsigned speed; /* Current speed */
- wait_queue_head_t thr_wait; /* transmit thread wakeup */
- struct completion thr_exited;
- pid_t thr_pid;
+ struct task_struct *thread; /* transmit thread */
struct sk_buff *tx_pending;
void *io_buf; /* transmit/receive buffer */
@@ -577,7 +576,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
SKB_LINEAR_ASSERT(skb);
skb = xchg(&stir->tx_pending, skb);
- wake_up(&stir->thr_wait);
+ wake_up_process(stir->thread);
/* this should never happen unless stop/wakeup problem */
if (unlikely(skb)) {
@@ -753,13 +752,7 @@ static int stir_transmit_thread(void *arg)
struct net_device *dev = stir->netdev;
struct sk_buff *skb;
- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
- while (netif_running(dev)
- && netif_device_present(dev)
- && !signal_pending(current))
- {
+ while (!kthread_should_stop()) {
#ifdef CONFIG_PM
/* if suspending, then power off and wait */
if (unlikely(freezing(current))) {
@@ -813,10 +806,11 @@ static int stir_transmit_thread(void *arg)
}
/* sleep if nothing to send */
- wait_event_interruptible(stir->thr_wait, stir->tx_pending);
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
- complete_and_exit (&stir->thr_exited, 0);
+ }
+ return 0;
}
@@ -859,7 +853,7 @@ static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
warn("%s: usb receive submit error: %d",
stir->netdev->name, err);
stir->receiving = 0;
- wake_up(&stir->thr_wait);
+ wake_up_process(stir->thread);
}
}
@@ -928,10 +922,10 @@ static int stir_net_open(struct net_device *netdev)
}
/** Start kernel thread for transmit. */
- stir->thr_pid = kernel_thread(stir_transmit_thread, stir,
- CLONE_FS|CLONE_FILES);
- if (stir->thr_pid < 0) {
- err = stir->thr_pid;
+ stir->thread = kthread_run(stir_transmit_thread, stir,
+ "%s", stir->netdev->name);
+ if (IS_ERR(stir->thread)) {
+ err = PTR_ERR(stir->thread);
err("stir4200: unable to start kernel thread");
goto err_out6;
}
@@ -968,8 +962,7 @@ static int stir_net_close(struct net_device *netdev)
netif_stop_queue(netdev);
/* Kill transmit thread */
- kill_proc(stir->thr_pid, SIGTERM, 1);
- wait_for_completion(&stir->thr_exited);
+ kthread_stop(stir->thread);
kfree(stir->fifo_status);
/* Mop up receive urb's */
@@ -1084,9 +1077,6 @@ static int stir_probe(struct usb_interface *intf,
stir->qos.min_turn_time.bits &= qos_mtt_bits;
irda_qos_bits_to_value(&stir->qos);
- init_completion (&stir->thr_exited);
- init_waitqueue_head (&stir->thr_wait);
-
/* Override the network functions we need to use */
net->hard_start_xmit = stir_hard_xmit;
net->open = stir_net_open;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 97a49e0be76b..d70b9e8d6e60 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|| (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
break;
udelay(100);
- /* must not sleep here - we are called under xmit_lock! */
+ /* must not sleep here - called under netif_tx_lock! */
}
}
diff --git a/drivers/net/ixgb/Makefile b/drivers/net/ixgb/Makefile
index 7c7aff1ea7d5..a8a2d3d03567 100644
--- a/drivers/net/ixgb/Makefile
+++ b/drivers/net/ixgb/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
#
-# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+# Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
#
# 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
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index c83271b38621..a83ef28dadb0 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -84,7 +84,12 @@ struct ixgb_adapter;
#define IXGB_DBG(args...)
#endif
-#define IXGB_ERR(args...) printk(KERN_ERR "ixgb: " args)
+#define PFX "ixgb: "
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+ (void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
+ __FUNCTION__ , ## args))
+
/* TX/RX descriptor defines */
#define DEFAULT_TXD 256
@@ -175,6 +180,7 @@ struct ixgb_adapter {
uint64_t hw_csum_tx_good;
uint64_t hw_csum_tx_error;
uint32_t tx_int_delay;
+ uint32_t tx_timeout_count;
boolean_t tx_int_delay_enable;
boolean_t detect_tx_hung;
@@ -192,7 +198,9 @@ struct ixgb_adapter {
/* structs defined in ixgb_hw.h */
struct ixgb_hw hw;
+ u16 msg_enable;
struct ixgb_hw_stats stats;
+ uint32_t alloc_rx_buff_failed;
#ifdef CONFIG_PCI_MSI
boolean_t have_msi;
#endif
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 661a46b95a61..8357c5590bfb 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
index 5190aa8761a2..bf6fa220f38e 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index d38ade5f2f4e..cf19b898ba9b 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -44,6 +44,8 @@ extern void ixgb_free_rx_resources(struct ixgb_adapter *adapter);
extern void ixgb_free_tx_resources(struct ixgb_adapter *adapter);
extern void ixgb_update_stats(struct ixgb_adapter *adapter);
+#define IXGB_ALL_RAR_ENTRIES 16
+
struct ixgb_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
@@ -76,6 +78,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_heartbeat_errors", IXGB_STAT(net_stats.tx_heartbeat_errors)},
{"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)},
{"tx_deferred_ok", IXGB_STAT(stats.dc)},
+ {"tx_timeout_count", IXGB_STAT(tx_timeout_count) },
{"rx_long_length_errors", IXGB_STAT(stats.roc)},
{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
#ifdef NETIF_F_TSO
@@ -117,6 +120,16 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
return 0;
}
+static void ixgb_set_speed_duplex(struct net_device *netdev)
+{
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+ /* be optimistic about our link, since we were up before */
+ adapter->link_speed = 10000;
+ adapter->link_duplex = FULL_DUPLEX;
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+}
+
static int
ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
@@ -130,12 +143,7 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ixgb_down(adapter, TRUE);
ixgb_reset(adapter);
ixgb_up(adapter);
- /* be optimistic about our link, since we were up before */
- adapter->link_speed = 10000;
- adapter->link_duplex = FULL_DUPLEX;
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
-
+ ixgb_set_speed_duplex(netdev);
} else
ixgb_reset(adapter);
@@ -183,11 +191,7 @@ ixgb_set_pauseparam(struct net_device *netdev,
if(netif_running(adapter->netdev)) {
ixgb_down(adapter, TRUE);
ixgb_up(adapter);
- /* be optimistic about our link, since we were up before */
- adapter->link_speed = 10000;
- adapter->link_duplex = FULL_DUPLEX;
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
+ ixgb_set_speed_duplex(netdev);
} else
ixgb_reset(adapter);
@@ -212,11 +216,7 @@ ixgb_set_rx_csum(struct net_device *netdev, uint32_t data)
if(netif_running(netdev)) {
ixgb_down(adapter,TRUE);
ixgb_up(adapter);
- /* be optimistic about our link, since we were up before */
- adapter->link_speed = 10000;
- adapter->link_duplex = FULL_DUPLEX;
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
+ ixgb_set_speed_duplex(netdev);
} else
ixgb_reset(adapter);
return 0;
@@ -251,6 +251,19 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data)
}
#endif /* NETIF_F_TSO */
+static uint32_t
+ixgb_get_msglevel(struct net_device *netdev)
+{
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void
+ixgb_set_msglevel(struct net_device *netdev, uint32_t data)
+{
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
#define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_
static int
@@ -303,7 +316,7 @@ ixgb_get_regs(struct net_device *netdev,
*reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */
/* there are 16 RAR entries in hardware, we only use 3 */
- for(i = 0; i < 16; i++) {
+ for(i = 0; i < IXGB_ALL_RAR_ENTRIES; i++) {
*reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */
*reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */
}
@@ -593,11 +606,7 @@ ixgb_set_ringparam(struct net_device *netdev,
adapter->tx_ring = tx_new;
if((err = ixgb_up(adapter)))
return err;
- /* be optimistic about our link, since we were up before */
- adapter->link_speed = 10000;
- adapter->link_duplex = FULL_DUPLEX;
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
+ ixgb_set_speed_duplex(netdev);
}
return 0;
@@ -714,6 +723,8 @@ static struct ethtool_ops ixgb_ethtool_ops = {
.set_tx_csum = ixgb_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
+ .get_msglevel = ixgb_get_msglevel,
+ .set_msglevel = ixgb_set_msglevel,
#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index 620cad48bdea..f7fa10e47fa2 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index 382c6300ccc2..cb4568915ada 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -57,6 +57,7 @@ typedef enum {
typedef enum {
ixgb_media_type_unknown = 0,
ixgb_media_type_fiber = 1,
+ ixgb_media_type_copper = 2,
ixgb_num_media_types
} ixgb_media_type;
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
index aee207eaa287..40a085f94c7b 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -43,6 +43,8 @@
#define IXGB_SUBDEVICE_ID_A11F 0xA11F
#define IXGB_SUBDEVICE_ID_A01F 0xA01F
-#endif /* #ifndef _IXGB_IDS_H_ */
+#define IXGB_DEVICE_ID_82597EX_CX4 0x109E
+#define IXGB_SUBDEVICE_ID_A00C 0xA00C
+#endif /* #ifndef _IXGB_IDS_H_ */
/* End of File */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index cfd67d812f0d..57006fb8840e 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -28,22 +28,6 @@
#include "ixgb.h"
-/* Change Log
- * 1.0.96 04/19/05
- * - Make needlessly global code static -- bunk@stusta.de
- * - ethtool cleanup -- shemminger@osdl.org
- * - Support for MODULE_VERSION -- linville@tuxdriver.com
- * - add skb_header_cloned check to the tso path -- herbert@apana.org.au
- * 1.0.88 01/05/05
- * - include fix to the condition that determines when to quit NAPI - Robert Olsson
- * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
- * 1.0.84 10/26/04
- * - reset buffer_info->dma in Tx resource cleanup logic
- * 1.0.83 10/12/04
- * - sparse cleanup - shemminger@osdl.org
- * - fix tx resource cleanup logic
- */
-
char ixgb_driver_name[] = "ixgb";
static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
@@ -52,9 +36,9 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "1.0.100-k2"DRIVERNAPI
+#define DRV_VERSION "1.0.109-k2"DRIVERNAPI
char ixgb_driver_version[] = DRV_VERSION;
-static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
+static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
/* ixgb_pci_tbl - PCI Device ID Table
*
@@ -67,6 +51,8 @@ static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
static struct pci_device_id ixgb_pci_tbl[] = {
{INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_CX4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_SR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_LR,
@@ -148,6 +134,11 @@ MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+static int debug = DEFAULT_DEBUG_LEVEL_SHIFT;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
/* some defines for controlling descriptor fetches in h/w */
#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */
#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
@@ -196,7 +187,7 @@ module_exit(ixgb_exit_module);
* @adapter: board private structure
**/
-static inline void
+static void
ixgb_irq_disable(struct ixgb_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
@@ -210,7 +201,7 @@ ixgb_irq_disable(struct ixgb_adapter *adapter)
* @adapter: board private structure
**/
-static inline void
+static void
ixgb_irq_enable(struct ixgb_adapter *adapter)
{
if(atomic_dec_and_test(&adapter->irq_sem)) {
@@ -231,6 +222,7 @@ ixgb_up(struct ixgb_adapter *adapter)
/* hardware has been reset, we need to reload some things */
+ ixgb_rar_set(hw, netdev->dev_addr, 0);
ixgb_set_multi(netdev);
ixgb_restore_vlan(adapter);
@@ -240,6 +232,9 @@ ixgb_up(struct ixgb_adapter *adapter)
ixgb_configure_rx(adapter);
ixgb_alloc_rx_buffers(adapter);
+ /* disable interrupts and get the hardware into a known state */
+ IXGB_WRITE_REG(&adapter->hw, IMC, 0xffffffff);
+
#ifdef CONFIG_PCI_MSI
{
boolean_t pcix = (IXGB_READ_REG(&adapter->hw, STATUS) &
@@ -249,7 +244,7 @@ ixgb_up(struct ixgb_adapter *adapter)
if (!pcix)
adapter->have_msi = FALSE;
else if((err = pci_enable_msi(adapter->pdev))) {
- printk (KERN_ERR
+ DPRINTK(PROBE, ERR,
"Unable to allocate MSI interrupt Error: %d\n", err);
adapter->have_msi = FALSE;
/* proceed to try to request regular interrupt */
@@ -259,11 +254,11 @@ ixgb_up(struct ixgb_adapter *adapter)
#endif
if((err = request_irq(adapter->pdev->irq, &ixgb_intr,
SA_SHIRQ | SA_SAMPLE_RANDOM,
- netdev->name, netdev)))
+ netdev->name, netdev))) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate interrupt Error: %d\n", err);
return err;
-
- /* disable interrupts and get the hardware into a known state */
- IXGB_WRITE_REG(&adapter->hw, IMC, 0xffffffff);
+ }
if((hw->max_frame_size != max_frame) ||
(hw->max_frame_size !=
@@ -285,11 +280,12 @@ ixgb_up(struct ixgb_adapter *adapter)
}
mod_timer(&adapter->watchdog_timer, jiffies);
- ixgb_irq_enable(adapter);
#ifdef CONFIG_IXGB_NAPI
netif_poll_enable(netdev);
#endif
+ ixgb_irq_enable(adapter);
+
return 0;
}
@@ -326,7 +322,7 @@ ixgb_reset(struct ixgb_adapter *adapter)
ixgb_adapter_stop(&adapter->hw);
if(!ixgb_init_hw(&adapter->hw))
- IXGB_DBG("ixgb_init_hw failed.\n");
+ DPRINTK(PROBE, ERR, "ixgb_init_hw failed.\n");
}
/**
@@ -363,7 +359,8 @@ ixgb_probe(struct pci_dev *pdev,
} else {
if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
(err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
- IXGB_ERR("No usable DMA configuration, aborting\n");
+ printk(KERN_ERR
+ "ixgb: No usable DMA configuration, aborting\n");
goto err_dma_mask;
}
pci_using_dac = 0;
@@ -388,6 +385,7 @@ ixgb_probe(struct pci_dev *pdev,
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.back = adapter;
+ adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT);
mmio_start = pci_resource_start(pdev, BAR_0);
mmio_len = pci_resource_len(pdev, BAR_0);
@@ -416,7 +414,7 @@ ixgb_probe(struct pci_dev *pdev,
netdev->change_mtu = &ixgb_change_mtu;
ixgb_set_ethtool_ops(netdev);
netdev->tx_timeout = &ixgb_tx_timeout;
- netdev->watchdog_timeo = HZ;
+ netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_IXGB_NAPI
netdev->poll = &ixgb_clean;
netdev->weight = 64;
@@ -428,6 +426,7 @@ ixgb_probe(struct pci_dev *pdev,
netdev->poll_controller = ixgb_netpoll;
#endif
+ strcpy(netdev->name, pci_name(pdev));
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;
@@ -449,6 +448,9 @@ ixgb_probe(struct pci_dev *pdev,
#ifdef NETIF_F_TSO
netdev->features |= NETIF_F_TSO;
#endif
+#ifdef NETIF_F_LLTX
+ netdev->features |= NETIF_F_LLTX;
+#endif
if(pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -456,7 +458,7 @@ ixgb_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if(!ixgb_validate_eeprom_checksum(&adapter->hw)) {
- printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n");
+ DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
err = -EIO;
goto err_eeprom;
}
@@ -465,6 +467,7 @@ ixgb_probe(struct pci_dev *pdev,
memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
if(!is_valid_ether_addr(netdev->perm_addr)) {
+ DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
}
@@ -478,6 +481,7 @@ ixgb_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->tx_timeout_task,
(void (*)(void *))ixgb_tx_timeout_task, netdev);
+ strcpy(netdev->name, "eth%d");
if((err = register_netdev(netdev)))
goto err_register;
@@ -486,8 +490,7 @@ ixgb_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- printk(KERN_INFO "%s: Intel(R) PRO/10GbE Network Connection\n",
- netdev->name);
+ DPRINTK(PROBE, INFO, "Intel(R) PRO/10GbE Network Connection\n");
ixgb_check_options(adapter);
/* reset the hardware with the new settings */
@@ -557,17 +560,17 @@ ixgb_sw_init(struct ixgb_adapter *adapter)
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_id = pdev->subsystem_device;
- adapter->rx_buffer_len = IXGB_RXBUFFER_2048;
-
hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
+ adapter->rx_buffer_len = hw->max_frame_size;
if((hw->device_id == IXGB_DEVICE_ID_82597EX)
- ||(hw->device_id == IXGB_DEVICE_ID_82597EX_LR)
- ||(hw->device_id == IXGB_DEVICE_ID_82597EX_SR))
+ || (hw->device_id == IXGB_DEVICE_ID_82597EX_CX4)
+ || (hw->device_id == IXGB_DEVICE_ID_82597EX_LR)
+ || (hw->device_id == IXGB_DEVICE_ID_82597EX_SR))
hw->mac_type = ixgb_82597;
else {
/* should never have loaded on this device */
- printk(KERN_ERR "ixgb: unsupported device id\n");
+ DPRINTK(PROBE, ERR, "unsupported device id\n");
}
/* enable flow control to be programmed */
@@ -665,6 +668,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
size = sizeof(struct ixgb_buffer) * txdr->count;
txdr->buffer_info = vmalloc(size);
if(!txdr->buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate transmit descriptor ring memory\n");
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
@@ -677,6 +682,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
if(!txdr->desc) {
vfree(txdr->buffer_info);
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate transmit descriptor memory\n");
return -ENOMEM;
}
memset(txdr->desc, 0, txdr->size);
@@ -750,6 +757,8 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
size = sizeof(struct ixgb_buffer) * rxdr->count;
rxdr->buffer_info = vmalloc(size);
if(!rxdr->buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate receive descriptor ring\n");
return -ENOMEM;
}
memset(rxdr->buffer_info, 0, size);
@@ -763,6 +772,8 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
if(!rxdr->desc) {
vfree(rxdr->buffer_info);
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate receive descriptors\n");
return -ENOMEM;
}
memset(rxdr->desc, 0, rxdr->size);
@@ -794,21 +805,14 @@ ixgb_setup_rctl(struct ixgb_adapter *adapter)
rctl |= IXGB_RCTL_SECRC;
- switch (adapter->rx_buffer_len) {
- case IXGB_RXBUFFER_2048:
- default:
+ if (adapter->rx_buffer_len <= IXGB_RXBUFFER_2048)
rctl |= IXGB_RCTL_BSIZE_2048;
- break;
- case IXGB_RXBUFFER_4096:
+ else if (adapter->rx_buffer_len <= IXGB_RXBUFFER_4096)
rctl |= IXGB_RCTL_BSIZE_4096;
- break;
- case IXGB_RXBUFFER_8192:
+ else if (adapter->rx_buffer_len <= IXGB_RXBUFFER_8192)
rctl |= IXGB_RCTL_BSIZE_8192;
- break;
- case IXGB_RXBUFFER_16384:
+ else if (adapter->rx_buffer_len <= IXGB_RXBUFFER_16384)
rctl |= IXGB_RCTL_BSIZE_16384;
- break;
- }
IXGB_WRITE_REG(&adapter->hw, RCTL, rctl);
}
@@ -898,22 +902,25 @@ ixgb_free_tx_resources(struct ixgb_adapter *adapter)
adapter->tx_ring.desc = NULL;
}
-static inline void
+static void
ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter,
struct ixgb_buffer *buffer_info)
{
struct pci_dev *pdev = adapter->pdev;
- if(buffer_info->dma) {
- pci_unmap_page(pdev,
- buffer_info->dma,
- buffer_info->length,
- PCI_DMA_TODEVICE);
- buffer_info->dma = 0;
- }
- if(buffer_info->skb) {
+
+ if (buffer_info->dma)
+ pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
+ PCI_DMA_TODEVICE);
+
+ if (buffer_info->skb)
dev_kfree_skb_any(buffer_info->skb);
- buffer_info->skb = NULL;
- }
+
+ buffer_info->skb = NULL;
+ buffer_info->dma = 0;
+ buffer_info->time_stamp = 0;
+ /* these fields must always be initialized in tx
+ * buffer_info->length = 0;
+ * buffer_info->next_to_watch = 0; */
}
/**
@@ -1112,8 +1119,8 @@ ixgb_watchdog(unsigned long data)
if(adapter->hw.link_up) {
if(!netif_carrier_ok(netdev)) {
- printk(KERN_INFO "ixgb: %s NIC Link is Up %d Mbps %s\n",
- netdev->name, 10000, "Full Duplex");
+ DPRINTK(LINK, INFO,
+ "NIC Link is Up 10000 Mbps Full Duplex\n");
adapter->link_speed = 10000;
adapter->link_duplex = FULL_DUPLEX;
netif_carrier_on(netdev);
@@ -1123,9 +1130,7 @@ ixgb_watchdog(unsigned long data)
if(netif_carrier_ok(netdev)) {
adapter->link_speed = 0;
adapter->link_duplex = 0;
- printk(KERN_INFO
- "ixgb: %s NIC Link is Down\n",
- netdev->name);
+ DPRINTK(LINK, INFO, "NIC Link is Down\n");
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -1158,7 +1163,7 @@ ixgb_watchdog(unsigned long data)
#define IXGB_TX_FLAGS_VLAN 0x00000002
#define IXGB_TX_FLAGS_TSO 0x00000004
-static inline int
+static int
ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
@@ -1220,7 +1225,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
return 0;
}
-static inline boolean_t
+static boolean_t
ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb)
{
struct ixgb_context_desc *context_desc;
@@ -1258,7 +1263,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb)
#define IXGB_MAX_TXD_PWR 14
#define IXGB_MAX_DATA_PER_TXD (1<<IXGB_MAX_TXD_PWR)
-static inline int
+static int
ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
unsigned int first)
{
@@ -1284,6 +1289,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
size,
PCI_DMA_TODEVICE);
buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = 0;
len -= size;
offset += size;
@@ -1309,6 +1315,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
size,
PCI_DMA_TODEVICE);
buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = 0;
len -= size;
offset += size;
@@ -1323,7 +1330,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
return count;
}
-static inline void
+static void
ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
{
struct ixgb_desc_ring *tx_ring = &adapter->tx_ring;
@@ -1395,13 +1402,26 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return 0;
}
+#ifdef NETIF_F_LLTX
+ local_irq_save(flags);
+ if (!spin_trylock(&adapter->tx_lock)) {
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
+#else
spin_lock_irqsave(&adapter->tx_lock, flags);
+#endif
+
if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED)) {
netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
- return 1;
+ return NETDEV_TX_BUSY;
}
+
+#ifndef NETIF_F_LLTX
spin_unlock_irqrestore(&adapter->tx_lock, flags);
+#endif
if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
tx_flags |= IXGB_TX_FLAGS_VLAN;
@@ -1413,10 +1433,13 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tso = ixgb_tso(adapter, skb);
if (tso < 0) {
dev_kfree_skb_any(skb);
+#ifdef NETIF_F_LLTX
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+#endif
return NETDEV_TX_OK;
}
- if (tso)
+ if (likely(tso))
tx_flags |= IXGB_TX_FLAGS_TSO;
else if(ixgb_tx_csum(adapter, skb))
tx_flags |= IXGB_TX_FLAGS_CSUM;
@@ -1426,7 +1449,15 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
- return 0;
+#ifdef NETIF_F_LLTX
+ /* Make sure there is space in the ring for the next send. */
+ if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED))
+ netif_stop_queue(netdev);
+
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+
+#endif
+ return NETDEV_TX_OK;
}
/**
@@ -1448,6 +1479,7 @@ ixgb_tx_timeout_task(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
+ adapter->tx_timeout_count++;
ixgb_down(adapter, TRUE);
ixgb_up(adapter);
}
@@ -1486,28 +1518,15 @@ ixgb_change_mtu(struct net_device *netdev, int new_mtu)
if((max_frame < IXGB_MIN_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH)
|| (max_frame > IXGB_MAX_JUMBO_FRAME_SIZE + ENET_FCS_LENGTH)) {
- IXGB_ERR("Invalid MTU setting\n");
+ DPRINTK(PROBE, ERR, "Invalid MTU setting %d\n", new_mtu);
return -EINVAL;
}
- if((max_frame <= IXGB_MAX_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH)
- || (max_frame <= IXGB_RXBUFFER_2048)) {
- adapter->rx_buffer_len = IXGB_RXBUFFER_2048;
-
- } else if(max_frame <= IXGB_RXBUFFER_4096) {
- adapter->rx_buffer_len = IXGB_RXBUFFER_4096;
-
- } else if(max_frame <= IXGB_RXBUFFER_8192) {
- adapter->rx_buffer_len = IXGB_RXBUFFER_8192;
-
- } else {
- adapter->rx_buffer_len = IXGB_RXBUFFER_16384;
- }
+ adapter->rx_buffer_len = max_frame;
netdev->mtu = new_mtu;
- if(old_max_frame != max_frame && netif_running(netdev)) {
-
+ if ((old_max_frame != max_frame) && netif_running(netdev)) {
ixgb_down(adapter, TRUE);
ixgb_up(adapter);
}
@@ -1765,23 +1784,43 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
tx_ring->next_to_clean = i;
- spin_lock(&adapter->tx_lock);
- if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
- (IXGB_DESC_UNUSED(tx_ring) > IXGB_TX_QUEUE_WAKE)) {
-
- netif_wake_queue(netdev);
+ if (unlikely(netif_queue_stopped(netdev))) {
+ spin_lock(&adapter->tx_lock);
+ if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
+ (IXGB_DESC_UNUSED(tx_ring) > IXGB_TX_QUEUE_WAKE))
+ netif_wake_queue(netdev);
+ spin_unlock(&adapter->tx_lock);
}
- spin_unlock(&adapter->tx_lock);
if(adapter->detect_tx_hung) {
/* detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
adapter->detect_tx_hung = FALSE;
- if(tx_ring->buffer_info[i].dma &&
- time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ)
+ if (tx_ring->buffer_info[eop].dma &&
+ time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + HZ)
&& !(IXGB_READ_REG(&adapter->hw, STATUS) &
- IXGB_STATUS_TXOFF))
+ IXGB_STATUS_TXOFF)) {
+ /* detected Tx unit hang */
+ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%x>\n"
+ " jiffies <%lx>\n"
+ " next_to_watch.status <%x>\n",
+ IXGB_READ_REG(&adapter->hw, TDH),
+ IXGB_READ_REG(&adapter->hw, TDT),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_ring->buffer_info[eop].time_stamp,
+ eop,
+ jiffies,
+ eop_desc->status);
netif_stop_queue(netdev);
+ }
}
return cleaned;
@@ -1794,7 +1833,7 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
* @sk_buff: socket buffer with received data
**/
-static inline void
+static void
ixgb_rx_checksum(struct ixgb_adapter *adapter,
struct ixgb_rx_desc *rx_desc,
struct sk_buff *skb)
@@ -1858,6 +1897,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter)
#endif
status = rx_desc->status;
skb = buffer_info->skb;
+ buffer_info->skb = NULL;
prefetch(skb->data);
@@ -1902,6 +1942,26 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter)
goto rxdesc_done;
}
+ /* code added for copybreak, this should improve
+ * performance for small packets with large amounts
+ * of reassembly being done in the stack */
+#define IXGB_CB_LENGTH 256
+ if (length < IXGB_CB_LENGTH) {
+ struct sk_buff *new_skb =
+ dev_alloc_skb(length + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+ new_skb->dev = netdev;
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ length + NET_IP_ALIGN);
+ /* save the skb in buffer_info as good */
+ buffer_info->skb = skb;
+ skb = new_skb;
+ }
+ }
+ /* end copybreak code */
+
/* Good Receive */
skb_put(skb, length);
@@ -1931,7 +1991,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter)
rxdesc_done:
/* clean up descriptor, might be written over by hw */
rx_desc->status = 0;
- buffer_info->skb = NULL;
/* use prefetched values */
rx_desc = next_rxd;
@@ -1971,12 +2030,18 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
/* leave three descriptors unused */
while(--cleancount > 2) {
- rx_desc = IXGB_RX_DESC(*rx_ring, i);
-
- skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ /* recycle! its good for you */
+ if (!(skb = buffer_info->skb))
+ skb = dev_alloc_skb(adapter->rx_buffer_len
+ + NET_IP_ALIGN);
+ else {
+ skb_trim(skb, 0);
+ goto map_skb;
+ }
- if(unlikely(!skb)) {
+ if (unlikely(!skb)) {
/* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
break;
}
@@ -1990,33 +2055,36 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
- buffer_info->dma =
- pci_map_single(pdev,
- skb->data,
- adapter->rx_buffer_len,
- PCI_DMA_FROMDEVICE);
+map_skb:
+ buffer_info->dma = pci_map_single(pdev,
+ skb->data,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ rx_desc = IXGB_RX_DESC(*rx_ring, i);
rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);
/* guarantee DD bit not set now before h/w gets descriptor
* this is the rest of the workaround for h/w double
* writeback. */
rx_desc->status = 0;
- if((i & ~(num_group_tail_writes- 1)) == i) {
- /* Force memory writes to complete before letting h/w
- * know there are new descriptors to fetch. (Only
- * applicable for weak-ordered memory model archs,
- * such as IA-64). */
- wmb();
-
- IXGB_WRITE_REG(&adapter->hw, RDT, i);
- }
if(++i == rx_ring->count) i = 0;
buffer_info = &rx_ring->buffer_info[i];
}
- rx_ring->next_to_use = i;
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(i-- == 0))
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs, such
+ * as IA-64). */
+ wmb();
+ IXGB_WRITE_REG(&adapter->hw, RDT, i);
+ }
}
/**
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
index dba20481ee80..ee982feac64d 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index 8a83dfdf746d..39fbed29a3df 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
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
@@ -76,7 +76,7 @@ IXGB_PARAM(RxDescriptors, "Number of receive descriptors");
* - 2 - Tx only, generate PAUSE frames but ignore them on receive
* - 3 - Full Flow Control Support
*
- * Default Value: Read flow control settings from the EEPROM
+ * Default Value: 2 - Tx only (silicon bug avoidance)
*/
IXGB_PARAM(FlowControl, "Flow Control setting");
@@ -137,7 +137,7 @@ IXGB_PARAM(RxFCLowThresh, "Receive Flow Control Low Threshold");
*
* Valid Range: 1 - 65535
*
- * Default Value: 256 (0x100)
+ * Default Value: 65535 (0xffff) (we'll send an xon if we recover)
*/
IXGB_PARAM(FCReqTimeout, "Flow Control Request Timeout");
@@ -165,8 +165,6 @@ IXGB_PARAM(IntDelayEnable, "Transmit Interrupt Delay Enable");
#define XSUMRX_DEFAULT OPTION_ENABLED
-#define FLOW_CONTROL_FULL ixgb_fc_full
-#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
#define DEFAULT_FCRTL 0x28000
#define DEFAULT_FCRTH 0x30000
#define MIN_FCRTL 0
@@ -174,9 +172,9 @@ IXGB_PARAM(IntDelayEnable, "Transmit Interrupt Delay Enable");
#define MIN_FCRTH 8
#define MAX_FCRTH 0x3FFF0
-#define DEFAULT_FCPAUSE 0x100 /* this may be too long */
#define MIN_FCPAUSE 1
#define MAX_FCPAUSE 0xffff
+#define DEFAULT_FCPAUSE 0xFFFF /* this may be too long */
struct ixgb_option {
enum { enable_option, range_option, list_option } type;
@@ -336,7 +334,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
- .def = ixgb_fc_full,
+ .def = ixgb_fc_tx_pause,
.arg = { .l = { .nr = LIST_LEN(fc_list),
.p = fc_list }}
};
@@ -365,8 +363,8 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
adapter->hw.fc.high_water = opt.def;
}
- if(!(adapter->hw.fc.type & ixgb_fc_rx_pause) )
- printk (KERN_INFO
+ if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
+ printk (KERN_INFO
"Ignoring RxFCHighThresh when no RxFC\n");
}
{ /* Receive Flow Control Low Threshold */
@@ -385,8 +383,8 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
adapter->hw.fc.low_water = opt.def;
}
- if(!(adapter->hw.fc.type & ixgb_fc_rx_pause) )
- printk (KERN_INFO
+ if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
+ printk (KERN_INFO
"Ignoring RxFCLowThresh when no RxFC\n");
}
{ /* Flow Control Pause Time Request*/
@@ -406,12 +404,12 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
adapter->hw.fc.pause_time = opt.def;
}
- if(!(adapter->hw.fc.type & ixgb_fc_rx_pause) )
- printk (KERN_INFO
+ if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
+ printk (KERN_INFO
"Ignoring FCReqTimeout when no RxFC\n");
}
/* high low and spacing check for rx flow control thresholds */
- if (adapter->hw.fc.type & ixgb_fc_rx_pause) {
+ if (adapter->hw.fc.type & ixgb_fc_tx_pause) {
/* high must be greater than low */
if (adapter->hw.fc.high_water < (adapter->hw.fc.low_water + 8)) {
/* set defaults */
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
index 6f7dce8eba51..b67f586d7392 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -149,6 +149,8 @@ static void enp2611_check_link_status(unsigned long __dummy)
int status;
dev = nds[i];
+ if (dev == NULL)
+ continue;
status = pm3386_is_link_up(i);
if (status && !netif_carrier_ok(dev)) {
@@ -191,6 +193,7 @@ static void enp2611_set_port_admin_status(int port, int up)
static int __init enp2611_init_module(void)
{
+ int ports;
int i;
if (!machine_is_enp2611())
@@ -199,7 +202,8 @@ static int __init enp2611_init_module(void)
caleb_reset();
pm3386_reset();
- for (i = 0; i < 3; i++) {
+ ports = pm3386_port_count();
+ for (i = 0; i < ports; i++) {
nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
if (nds[i] == NULL) {
while (--i >= 0)
@@ -215,9 +219,10 @@ static int __init enp2611_init_module(void)
ixp2400_msf_init(&enp2611_msf_parameters);
- if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) {
- for (i = 0; i < 3; i++)
- free_netdev(nds[i]);
+ if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) {
+ for (i = 0; i < ports; i++)
+ if (nds[i])
+ free_netdev(nds[i]);
return -EINVAL;
}
diff --git a/drivers/net/ixp2000/pm3386.c b/drivers/net/ixp2000/pm3386.c
index 5c7ab7564053..5224651c9aac 100644
--- a/drivers/net/ixp2000/pm3386.c
+++ b/drivers/net/ixp2000/pm3386.c
@@ -86,40 +86,53 @@ static void pm3386_port_reg_write(int port, int _reg, int spacing, u16 value)
pm3386_reg_write(port >> 1, reg, value);
}
+int pm3386_secondary_present(void)
+{
+ return pm3386_reg_read(1, 0) == 0x3386;
+}
void pm3386_reset(void)
{
u8 mac[3][6];
+ int secondary;
+
+ secondary = pm3386_secondary_present();
/* Save programmed MAC addresses. */
pm3386_get_mac(0, mac[0]);
pm3386_get_mac(1, mac[1]);
- pm3386_get_mac(2, mac[2]);
+ if (secondary)
+ pm3386_get_mac(2, mac[2]);
/* Assert analog and digital reset. */
pm3386_reg_write(0, 0x002, 0x0060);
- pm3386_reg_write(1, 0x002, 0x0060);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0060);
mdelay(1);
/* Deassert analog reset. */
pm3386_reg_write(0, 0x002, 0x0062);
- pm3386_reg_write(1, 0x002, 0x0062);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0062);
mdelay(10);
/* Deassert digital reset. */
pm3386_reg_write(0, 0x002, 0x0063);
- pm3386_reg_write(1, 0x002, 0x0063);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0063);
mdelay(10);
/* Restore programmed MAC addresses. */
pm3386_set_mac(0, mac[0]);
pm3386_set_mac(1, mac[1]);
- pm3386_set_mac(2, mac[2]);
+ if (secondary)
+ pm3386_set_mac(2, mac[2]);
/* Disable carrier on all ports. */
pm3386_set_carrier(0, 0);
pm3386_set_carrier(1, 0);
- pm3386_set_carrier(2, 0);
+ if (secondary)
+ pm3386_set_carrier(2, 0);
}
static u16 swaph(u16 x)
@@ -127,6 +140,11 @@ static u16 swaph(u16 x)
return ((x << 8) | (x >> 8)) & 0xffff;
}
+int pm3386_port_count(void)
+{
+ return 2 + pm3386_secondary_present();
+}
+
void pm3386_init_port(int port)
{
int pm = port >> 1;
diff --git a/drivers/net/ixp2000/pm3386.h b/drivers/net/ixp2000/pm3386.h
index fe92bb056ac4..cc4183dca911 100644
--- a/drivers/net/ixp2000/pm3386.h
+++ b/drivers/net/ixp2000/pm3386.h
@@ -13,6 +13,7 @@
#define __PM3386_H
void pm3386_reset(void);
+int pm3386_port_count(void);
void pm3386_init_port(int port);
void pm3386_get_mac(int port, u8 *mac);
void pm3386_set_mac(int port, u8 *mac);
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index ea62a3e7d586..625ff61c9988 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1200,7 +1200,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (has_tiny_unaligned_frags(skb)) {
- if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
+ if (__skb_linearize(skb)) {
stats->tx_dropped++;
printk(KERN_DEBUG "%s: failed to linearize tiny "
"unaligned fragment\n", dev->name);
@@ -1419,6 +1419,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mv643xx_eth_update_pscr(dev, &cmd);
mv643xx_set_settings(dev, &cmd);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
err = register_netdev(dev);
if (err)
goto out;
diff --git a/drivers/net/myri10ge/Makefile b/drivers/net/myri10ge/Makefile
new file mode 100644
index 000000000000..5df891647aee
--- /dev/null
+++ b/drivers/net/myri10ge/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Myricom Myri-10G ethernet driver
+#
+
+obj-$(CONFIG_MYRI10GE) += myri10ge.o
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
new file mode 100644
index 000000000000..e1feb58bd661
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -0,0 +1,2869 @@
+/*************************************************************************
+ * myri10ge.c: Myricom Myri-10G Ethernet driver.
+ *
+ * Copyright (C) 2005, 2006 Myricom, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Myricom, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * If the eeprom on your board is not recent enough, you will need to get a
+ * newer firmware image at:
+ * http://www.myri.com/scs/download-Myri10GE.html
+ *
+ * Contact Information:
+ * <help@myri.com>
+ * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006
+ *************************************************************************/
+
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/vmalloc.h>
+#include <linux/crc32.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <net/checksum.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "myri10ge_mcp.h"
+#include "myri10ge_mcp_gen_header.h"
+
+#define MYRI10GE_VERSION_STR "1.0.0"
+
+MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
+MODULE_AUTHOR("Maintainer: help@myri.com");
+MODULE_VERSION(MYRI10GE_VERSION_STR);
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define MYRI10GE_MAX_ETHER_MTU 9014
+
+#define MYRI10GE_ETH_STOPPED 0
+#define MYRI10GE_ETH_STOPPING 1
+#define MYRI10GE_ETH_STARTING 2
+#define MYRI10GE_ETH_RUNNING 3
+#define MYRI10GE_ETH_OPEN_FAILED 4
+
+#define MYRI10GE_EEPROM_STRINGS_SIZE 256
+#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
+
+#define MYRI10GE_NO_CONFIRM_DATA 0xffffffff
+#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
+
+struct myri10ge_rx_buffer_state {
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(bus)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
+struct myri10ge_tx_buffer_state {
+ struct sk_buff *skb;
+ int last;
+ DECLARE_PCI_UNMAP_ADDR(bus)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
+struct myri10ge_cmd {
+ u32 data0;
+ u32 data1;
+ u32 data2;
+};
+
+struct myri10ge_rx_buf {
+ struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */
+ u8 __iomem *wc_fifo; /* w/c rx dma addr fifo address */
+ struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */
+ struct myri10ge_rx_buffer_state *info;
+ int cnt;
+ int alloc_fail;
+ int mask; /* number of rx slots -1 */
+};
+
+struct myri10ge_tx_buf {
+ struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */
+ u8 __iomem *wc_fifo; /* w/c send fifo address */
+ struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */
+ char *req_bytes;
+ struct myri10ge_tx_buffer_state *info;
+ int mask; /* number of transmit slots -1 */
+ int boundary; /* boundary transmits cannot cross */
+ int req ____cacheline_aligned; /* transmit slots submitted */
+ int pkt_start; /* packets started */
+ int done ____cacheline_aligned; /* transmit slots completed */
+ int pkt_done; /* packets completed */
+};
+
+struct myri10ge_rx_done {
+ struct mcp_slot *entry;
+ dma_addr_t bus;
+ int cnt;
+ int idx;
+};
+
+struct myri10ge_priv {
+ int running; /* running? */
+ int csum_flag; /* rx_csums? */
+ struct myri10ge_tx_buf tx; /* transmit ring */
+ struct myri10ge_rx_buf rx_small;
+ struct myri10ge_rx_buf rx_big;
+ struct myri10ge_rx_done rx_done;
+ int small_bytes;
+ struct net_device *dev;
+ struct net_device_stats stats;
+ u8 __iomem *sram;
+ int sram_size;
+ unsigned long board_span;
+ unsigned long iomem_base;
+ u32 __iomem *irq_claim;
+ u32 __iomem *irq_deassert;
+ char *mac_addr_string;
+ struct mcp_cmd_response *cmd;
+ dma_addr_t cmd_bus;
+ struct mcp_irq_data *fw_stats;
+ dma_addr_t fw_stats_bus;
+ struct pci_dev *pdev;
+ int msi_enabled;
+ unsigned int link_state;
+ unsigned int rdma_tags_available;
+ int intr_coal_delay;
+ u32 __iomem *intr_coal_delay_ptr;
+ int mtrr;
+ int wake_queue;
+ int stop_queue;
+ int down_cnt;
+ wait_queue_head_t down_wq;
+ struct work_struct watchdog_work;
+ struct timer_list watchdog_timer;
+ int watchdog_tx_done;
+ int watchdog_resets;
+ int tx_linearized;
+ int pause;
+ char *fw_name;
+ char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
+ char fw_version[128];
+ u8 mac_addr[6]; /* eeprom mac address */
+ unsigned long serial_number;
+ int vendor_specific_offset;
+ u32 devctl;
+ u16 msi_flags;
+ u32 pm_state[16];
+ u32 read_dma;
+ u32 write_dma;
+ u32 read_write_dma;
+};
+
+static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
+static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
+
+static char *myri10ge_fw_name = NULL;
+module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name\n");
+
+static int myri10ge_ecrc_enable = 1;
+module_param(myri10ge_ecrc_enable, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E\n");
+
+static int myri10ge_max_intr_slots = 1024;
+module_param(myri10ge_max_intr_slots, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_max_intr_slots, "Interrupt queue slots\n");
+
+static int myri10ge_small_bytes = -1; /* -1 == auto */
+module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n");
+
+static int myri10ge_msi = 1; /* enable msi by default */
+module_param(myri10ge_msi, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n");
+
+static int myri10ge_intr_coal_delay = 25;
+module_param(myri10ge_intr_coal_delay, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay\n");
+
+static int myri10ge_flow_control = 1;
+module_param(myri10ge_flow_control, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter\n");
+
+static int myri10ge_deassert_wait = 1;
+module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_deassert_wait,
+ "Wait when deasserting legacy interrupts\n");
+
+static int myri10ge_force_firmware = 0;
+module_param(myri10ge_force_firmware, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_force_firmware,
+ "Force firmware to assume aligned completions\n");
+
+static int myri10ge_skb_cross_4k = 0;
+module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_skb_cross_4k,
+ "Can a small skb cross a 4KB boundary?\n");
+
+static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
+module_param(myri10ge_initial_mtu, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
+
+static int myri10ge_napi_weight = 64;
+module_param(myri10ge_napi_weight, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight\n");
+
+static int myri10ge_watchdog_timeout = 1;
+module_param(myri10ge_watchdog_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout\n");
+
+static int myri10ge_max_irq_loops = 1048576;
+module_param(myri10ge_max_irq_loops, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_max_irq_loops,
+ "Set stuck legacy IRQ detection threshold\n");
+
+#define MYRI10GE_FW_OFFSET 1024*1024
+#define MYRI10GE_HIGHPART_TO_U32(X) \
+(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
+#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X))
+
+#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
+
+static int
+myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
+ struct myri10ge_cmd *data, int atomic)
+{
+ struct mcp_cmd *buf;
+ char buf_bytes[sizeof(*buf) + 8];
+ struct mcp_cmd_response *response = mgp->cmd;
+ char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET;
+ u32 dma_low, dma_high, result, value;
+ int sleep_total = 0;
+
+ /* ensure buf is aligned to 8 bytes */
+ buf = (struct mcp_cmd *)ALIGN((unsigned long)buf_bytes, 8);
+
+ buf->data0 = htonl(data->data0);
+ buf->data1 = htonl(data->data1);
+ buf->data2 = htonl(data->data2);
+ buf->cmd = htonl(cmd);
+ dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
+ dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
+
+ buf->response_addr.low = htonl(dma_low);
+ buf->response_addr.high = htonl(dma_high);
+ response->result = MYRI10GE_NO_RESPONSE_RESULT;
+ mb();
+ myri10ge_pio_copy(cmd_addr, buf, sizeof(*buf));
+
+ /* wait up to 15ms. Longest command is the DMA benchmark,
+ * which is capped at 5ms, but runs from a timeout handler
+ * that runs every 7.8ms. So a 15ms timeout leaves us with
+ * a 2.2ms margin
+ */
+ if (atomic) {
+ /* if atomic is set, do not sleep,
+ * and try to get the completion quickly
+ * (1ms will be enough for those commands) */
+ for (sleep_total = 0;
+ sleep_total < 1000
+ && response->result == MYRI10GE_NO_RESPONSE_RESULT;
+ sleep_total += 10)
+ udelay(10);
+ } else {
+ /* use msleep for most command */
+ for (sleep_total = 0;
+ sleep_total < 15
+ && response->result == MYRI10GE_NO_RESPONSE_RESULT;
+ sleep_total++)
+ msleep(1);
+ }
+
+ result = ntohl(response->result);
+ value = ntohl(response->data);
+ if (result != MYRI10GE_NO_RESPONSE_RESULT) {
+ if (result == 0) {
+ data->data0 = value;
+ return 0;
+ } else {
+ dev_err(&mgp->pdev->dev,
+ "command %d failed, result = %d\n",
+ cmd, result);
+ return -ENXIO;
+ }
+ }
+
+ dev_err(&mgp->pdev->dev, "command %d timed out, result = %d\n",
+ cmd, result);
+ return -EAGAIN;
+}
+
+/*
+ * The eeprom strings on the lanaiX have the format
+ * SN=x\0
+ * MAC=x:x:x:x:x:x\0
+ * PT:ddd mmm xx xx:xx:xx xx\0
+ * PV:ddd mmm xx xx:xx:xx xx\0
+ */
+static int myri10ge_read_mac_addr(struct myri10ge_priv *mgp)
+{
+ char *ptr, *limit;
+ int i;
+
+ ptr = mgp->eeprom_strings;
+ limit = mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE;
+
+ while (*ptr != '\0' && ptr < limit) {
+ if (memcmp(ptr, "MAC=", 4) == 0) {
+ ptr += 4;
+ mgp->mac_addr_string = ptr;
+ for (i = 0; i < 6; i++) {
+ if ((ptr + 2) > limit)
+ goto abort;
+ mgp->mac_addr[i] =
+ simple_strtoul(ptr, &ptr, 16);
+ ptr += 1;
+ }
+ }
+ if (memcmp((const void *)ptr, "SN=", 3) == 0) {
+ ptr += 3;
+ mgp->serial_number = simple_strtoul(ptr, &ptr, 10);
+ }
+ while (ptr < limit && *ptr++) ;
+ }
+
+ return 0;
+
+abort:
+ dev_err(&mgp->pdev->dev, "failed to parse eeprom_strings\n");
+ return -ENXIO;
+}
+
+/*
+ * Enable or disable periodic RDMAs from the host to make certain
+ * chipsets resend dropped PCIe messages
+ */
+
+static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
+{
+ char __iomem *submit;
+ u32 buf[16];
+ u32 dma_low, dma_high;
+ int i;
+
+ /* clear confirmation addr */
+ mgp->cmd->data = 0;
+ mb();
+
+ /* send a rdma command to the PCIe engine, and wait for the
+ * response in the confirmation address. The firmware should
+ * write a -1 there to indicate it is alive and well
+ */
+ dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
+ dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
+
+ buf[0] = htonl(dma_high); /* confirm addr MSW */
+ buf[1] = htonl(dma_low); /* confirm addr LSW */
+ buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */
+ buf[3] = htonl(dma_high); /* dummy addr MSW */
+ buf[4] = htonl(dma_low); /* dummy addr LSW */
+ buf[5] = htonl(enable); /* enable? */
+
+ submit = mgp->sram + 0xfc01c0;
+
+ myri10ge_pio_copy(submit, &buf, sizeof(buf));
+ for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++)
+ msleep(1);
+ if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA)
+ dev_err(&mgp->pdev->dev, "dummy rdma %s failed\n",
+ (enable ? "enable" : "disable"));
+}
+
+static int
+myri10ge_validate_firmware(struct myri10ge_priv *mgp,
+ struct mcp_gen_header *hdr)
+{
+ struct device *dev = &mgp->pdev->dev;
+ int major, minor;
+
+ /* check firmware type */
+ if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {
+ dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type));
+ return -EINVAL;
+ }
+
+ /* save firmware version for ethtool */
+ strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));
+
+ sscanf(mgp->fw_version, "%d.%d", &major, &minor);
+
+ if (!(major == MXGEFW_VERSION_MAJOR && minor == MXGEFW_VERSION_MINOR)) {
+ dev_err(dev, "Found firmware version %s\n", mgp->fw_version);
+ dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,
+ MXGEFW_VERSION_MINOR);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
+{
+ unsigned crc, reread_crc;
+ const struct firmware *fw;
+ struct device *dev = &mgp->pdev->dev;
+ struct mcp_gen_header *hdr;
+ size_t hdr_offset;
+ int status;
+
+ if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {
+ dev_err(dev, "Unable to load %s firmware image via hotplug\n",
+ mgp->fw_name);
+ status = -EINVAL;
+ goto abort_with_nothing;
+ }
+
+ /* check size */
+
+ if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET ||
+ fw->size < MCP_HEADER_PTR_OFFSET + 4) {
+ dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size);
+ status = -EINVAL;
+ goto abort_with_fw;
+ }
+
+ /* check id */
+ hdr_offset = ntohl(*(u32 *) (fw->data + MCP_HEADER_PTR_OFFSET));
+ if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) {
+ dev_err(dev, "Bad firmware file\n");
+ status = -EINVAL;
+ goto abort_with_fw;
+ }
+ hdr = (void *)(fw->data + hdr_offset);
+
+ status = myri10ge_validate_firmware(mgp, hdr);
+ if (status != 0)
+ goto abort_with_fw;
+
+ crc = crc32(~0, fw->data, fw->size);
+ if (mgp->tx.boundary == 2048) {
+ /* Avoid PCI burst on chipset with unaligned completions. */
+ int i;
+ __iomem u32 *ptr = (__iomem u32 *) (mgp->sram +
+ MYRI10GE_FW_OFFSET);
+ for (i = 0; i < fw->size / 4; i++) {
+ __raw_writel(((u32 *) fw->data)[i], ptr + i);
+ wmb();
+ }
+ } else {
+ myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET, fw->data,
+ fw->size);
+ }
+ /* corruption checking is good for parity recovery and buggy chipset */
+ memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
+ reread_crc = crc32(~0, fw->data, fw->size);
+ if (crc != reread_crc) {
+ dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n",
+ (unsigned)fw->size, reread_crc, crc);
+ status = -EIO;
+ goto abort_with_fw;
+ }
+ *size = (u32) fw->size;
+
+abort_with_fw:
+ release_firmware(fw);
+
+abort_with_nothing:
+ return status;
+}
+
+static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
+{
+ struct mcp_gen_header *hdr;
+ struct device *dev = &mgp->pdev->dev;
+ const size_t bytes = sizeof(struct mcp_gen_header);
+ size_t hdr_offset;
+ int status;
+
+ /* find running firmware header */
+ hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
+
+ if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {
+ dev_err(dev, "Running firmware has bad header offset (%d)\n",
+ (int)hdr_offset);
+ return -EIO;
+ }
+
+ /* copy header of running firmware from SRAM to host memory to
+ * validate firmware */
+ hdr = kmalloc(bytes, GFP_KERNEL);
+ if (hdr == NULL) {
+ dev_err(dev, "could not malloc firmware hdr\n");
+ return -ENOMEM;
+ }
+ memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
+ status = myri10ge_validate_firmware(mgp, hdr);
+ kfree(hdr);
+ return status;
+}
+
+static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
+{
+ char __iomem *submit;
+ u32 buf[16];
+ u32 dma_low, dma_high, size;
+ int status, i;
+
+ size = 0;
+ status = myri10ge_load_hotplug_firmware(mgp, &size);
+ if (status) {
+ dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
+
+ /* Do not attempt to adopt firmware if there
+ * was a bad crc */
+ if (status == -EIO)
+ return status;
+
+ status = myri10ge_adopt_running_firmware(mgp);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed to adopt running firmware\n");
+ return status;
+ }
+ dev_info(&mgp->pdev->dev,
+ "Successfully adopted running firmware\n");
+ if (mgp->tx.boundary == 4096) {
+ dev_warn(&mgp->pdev->dev,
+ "Using firmware currently running on NIC"
+ ". For optimal\n");
+ dev_warn(&mgp->pdev->dev,
+ "performance consider loading optimized "
+ "firmware\n");
+ dev_warn(&mgp->pdev->dev, "via hotplug\n");
+ }
+
+ mgp->fw_name = "adopted";
+ mgp->tx.boundary = 2048;
+ return status;
+ }
+
+ /* clear confirmation addr */
+ mgp->cmd->data = 0;
+ mb();
+
+ /* send a reload command to the bootstrap MCP, and wait for the
+ * response in the confirmation address. The firmware should
+ * write a -1 there to indicate it is alive and well
+ */
+ dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus);
+ dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus);
+
+ buf[0] = htonl(dma_high); /* confirm addr MSW */
+ buf[1] = htonl(dma_low); /* confirm addr LSW */
+ buf[2] = htonl(MYRI10GE_NO_CONFIRM_DATA); /* confirm data */
+
+ /* FIX: All newest firmware should un-protect the bottom of
+ * the sram before handoff. However, the very first interfaces
+ * do not. Therefore the handoff copy must skip the first 8 bytes
+ */
+ buf[3] = htonl(MYRI10GE_FW_OFFSET + 8); /* where the code starts */
+ buf[4] = htonl(size - 8); /* length of code */
+ buf[5] = htonl(8); /* where to copy to */
+ buf[6] = htonl(0); /* where to jump to */
+
+ submit = mgp->sram + 0xfc0000;
+
+ myri10ge_pio_copy(submit, &buf, sizeof(buf));
+ mb();
+ msleep(1);
+ mb();
+ i = 0;
+ while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20) {
+ msleep(1);
+ i++;
+ }
+ if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {
+ dev_err(&mgp->pdev->dev, "handoff failed\n");
+ return -ENXIO;
+ }
+ dev_info(&mgp->pdev->dev, "handoff confirmed\n");
+ myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096);
+
+ return 0;
+}
+
+static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr)
+{
+ struct myri10ge_cmd cmd;
+ int status;
+
+ cmd.data0 = ((addr[0] << 24) | (addr[1] << 16)
+ | (addr[2] << 8) | addr[3]);
+
+ cmd.data1 = ((addr[4] << 8) | (addr[5]));
+
+ status = myri10ge_send_cmd(mgp, MXGEFW_SET_MAC_ADDRESS, &cmd, 0);
+ return status;
+}
+
+static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
+{
+ struct myri10ge_cmd cmd;
+ int status, ctl;
+
+ ctl = pause ? MXGEFW_ENABLE_FLOW_CONTROL : MXGEFW_DISABLE_FLOW_CONTROL;
+ status = myri10ge_send_cmd(mgp, ctl, &cmd, 0);
+
+ if (status) {
+ printk(KERN_ERR
+ "myri10ge: %s: Failed to set flow control mode\n",
+ mgp->dev->name);
+ return status;
+ }
+ mgp->pause = pause;
+ return 0;
+}
+
+static void
+myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic)
+{
+ struct myri10ge_cmd cmd;
+ int status, ctl;
+
+ ctl = promisc ? MXGEFW_ENABLE_PROMISC : MXGEFW_DISABLE_PROMISC;
+ status = myri10ge_send_cmd(mgp, ctl, &cmd, atomic);
+ if (status)
+ printk(KERN_ERR "myri10ge: %s: Failed to set promisc mode\n",
+ mgp->dev->name);
+}
+
+static int myri10ge_reset(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_cmd cmd;
+ int status;
+ size_t bytes;
+ u32 len;
+
+ /* try to send a reset command to the card to see if it
+ * is alive */
+ memset(&cmd, 0, sizeof(cmd));
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev, "failed reset\n");
+ return -ENXIO;
+ }
+
+ /* Now exchange information about interrupts */
+
+ bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ memset(mgp->rx_done.entry, 0, bytes);
+ cmd.data0 = (u32) bytes;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);
+
+ status |=
+ myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
+ mgp->irq_claim = (__iomem u32 *) (mgp->sram + cmd.data0);
+ if (!mgp->msi_enabled) {
+ status |= myri10ge_send_cmd
+ (mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0);
+ mgp->irq_deassert = (__iomem u32 *) (mgp->sram + cmd.data0);
+
+ }
+ status |= myri10ge_send_cmd
+ (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0);
+ mgp->intr_coal_delay_ptr = (__iomem u32 *) (mgp->sram + cmd.data0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev, "failed set interrupt parameters\n");
+ return status;
+ }
+ __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
+
+ /* Run a small DMA test.
+ * The magic multipliers to the length tell the firmware
+ * to do DMA read, write, or read+write tests. The
+ * results are returned in cmd.data0. The upper 16
+ * bits or the return is the number of transfers completed.
+ * The lower 16 bits is the time in 0.5us ticks that the
+ * transfers took to complete.
+ */
+
+ len = mgp->tx.boundary;
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data2 = len * 0x10000;
+ status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
+ if (status == 0)
+ mgp->read_dma = ((cmd.data0 >> 16) * len * 2) /
+ (cmd.data0 & 0xffff);
+ else
+ dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n",
+ status);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data2 = len * 0x1;
+ status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
+ if (status == 0)
+ mgp->write_dma = ((cmd.data0 >> 16) * len * 2) /
+ (cmd.data0 & 0xffff);
+ else
+ dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n",
+ status);
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data2 = len * 0x10001;
+ status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
+ if (status == 0)
+ mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /
+ (cmd.data0 & 0xffff);
+ else
+ dev_warn(&mgp->pdev->dev,
+ "DMA read/write benchmark failed: %d\n", status);
+
+ memset(mgp->rx_done.entry, 0, bytes);
+
+ /* reset mcp/driver shared state back to 0 */
+ mgp->tx.req = 0;
+ mgp->tx.done = 0;
+ mgp->tx.pkt_start = 0;
+ mgp->tx.pkt_done = 0;
+ mgp->rx_big.cnt = 0;
+ mgp->rx_small.cnt = 0;
+ mgp->rx_done.idx = 0;
+ mgp->rx_done.cnt = 0;
+ status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
+ myri10ge_change_promisc(mgp, 0, 0);
+ myri10ge_change_pause(mgp, mgp->pause);
+ return status;
+}
+
+static inline void
+myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
+ struct mcp_kreq_ether_recv *src)
+{
+ u32 low;
+
+ low = src->addr_low;
+ src->addr_low = DMA_32BIT_MASK;
+ myri10ge_pio_copy(dst, src, 8 * sizeof(*src));
+ mb();
+ src->addr_low = low;
+ __raw_writel(low, &dst->addr_low);
+ mb();
+}
+
+/*
+ * Set of routines to get a new receive buffer. Any buffer which
+ * crosses a 4KB boundary must start on a 4KB boundary due to PCIe
+ * wdma restrictions. We also try to align any smaller allocation to
+ * at least a 16 byte boundary for efficiency. We assume the linux
+ * memory allocator works by powers of 2, and will not return memory
+ * smaller than 2KB which crosses a 4KB boundary. If it does, we fall
+ * back to allocating 2x as much space as required.
+ *
+ * We intend to replace large (>4KB) skb allocations by using
+ * pages directly and building a fraglist in the near future.
+ */
+
+static inline struct sk_buff *myri10ge_alloc_big(int bytes)
+{
+ struct sk_buff *skb;
+ unsigned long data, roundup;
+
+ skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD);
+ if (skb == NULL)
+ return NULL;
+
+ /* Correct skb->truesize so that socket buffer
+ * accounting is not confused the rounding we must
+ * do to satisfy alignment constraints.
+ */
+ skb->truesize -= 4096;
+
+ data = (unsigned long)(skb->data);
+ roundup = (-data) & (4095);
+ skb_reserve(skb, roundup);
+ return skb;
+}
+
+/* Allocate 2x as much space as required and use whichever portion
+ * does not cross a 4KB boundary */
+static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
+{
+ struct sk_buff *skb;
+ unsigned long data, boundary;
+
+ skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1);
+ if (unlikely(skb == NULL))
+ return NULL;
+
+ /* Correct skb->truesize so that socket buffer
+ * accounting is not confused the rounding we must
+ * do to satisfy alignment constraints.
+ */
+ skb->truesize -= bytes + MXGEFW_PAD;
+
+ data = (unsigned long)(skb->data);
+ boundary = (data + 4095UL) & ~4095UL;
+ if ((boundary - data) >= (bytes + MXGEFW_PAD))
+ return skb;
+
+ skb_reserve(skb, boundary - data);
+ return skb;
+}
+
+/* Allocate just enough space, and verify that the allocated
+ * space does not cross a 4KB boundary */
+static inline struct sk_buff *myri10ge_alloc_small(int bytes)
+{
+ struct sk_buff *skb;
+ unsigned long roundup, data, end;
+
+ skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD);
+ if (unlikely(skb == NULL))
+ return NULL;
+
+ /* Round allocated buffer to 16 byte boundary */
+ data = (unsigned long)(skb->data);
+ roundup = (-data) & 15UL;
+ skb_reserve(skb, roundup);
+ /* Verify that the data buffer does not cross a page boundary */
+ data = (unsigned long)(skb->data);
+ end = data + bytes + MXGEFW_PAD - 1;
+ if (unlikely(((end >> 12) != (data >> 12)) && (data & 4095UL))) {
+ printk(KERN_NOTICE
+ "myri10ge_alloc_small: small skb crossed 4KB boundary\n");
+ myri10ge_skb_cross_4k = 1;
+ dev_kfree_skb_any(skb);
+ skb = myri10ge_alloc_small_safe(bytes);
+ }
+ return skb;
+}
+
+static inline int
+myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
+ int idx)
+{
+ struct sk_buff *skb;
+ dma_addr_t bus;
+ int len, retval = 0;
+
+ bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
+
+ if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
+ skb = myri10ge_alloc_big(bytes);
+ else if (myri10ge_skb_cross_4k)
+ skb = myri10ge_alloc_small_safe(bytes);
+ else
+ skb = myri10ge_alloc_small(bytes);
+
+ if (unlikely(skb == NULL)) {
+ rx->alloc_fail++;
+ retval = -ENOBUFS;
+ goto done;
+ }
+
+ /* set len so that it only covers the area we
+ * need mapped for DMA */
+ len = bytes + MXGEFW_PAD;
+
+ bus = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+ rx->info[idx].skb = skb;
+ pci_unmap_addr_set(&rx->info[idx], bus, bus);
+ pci_unmap_len_set(&rx->info[idx], len, len);
+ rx->shadow[idx].addr_low = htonl(MYRI10GE_LOWPART_TO_U32(bus));
+ rx->shadow[idx].addr_high = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
+
+done:
+ /* copy 8 descriptors (64-bytes) to the mcp at a time */
+ if ((idx & 7) == 7) {
+ if (rx->wc_fifo == NULL)
+ myri10ge_submit_8rx(&rx->lanai[idx - 7],
+ &rx->shadow[idx - 7]);
+ else {
+ mb();
+ myri10ge_pio_copy(rx->wc_fifo,
+ &rx->shadow[idx - 7], 64);
+ }
+ }
+ return retval;
+}
+
+static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum)
+{
+ struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
+
+ if ((skb->protocol == ntohs(ETH_P_8021Q)) &&
+ (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
+ vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
+ skb->csum = hw_csum;
+ skb->ip_summed = CHECKSUM_HW;
+ }
+}
+
+static inline unsigned long
+myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+ int bytes, int len, int csum)
+{
+ dma_addr_t bus;
+ struct sk_buff *skb;
+ int idx, unmap_len;
+
+ idx = rx->cnt & rx->mask;
+ rx->cnt++;
+
+ /* save a pointer to the received skb */
+ skb = rx->info[idx].skb;
+ bus = pci_unmap_addr(&rx->info[idx], bus);
+ unmap_len = pci_unmap_len(&rx->info[idx], len);
+
+ /* try to replace the received skb */
+ if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) {
+ /* drop the frame -- the old skbuf is re-cycled */
+ mgp->stats.rx_dropped += 1;
+ return 0;
+ }
+
+ /* unmap the recvd skb */
+ pci_unmap_single(mgp->pdev, bus, unmap_len, PCI_DMA_FROMDEVICE);
+
+ /* mcp implicitly skips 1st bytes so that packet is properly
+ * aligned */
+ skb_reserve(skb, MXGEFW_PAD);
+
+ /* set the length of the frame */
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, mgp->dev);
+ skb->dev = mgp->dev;
+ if (mgp->csum_flag) {
+ if ((skb->protocol == ntohs(ETH_P_IP)) ||
+ (skb->protocol == ntohs(ETH_P_IPV6))) {
+ skb->csum = ntohs((u16) csum);
+ skb->ip_summed = CHECKSUM_HW;
+ } else
+ myri10ge_vlan_ip_csum(skb, ntohs((u16) csum));
+ }
+
+ netif_receive_skb(skb);
+ mgp->dev->last_rx = jiffies;
+ return 1;
+}
+
+static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ struct myri10ge_tx_buf *tx = &mgp->tx;
+ struct sk_buff *skb;
+ int idx, len;
+ int limit = 0;
+
+ while (tx->pkt_done != mcp_index) {
+ idx = tx->done & tx->mask;
+ skb = tx->info[idx].skb;
+
+ /* Mark as free */
+ tx->info[idx].skb = NULL;
+ if (tx->info[idx].last) {
+ tx->pkt_done++;
+ tx->info[idx].last = 0;
+ }
+ tx->done++;
+ len = pci_unmap_len(&tx->info[idx], len);
+ pci_unmap_len_set(&tx->info[idx], len, 0);
+ if (skb) {
+ mgp->stats.tx_bytes += skb->len;
+ mgp->stats.tx_packets++;
+ dev_kfree_skb_irq(skb);
+ if (len)
+ pci_unmap_single(pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ } else {
+ if (len)
+ pci_unmap_page(pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ }
+
+ /* limit potential for livelock by only handling
+ * 2 full tx rings per call */
+ if (unlikely(++limit > 2 * tx->mask))
+ break;
+ }
+ /* start the queue if we've stopped it */
+ if (netif_queue_stopped(mgp->dev)
+ && tx->req - tx->done < (tx->mask >> 1)) {
+ mgp->wake_queue++;
+ netif_wake_queue(mgp->dev);
+ }
+}
+
+static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
+{
+ struct myri10ge_rx_done *rx_done = &mgp->rx_done;
+ unsigned long rx_bytes = 0;
+ unsigned long rx_packets = 0;
+ unsigned long rx_ok;
+
+ int idx = rx_done->idx;
+ int cnt = rx_done->cnt;
+ u16 length;
+ u16 checksum;
+
+ while (rx_done->entry[idx].length != 0 && *limit != 0) {
+ length = ntohs(rx_done->entry[idx].length);
+ rx_done->entry[idx].length = 0;
+ checksum = ntohs(rx_done->entry[idx].checksum);
+ if (length <= mgp->small_bytes)
+ rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small,
+ mgp->small_bytes,
+ length, checksum);
+ else
+ rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
+ mgp->dev->mtu + ETH_HLEN,
+ length, checksum);
+ rx_packets += rx_ok;
+ rx_bytes += rx_ok * (unsigned long)length;
+ cnt++;
+ idx = cnt & (myri10ge_max_intr_slots - 1);
+
+ /* limit potential for livelock by only handling a
+ * limited number of frames. */
+ (*limit)--;
+ }
+ rx_done->idx = idx;
+ rx_done->cnt = cnt;
+ mgp->stats.rx_packets += rx_packets;
+ mgp->stats.rx_bytes += rx_bytes;
+}
+
+static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
+{
+ struct mcp_irq_data *stats = mgp->fw_stats;
+
+ if (unlikely(stats->stats_updated)) {
+ if (mgp->link_state != stats->link_up) {
+ mgp->link_state = stats->link_up;
+ if (mgp->link_state) {
+ printk(KERN_INFO "myri10ge: %s: link up\n",
+ mgp->dev->name);
+ netif_carrier_on(mgp->dev);
+ } else {
+ printk(KERN_INFO "myri10ge: %s: link down\n",
+ mgp->dev->name);
+ netif_carrier_off(mgp->dev);
+ }
+ }
+ if (mgp->rdma_tags_available !=
+ ntohl(mgp->fw_stats->rdma_tags_available)) {
+ mgp->rdma_tags_available =
+ ntohl(mgp->fw_stats->rdma_tags_available);
+ printk(KERN_WARNING "myri10ge: %s: RDMA timed out! "
+ "%d tags left\n", mgp->dev->name,
+ mgp->rdma_tags_available);
+ }
+ mgp->down_cnt += stats->link_down;
+ if (stats->link_down)
+ wake_up(&mgp->down_wq);
+ }
+}
+
+static int myri10ge_poll(struct net_device *netdev, int *budget)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ struct myri10ge_rx_done *rx_done = &mgp->rx_done;
+ int limit, orig_limit, work_done;
+
+ /* process as many rx events as NAPI will allow */
+ limit = min(*budget, netdev->quota);
+ orig_limit = limit;
+ myri10ge_clean_rx_done(mgp, &limit);
+ work_done = orig_limit - limit;
+ *budget -= work_done;
+ netdev->quota -= work_done;
+
+ if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) {
+ netif_rx_complete(netdev);
+ __raw_writel(htonl(3), mgp->irq_claim);
+ return 0;
+ }
+ return 1;
+}
+
+static irqreturn_t myri10ge_intr(int irq, void *arg, struct pt_regs *regs)
+{
+ struct myri10ge_priv *mgp = arg;
+ struct mcp_irq_data *stats = mgp->fw_stats;
+ struct myri10ge_tx_buf *tx = &mgp->tx;
+ u32 send_done_count;
+ int i;
+
+ /* make sure it is our IRQ, and that the DMA has finished */
+ if (unlikely(!stats->valid))
+ return (IRQ_NONE);
+
+ /* low bit indicates receives are present, so schedule
+ * napi poll handler */
+ if (stats->valid & 1)
+ netif_rx_schedule(mgp->dev);
+
+ if (!mgp->msi_enabled) {
+ __raw_writel(0, mgp->irq_deassert);
+ if (!myri10ge_deassert_wait)
+ stats->valid = 0;
+ mb();
+ } else
+ stats->valid = 0;
+
+ /* Wait for IRQ line to go low, if using INTx */
+ i = 0;
+ while (1) {
+ i++;
+ /* check for transmit completes and receives */
+ send_done_count = ntohl(stats->send_done_count);
+ if (send_done_count != tx->pkt_done)
+ myri10ge_tx_done(mgp, (int)send_done_count);
+ if (unlikely(i > myri10ge_max_irq_loops)) {
+ printk(KERN_WARNING "myri10ge: %s: irq stuck?\n",
+ mgp->dev->name);
+ stats->valid = 0;
+ schedule_work(&mgp->watchdog_work);
+ }
+ if (likely(stats->valid == 0))
+ break;
+ cpu_relax();
+ barrier();
+ }
+
+ myri10ge_check_statblock(mgp);
+
+ __raw_writel(htonl(3), mgp->irq_claim + 1);
+ return (IRQ_HANDLED);
+}
+
+static int
+myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static void
+myri10ge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ strlcpy(info->driver, "myri10ge", sizeof(info->driver));
+ strlcpy(info->version, MYRI10GE_VERSION_STR, sizeof(info->version));
+ strlcpy(info->fw_version, mgp->fw_version, sizeof(info->fw_version));
+ strlcpy(info->bus_info, pci_name(mgp->pdev), sizeof(info->bus_info));
+}
+
+static int
+myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ coal->rx_coalesce_usecs = mgp->intr_coal_delay;
+ return 0;
+}
+
+static int
+myri10ge_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ mgp->intr_coal_delay = coal->rx_coalesce_usecs;
+ __raw_writel(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
+ return 0;
+}
+
+static void
+myri10ge_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ pause->autoneg = 0;
+ pause->rx_pause = mgp->pause;
+ pause->tx_pause = mgp->pause;
+}
+
+static int
+myri10ge_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ if (pause->tx_pause != mgp->pause)
+ return myri10ge_change_pause(mgp, pause->tx_pause);
+ if (pause->rx_pause != mgp->pause)
+ return myri10ge_change_pause(mgp, pause->tx_pause);
+ if (pause->autoneg != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static void
+myri10ge_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
+ ring->rx_mini_max_pending = mgp->rx_small.mask + 1;
+ ring->rx_max_pending = mgp->rx_big.mask + 1;
+ ring->rx_jumbo_max_pending = 0;
+ ring->tx_max_pending = mgp->rx_small.mask + 1;
+ ring->rx_mini_pending = ring->rx_mini_max_pending;
+ ring->rx_pending = ring->rx_max_pending;
+ ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
+ ring->tx_pending = ring->tx_max_pending;
+}
+
+static u32 myri10ge_get_rx_csum(struct net_device *netdev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ if (mgp->csum_flag)
+ return 1;
+ else
+ return 0;
+}
+
+static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ if (csum_enabled)
+ mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
+ else
+ mgp->csum_flag = 0;
+ return 0;
+}
+
+static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+ "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+ "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+ "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+ "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+ "tx_heartbeat_errors", "tx_window_errors",
+ /* device-specific stats */
+ "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
+ "serial_number", "tx_pkt_start", "tx_pkt_done",
+ "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
+ "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
+ "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered",
+ "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
+ "dropped_no_big_buffer"
+};
+
+#define MYRI10GE_NET_STATS_LEN 21
+#define MYRI10GE_STATS_LEN sizeof(myri10ge_gstrings_stats) / ETH_GSTRING_LEN
+
+static void
+myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *myri10ge_gstrings_stats,
+ sizeof(myri10ge_gstrings_stats));
+ break;
+ }
+}
+
+static int myri10ge_get_stats_count(struct net_device *netdev)
+{
+ return MYRI10GE_STATS_LEN;
+}
+
+static void
+myri10ge_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 * data)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ int i;
+
+ for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
+ data[i] = ((unsigned long *)&mgp->stats)[i];
+
+ data[i++] = (unsigned int)mgp->read_dma;
+ data[i++] = (unsigned int)mgp->write_dma;
+ data[i++] = (unsigned int)mgp->read_write_dma;
+ data[i++] = (unsigned int)mgp->serial_number;
+ data[i++] = (unsigned int)mgp->tx.pkt_start;
+ data[i++] = (unsigned int)mgp->tx.pkt_done;
+ data[i++] = (unsigned int)mgp->tx.req;
+ data[i++] = (unsigned int)mgp->tx.done;
+ data[i++] = (unsigned int)mgp->rx_small.cnt;
+ data[i++] = (unsigned int)mgp->rx_big.cnt;
+ data[i++] = (unsigned int)mgp->wake_queue;
+ data[i++] = (unsigned int)mgp->stop_queue;
+ data[i++] = (unsigned int)mgp->watchdog_resets;
+ data[i++] = (unsigned int)mgp->tx_linearized;
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
+ data[i++] =
+ (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
+}
+
+static struct ethtool_ops myri10ge_ethtool_ops = {
+ .get_settings = myri10ge_get_settings,
+ .get_drvinfo = myri10ge_get_drvinfo,
+ .get_coalesce = myri10ge_get_coalesce,
+ .set_coalesce = myri10ge_set_coalesce,
+ .get_pauseparam = myri10ge_get_pauseparam,
+ .set_pauseparam = myri10ge_set_pauseparam,
+ .get_ringparam = myri10ge_get_ringparam,
+ .get_rx_csum = myri10ge_get_rx_csum,
+ .set_rx_csum = myri10ge_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+#endif
+ .get_strings = myri10ge_get_strings,
+ .get_stats_count = myri10ge_get_stats_count,
+ .get_ethtool_stats = myri10ge_get_ethtool_stats
+};
+
+static int myri10ge_allocate_rings(struct net_device *dev)
+{
+ struct myri10ge_priv *mgp;
+ struct myri10ge_cmd cmd;
+ int tx_ring_size, rx_ring_size;
+ int tx_ring_entries, rx_ring_entries;
+ int i, status;
+ size_t bytes;
+
+ mgp = netdev_priv(dev);
+
+ /* get ring sizes */
+
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
+ tx_ring_size = cmd.data0;
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+ rx_ring_size = cmd.data0;
+
+ tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send);
+ rx_ring_entries = rx_ring_size / sizeof(struct mcp_dma_addr);
+ mgp->tx.mask = tx_ring_entries - 1;
+ mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1;
+
+ /* allocate the host shadow rings */
+
+ bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4)
+ * sizeof(*mgp->tx.req_list);
+ mgp->tx.req_bytes = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->tx.req_bytes == NULL)
+ goto abort_with_nothing;
+
+ /* ensure req_list entries are aligned to 8 bytes */
+ mgp->tx.req_list = (struct mcp_kreq_ether_send *)
+ ALIGN((unsigned long)mgp->tx.req_bytes, 8);
+
+ bytes = rx_ring_entries * sizeof(*mgp->rx_small.shadow);
+ mgp->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->rx_small.shadow == NULL)
+ goto abort_with_tx_req_bytes;
+
+ bytes = rx_ring_entries * sizeof(*mgp->rx_big.shadow);
+ mgp->rx_big.shadow = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->rx_big.shadow == NULL)
+ goto abort_with_rx_small_shadow;
+
+ /* allocate the host info rings */
+
+ bytes = tx_ring_entries * sizeof(*mgp->tx.info);
+ mgp->tx.info = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->tx.info == NULL)
+ goto abort_with_rx_big_shadow;
+
+ bytes = rx_ring_entries * sizeof(*mgp->rx_small.info);
+ mgp->rx_small.info = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->rx_small.info == NULL)
+ goto abort_with_tx_info;
+
+ bytes = rx_ring_entries * sizeof(*mgp->rx_big.info);
+ mgp->rx_big.info = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->rx_big.info == NULL)
+ goto abort_with_rx_small_info;
+
+ /* Fill the receive rings */
+
+ for (i = 0; i <= mgp->rx_small.mask; i++) {
+ status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev,
+ mgp->small_bytes, i);
+ if (status) {
+ printk(KERN_ERR
+ "myri10ge: %s: alloced only %d small bufs\n",
+ dev->name, i);
+ goto abort_with_rx_small_ring;
+ }
+ }
+
+ for (i = 0; i <= mgp->rx_big.mask; i++) {
+ status =
+ myri10ge_getbuf(&mgp->rx_big, mgp->pdev,
+ dev->mtu + ETH_HLEN, i);
+ if (status) {
+ printk(KERN_ERR
+ "myri10ge: %s: alloced only %d big bufs\n",
+ dev->name, i);
+ goto abort_with_rx_big_ring;
+ }
+ }
+
+ return 0;
+
+abort_with_rx_big_ring:
+ for (i = 0; i <= mgp->rx_big.mask; i++) {
+ if (mgp->rx_big.info[i].skb != NULL)
+ dev_kfree_skb_any(mgp->rx_big.info[i].skb);
+ if (pci_unmap_len(&mgp->rx_big.info[i], len))
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&mgp->rx_big.info[i],
+ bus),
+ pci_unmap_len(&mgp->rx_big.info[i],
+ len),
+ PCI_DMA_FROMDEVICE);
+ }
+
+abort_with_rx_small_ring:
+ for (i = 0; i <= mgp->rx_small.mask; i++) {
+ if (mgp->rx_small.info[i].skb != NULL)
+ dev_kfree_skb_any(mgp->rx_small.info[i].skb);
+ if (pci_unmap_len(&mgp->rx_small.info[i], len))
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&mgp->rx_small.info[i],
+ bus),
+ pci_unmap_len(&mgp->rx_small.info[i],
+ len),
+ PCI_DMA_FROMDEVICE);
+ }
+ kfree(mgp->rx_big.info);
+
+abort_with_rx_small_info:
+ kfree(mgp->rx_small.info);
+
+abort_with_tx_info:
+ kfree(mgp->tx.info);
+
+abort_with_rx_big_shadow:
+ kfree(mgp->rx_big.shadow);
+
+abort_with_rx_small_shadow:
+ kfree(mgp->rx_small.shadow);
+
+abort_with_tx_req_bytes:
+ kfree(mgp->tx.req_bytes);
+ mgp->tx.req_bytes = NULL;
+ mgp->tx.req_list = NULL;
+
+abort_with_nothing:
+ return status;
+}
+
+static void myri10ge_free_rings(struct net_device *dev)
+{
+ struct myri10ge_priv *mgp;
+ struct sk_buff *skb;
+ struct myri10ge_tx_buf *tx;
+ int i, len, idx;
+
+ mgp = netdev_priv(dev);
+
+ for (i = 0; i <= mgp->rx_big.mask; i++) {
+ if (mgp->rx_big.info[i].skb != NULL)
+ dev_kfree_skb_any(mgp->rx_big.info[i].skb);
+ if (pci_unmap_len(&mgp->rx_big.info[i], len))
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&mgp->rx_big.info[i],
+ bus),
+ pci_unmap_len(&mgp->rx_big.info[i],
+ len),
+ PCI_DMA_FROMDEVICE);
+ }
+
+ for (i = 0; i <= mgp->rx_small.mask; i++) {
+ if (mgp->rx_small.info[i].skb != NULL)
+ dev_kfree_skb_any(mgp->rx_small.info[i].skb);
+ if (pci_unmap_len(&mgp->rx_small.info[i], len))
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&mgp->rx_small.info[i],
+ bus),
+ pci_unmap_len(&mgp->rx_small.info[i],
+ len),
+ PCI_DMA_FROMDEVICE);
+ }
+
+ tx = &mgp->tx;
+ while (tx->done != tx->req) {
+ idx = tx->done & tx->mask;
+ skb = tx->info[idx].skb;
+
+ /* Mark as free */
+ tx->info[idx].skb = NULL;
+ tx->done++;
+ len = pci_unmap_len(&tx->info[idx], len);
+ pci_unmap_len_set(&tx->info[idx], len, 0);
+ if (skb) {
+ mgp->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ if (len)
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ } else {
+ if (len)
+ pci_unmap_page(mgp->pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ }
+ }
+ kfree(mgp->rx_big.info);
+
+ kfree(mgp->rx_small.info);
+
+ kfree(mgp->tx.info);
+
+ kfree(mgp->rx_big.shadow);
+
+ kfree(mgp->rx_small.shadow);
+
+ kfree(mgp->tx.req_bytes);
+ mgp->tx.req_bytes = NULL;
+ mgp->tx.req_list = NULL;
+}
+
+static int myri10ge_open(struct net_device *dev)
+{
+ struct myri10ge_priv *mgp;
+ struct myri10ge_cmd cmd;
+ int status, big_pow2;
+
+ mgp = netdev_priv(dev);
+
+ if (mgp->running != MYRI10GE_ETH_STOPPED)
+ return -EBUSY;
+
+ mgp->running = MYRI10GE_ETH_STARTING;
+ status = myri10ge_reset(mgp);
+ if (status != 0) {
+ printk(KERN_ERR "myri10ge: %s: failed reset\n", dev->name);
+ mgp->running = MYRI10GE_ETH_STOPPED;
+ return -ENXIO;
+ }
+
+ /* decide what small buffer size to use. For good TCP rx
+ * performance, it is important to not receive 1514 byte
+ * frames into jumbo buffers, as it confuses the socket buffer
+ * accounting code, leading to drops and erratic performance.
+ */
+
+ if (dev->mtu <= ETH_DATA_LEN)
+ mgp->small_bytes = 128; /* enough for a TCP header */
+ else
+ mgp->small_bytes = ETH_FRAME_LEN; /* enough for an ETH_DATA_LEN frame */
+
+ /* Override the small buffer size? */
+ if (myri10ge_small_bytes > 0)
+ mgp->small_bytes = myri10ge_small_bytes;
+
+ /* If the user sets an obscenely small MTU, adjust the small
+ * bytes down to nearly nothing */
+ if (mgp->small_bytes >= (dev->mtu + ETH_HLEN))
+ mgp->small_bytes = 64;
+
+ /* get the lanai pointers to the send and receive rings */
+
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
+ mgp->tx.lanai =
+ (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0);
+
+ status |=
+ myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0);
+ mgp->rx_small.lanai =
+ (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
+
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
+ mgp->rx_big.lanai =
+ (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
+
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: failed to get ring sizes or locations\n",
+ dev->name);
+ mgp->running = MYRI10GE_ETH_STOPPED;
+ return -ENXIO;
+ }
+
+ if (mgp->mtrr >= 0) {
+ mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000;
+ mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000;
+ mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000;
+ } else {
+ mgp->tx.wc_fifo = NULL;
+ mgp->rx_small.wc_fifo = NULL;
+ mgp->rx_big.wc_fifo = NULL;
+ }
+
+ status = myri10ge_allocate_rings(dev);
+ if (status != 0)
+ goto abort_with_nothing;
+
+ /* Firmware needs the big buff size as a power of 2. Lie and
+ * tell him the buffer is larger, because we only use 1
+ * buffer/pkt, and the mtu will prevent overruns.
+ */
+ big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD;
+ while ((big_pow2 & (big_pow2 - 1)) != 0)
+ big_pow2++;
+
+ /* now give firmware buffers sizes, and MTU */
+ cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_MTU, &cmd, 0);
+ cmd.data0 = mgp->small_bytes;
+ status |=
+ myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd, 0);
+ cmd.data0 = big_pow2;
+ status |=
+ myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd, 0);
+ if (status) {
+ printk(KERN_ERR "myri10ge: %s: Couldn't set buffer sizes\n",
+ dev->name);
+ goto abort_with_rings;
+ }
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0);
+ if (status) {
+ printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
+ dev->name);
+ goto abort_with_rings;
+ }
+
+ mgp->link_state = -1;
+ mgp->rdma_tags_available = 15;
+
+ netif_poll_enable(mgp->dev); /* must happen prior to any irq */
+
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
+ if (status) {
+ printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n",
+ dev->name);
+ goto abort_with_rings;
+ }
+
+ mgp->wake_queue = 0;
+ mgp->stop_queue = 0;
+ mgp->running = MYRI10GE_ETH_RUNNING;
+ mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
+ add_timer(&mgp->watchdog_timer);
+ netif_wake_queue(dev);
+ return 0;
+
+abort_with_rings:
+ myri10ge_free_rings(dev);
+
+abort_with_nothing:
+ mgp->running = MYRI10GE_ETH_STOPPED;
+ return -ENOMEM;
+}
+
+static int myri10ge_close(struct net_device *dev)
+{
+ struct myri10ge_priv *mgp;
+ struct myri10ge_cmd cmd;
+ int status, old_down_cnt;
+
+ mgp = netdev_priv(dev);
+
+ if (mgp->running != MYRI10GE_ETH_RUNNING)
+ return 0;
+
+ if (mgp->tx.req_bytes == NULL)
+ return 0;
+
+ del_timer_sync(&mgp->watchdog_timer);
+ mgp->running = MYRI10GE_ETH_STOPPING;
+ netif_poll_disable(mgp->dev);
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ old_down_cnt = mgp->down_cnt;
+ mb();
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0);
+ if (status)
+ printk(KERN_ERR "myri10ge: %s: Couldn't bring down link\n",
+ dev->name);
+
+ wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, HZ);
+ if (old_down_cnt == mgp->down_cnt)
+ printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name);
+
+ netif_tx_disable(dev);
+
+ myri10ge_free_rings(dev);
+
+ mgp->running = MYRI10GE_ETH_STOPPED;
+ return 0;
+}
+
+/* copy an array of struct mcp_kreq_ether_send's to the mcp. Copy
+ * backwards one at a time and handle ring wraps */
+
+static inline void
+myri10ge_submit_req_backwards(struct myri10ge_tx_buf *tx,
+ struct mcp_kreq_ether_send *src, int cnt)
+{
+ int idx, starting_slot;
+ starting_slot = tx->req;
+ while (cnt > 1) {
+ cnt--;
+ idx = (starting_slot + cnt) & tx->mask;
+ myri10ge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src));
+ mb();
+ }
+}
+
+/*
+ * copy an array of struct mcp_kreq_ether_send's to the mcp. Copy
+ * at most 32 bytes at a time, so as to avoid involving the software
+ * pio handler in the nic. We re-write the first segment's flags
+ * to mark them valid only after writing the entire chain.
+ */
+
+static inline void
+myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src,
+ int cnt)
+{
+ int idx, i;
+ struct mcp_kreq_ether_send __iomem *dstp, *dst;
+ struct mcp_kreq_ether_send *srcp;
+ u8 last_flags;
+
+ idx = tx->req & tx->mask;
+
+ last_flags = src->flags;
+ src->flags = 0;
+ mb();
+ dst = dstp = &tx->lanai[idx];
+ srcp = src;
+
+ if ((idx + cnt) < tx->mask) {
+ for (i = 0; i < (cnt - 1); i += 2) {
+ myri10ge_pio_copy(dstp, srcp, 2 * sizeof(*src));
+ mb(); /* force write every 32 bytes */
+ srcp += 2;
+ dstp += 2;
+ }
+ } else {
+ /* submit all but the first request, and ensure
+ * that it is submitted below */
+ myri10ge_submit_req_backwards(tx, src, cnt);
+ i = 0;
+ }
+ if (i < cnt) {
+ /* submit the first request */
+ myri10ge_pio_copy(dstp, srcp, sizeof(*src));
+ mb(); /* barrier before setting valid flag */
+ }
+
+ /* re-write the last 32-bits with the valid flags */
+ src->flags = last_flags;
+ __raw_writel(*((u32 *) src + 3), (u32 __iomem *) dst + 3);
+ tx->req += cnt;
+ mb();
+}
+
+static inline void
+myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx,
+ struct mcp_kreq_ether_send *src, int cnt)
+{
+ tx->req += cnt;
+ mb();
+ while (cnt >= 4) {
+ myri10ge_pio_copy(tx->wc_fifo, src, 64);
+ mb();
+ src += 4;
+ cnt -= 4;
+ }
+ if (cnt > 0) {
+ /* pad it to 64 bytes. The src is 64 bytes bigger than it
+ * needs to be so that we don't overrun it */
+ myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64);
+ mb();
+ }
+}
+
+/*
+ * Transmit a packet. We need to split the packet so that a single
+ * segment does not cross myri10ge->tx.boundary, so this makes segment
+ * counting tricky. So rather than try to count segments up front, we
+ * just give up if there are too few segments to hold a reasonably
+ * fragmented packet currently available. If we run
+ * out of segments while preparing a packet for DMA, we just linearize
+ * it and try again.
+ */
+
+static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(dev);
+ struct mcp_kreq_ether_send *req;
+ struct myri10ge_tx_buf *tx = &mgp->tx;
+ struct skb_frag_struct *frag;
+ dma_addr_t bus;
+ u32 low, high_swapped;
+ unsigned int len;
+ int idx, last_idx, avail, frag_cnt, frag_idx, count, mss, max_segments;
+ u16 pseudo_hdr_offset, cksum_offset;
+ int cum_len, seglen, boundary, rdma_count;
+ u8 flags, odd_flag;
+
+again:
+ req = tx->req_list;
+ avail = tx->mask - 1 - (tx->req - tx->done);
+
+ mss = 0;
+ max_segments = MXGEFW_MAX_SEND_DESC;
+
+#ifdef NETIF_F_TSO
+ if (skb->len > (dev->mtu + ETH_HLEN)) {
+ mss = skb_shinfo(skb)->tso_size;
+ if (mss != 0)
+ max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
+ }
+#endif /*NETIF_F_TSO */
+
+ if ((unlikely(avail < max_segments))) {
+ /* we are out of transmit resources */
+ mgp->stop_queue++;
+ netif_stop_queue(dev);
+ return 1;
+ }
+
+ /* Setup checksum offloading, if needed */
+ cksum_offset = 0;
+ pseudo_hdr_offset = 0;
+ odd_flag = 0;
+ flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST);
+ if (likely(skb->ip_summed == CHECKSUM_HW)) {
+ cksum_offset = (skb->h.raw - skb->data);
+ pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data;
+ /* If the headers are excessively large, then we must
+ * fall back to a software checksum */
+ if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
+ if (skb_checksum_help(skb, 0))
+ goto drop;
+ cksum_offset = 0;
+ pseudo_hdr_offset = 0;
+ } else {
+ pseudo_hdr_offset = htons(pseudo_hdr_offset);
+ odd_flag = MXGEFW_FLAGS_ALIGN_ODD;
+ flags |= MXGEFW_FLAGS_CKSUM;
+ }
+ }
+
+ cum_len = 0;
+
+#ifdef NETIF_F_TSO
+ if (mss) { /* TSO */
+ /* this removes any CKSUM flag from before */
+ flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
+
+ /* negative cum_len signifies to the
+ * send loop that we are still in the
+ * header portion of the TSO packet.
+ * TSO header must be at most 134 bytes long */
+ cum_len = -((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+
+ /* for TSO, pseudo_hdr_offset holds mss.
+ * The firmware figures out where to put
+ * the checksum by parsing the header. */
+ pseudo_hdr_offset = htons(mss);
+ } else
+#endif /*NETIF_F_TSO */
+ /* Mark small packets, and pad out tiny packets */
+ if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
+ flags |= MXGEFW_FLAGS_SMALL;
+
+ /* pad frames to at least ETH_ZLEN bytes */
+ if (unlikely(skb->len < ETH_ZLEN)) {
+ skb = skb_padto(skb, ETH_ZLEN);
+ if (skb == NULL) {
+ /* The packet is gone, so we must
+ * return 0 */
+ mgp->stats.tx_dropped += 1;
+ return 0;
+ }
+ /* adjust the len to account for the zero pad
+ * so that the nic can know how long it is */
+ skb->len = ETH_ZLEN;
+ }
+ }
+
+ /* map the skb for DMA */
+ len = skb->len - skb->data_len;
+ idx = tx->req & tx->mask;
+ tx->info[idx].skb = skb;
+ bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&tx->info[idx], bus, bus);
+ pci_unmap_len_set(&tx->info[idx], len, len);
+
+ frag_cnt = skb_shinfo(skb)->nr_frags;
+ frag_idx = 0;
+ count = 0;
+ rdma_count = 0;
+
+ /* "rdma_count" is the number of RDMAs belonging to the
+ * current packet BEFORE the current send request. For
+ * non-TSO packets, this is equal to "count".
+ * For TSO packets, rdma_count needs to be reset
+ * to 0 after a segment cut.
+ *
+ * The rdma_count field of the send request is
+ * the number of RDMAs of the packet starting at
+ * that request. For TSO send requests with one ore more cuts
+ * in the middle, this is the number of RDMAs starting
+ * after the last cut in the request. All previous
+ * segments before the last cut implicitly have 1 RDMA.
+ *
+ * Since the number of RDMAs is not known beforehand,
+ * it must be filled-in retroactively - after each
+ * segmentation cut or at the end of the entire packet.
+ */
+
+ while (1) {
+ /* Break the SKB or Fragment up into pieces which
+ * do not cross mgp->tx.boundary */
+ low = MYRI10GE_LOWPART_TO_U32(bus);
+ high_swapped = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
+ while (len) {
+ u8 flags_next;
+ int cum_len_next;
+
+ if (unlikely(count == max_segments))
+ goto abort_linearize;
+
+ boundary = (low + tx->boundary) & ~(tx->boundary - 1);
+ seglen = boundary - low;
+ if (seglen > len)
+ seglen = len;
+ flags_next = flags & ~MXGEFW_FLAGS_FIRST;
+ cum_len_next = cum_len + seglen;
+#ifdef NETIF_F_TSO
+ if (mss) { /* TSO */
+ (req - rdma_count)->rdma_count = rdma_count + 1;
+
+ if (likely(cum_len >= 0)) { /* payload */
+ int next_is_first, chop;
+
+ chop = (cum_len_next > mss);
+ cum_len_next = cum_len_next % mss;
+ next_is_first = (cum_len_next == 0);
+ flags |= chop * MXGEFW_FLAGS_TSO_CHOP;
+ flags_next |= next_is_first *
+ MXGEFW_FLAGS_FIRST;
+ rdma_count |= -(chop | next_is_first);
+ rdma_count += chop & !next_is_first;
+ } else if (likely(cum_len_next >= 0)) { /* header ends */
+ int small;
+
+ rdma_count = -1;
+ cum_len_next = 0;
+ seglen = -cum_len;
+ small = (mss <= MXGEFW_SEND_SMALL_SIZE);
+ flags_next = MXGEFW_FLAGS_TSO_PLD |
+ MXGEFW_FLAGS_FIRST |
+ (small * MXGEFW_FLAGS_SMALL);
+ }
+ }
+#endif /* NETIF_F_TSO */
+ req->addr_high = high_swapped;
+ req->addr_low = htonl(low);
+ req->pseudo_hdr_offset = pseudo_hdr_offset;
+ req->pad = 0; /* complete solid 16-byte block; does this matter? */
+ req->rdma_count = 1;
+ req->length = htons(seglen);
+ req->cksum_offset = cksum_offset;
+ req->flags = flags | ((cum_len & 1) * odd_flag);
+
+ low += seglen;
+ len -= seglen;
+ cum_len = cum_len_next;
+ flags = flags_next;
+ req++;
+ count++;
+ rdma_count++;
+ if (unlikely(cksum_offset > seglen))
+ cksum_offset -= seglen;
+ else
+ cksum_offset = 0;
+ }
+ if (frag_idx == frag_cnt)
+ break;
+
+ /* map next fragment for DMA */
+ idx = (count + tx->req) & tx->mask;
+ frag = &skb_shinfo(skb)->frags[frag_idx];
+ frag_idx++;
+ len = frag->size;
+ bus = pci_map_page(mgp->pdev, frag->page, frag->page_offset,
+ len, PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&tx->info[idx], bus, bus);
+ pci_unmap_len_set(&tx->info[idx], len, len);
+ }
+
+ (req - rdma_count)->rdma_count = rdma_count;
+#ifdef NETIF_F_TSO
+ if (mss)
+ do {
+ req--;
+ req->flags |= MXGEFW_FLAGS_TSO_LAST;
+ } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
+ MXGEFW_FLAGS_FIRST)));
+#endif
+ idx = ((count - 1) + tx->req) & tx->mask;
+ tx->info[idx].last = 1;
+ if (tx->wc_fifo == NULL)
+ myri10ge_submit_req(tx, tx->req_list, count);
+ else
+ myri10ge_submit_req_wc(tx, tx->req_list, count);
+ tx->pkt_start++;
+ if ((avail - count) < MXGEFW_MAX_SEND_DESC) {
+ mgp->stop_queue++;
+ netif_stop_queue(dev);
+ }
+ dev->trans_start = jiffies;
+ return 0;
+
+abort_linearize:
+ /* Free any DMA resources we've alloced and clear out the skb
+ * slot so as to not trip up assertions, and to avoid a
+ * double-free if linearizing fails */
+
+ last_idx = (idx + 1) & tx->mask;
+ idx = tx->req & tx->mask;
+ tx->info[idx].skb = NULL;
+ do {
+ len = pci_unmap_len(&tx->info[idx], len);
+ if (len) {
+ if (tx->info[idx].skb != NULL)
+ pci_unmap_single(mgp->pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_page(mgp->pdev,
+ pci_unmap_addr(&tx->info[idx],
+ bus), len,
+ PCI_DMA_TODEVICE);
+ pci_unmap_len_set(&tx->info[idx], len, 0);
+ tx->info[idx].skb = NULL;
+ }
+ idx = (idx + 1) & tx->mask;
+ } while (idx != last_idx);
+ if (skb_shinfo(skb)->tso_size) {
+ printk(KERN_ERR
+ "myri10ge: %s: TSO but wanted to linearize?!?!?\n",
+ mgp->dev->name);
+ goto drop;
+ }
+
+ if (skb_linearize(skb, GFP_ATOMIC))
+ goto drop;
+
+ mgp->tx_linearized++;
+ goto again;
+
+drop:
+ dev_kfree_skb_any(skb);
+ mgp->stats.tx_dropped += 1;
+ return 0;
+
+}
+
+static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(dev);
+ return &mgp->stats;
+}
+
+static void myri10ge_set_multicast_list(struct net_device *dev)
+{
+ /* can be called from atomic contexts,
+ * pass 1 to force atomicity in myri10ge_send_cmd() */
+ myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1);
+}
+
+static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sa = addr;
+ struct myri10ge_priv *mgp = netdev_priv(dev);
+ int status;
+
+ if (!is_valid_ether_addr(sa->sa_data))
+ return -EADDRNOTAVAIL;
+
+ status = myri10ge_update_mac_address(mgp, sa->sa_data);
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: changing mac address failed with %d\n",
+ dev->name, status);
+ return status;
+ }
+
+ /* change the dev structure */
+ memcpy(dev->dev_addr, sa->sa_data, 6);
+ return 0;
+}
+
+static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct myri10ge_priv *mgp = netdev_priv(dev);
+ int error = 0;
+
+ if ((new_mtu < 68) || (ETH_HLEN + new_mtu > MYRI10GE_MAX_ETHER_MTU)) {
+ printk(KERN_ERR "myri10ge: %s: new mtu (%d) is not valid\n",
+ dev->name, new_mtu);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: changing mtu from %d to %d\n",
+ dev->name, dev->mtu, new_mtu);
+ if (mgp->running) {
+ /* if we change the mtu on an active device, we must
+ * reset the device so the firmware sees the change */
+ myri10ge_close(dev);
+ dev->mtu = new_mtu;
+ myri10ge_open(dev);
+ } else
+ dev->mtu = new_mtu;
+
+ return error;
+}
+
+/*
+ * Enable ECRC to align PCI-E Completion packets on an 8-byte boundary.
+ * Only do it if the bridge is a root port since we don't want to disturb
+ * any other device, except if forced with myri10ge_ecrc_enable > 1.
+ */
+
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
+
+static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *bridge = mgp->pdev->bus->self;
+ struct device *dev = &mgp->pdev->dev;
+ unsigned cap;
+ unsigned err_cap;
+ u16 val;
+ u8 ext_type;
+ int ret;
+
+ if (!myri10ge_ecrc_enable || !bridge)
+ return;
+
+ /* check that the bridge is a root port */
+ cap = pci_find_capability(bridge, PCI_CAP_ID_EXP);
+ pci_read_config_word(bridge, cap + PCI_CAP_FLAGS, &val);
+ ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
+ if (ext_type != PCI_EXP_TYPE_ROOT_PORT) {
+ if (myri10ge_ecrc_enable > 1) {
+ struct pci_dev *old_bridge = bridge;
+
+ /* Walk the hierarchy up to the root port
+ * where ECRC has to be enabled */
+ do {
+ bridge = bridge->bus->self;
+ if (!bridge) {
+ dev_err(dev,
+ "Failed to find root port"
+ " to force ECRC\n");
+ return;
+ }
+ cap =
+ pci_find_capability(bridge, PCI_CAP_ID_EXP);
+ pci_read_config_word(bridge,
+ cap + PCI_CAP_FLAGS, &val);
+ ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
+ } while (ext_type != PCI_EXP_TYPE_ROOT_PORT);
+
+ dev_info(dev,
+ "Forcing ECRC on non-root port %s"
+ " (enabling on root port %s)\n",
+ pci_name(old_bridge), pci_name(bridge));
+ } else {
+ dev_err(dev,
+ "Not enabling ECRC on non-root port %s\n",
+ pci_name(bridge));
+ return;
+ }
+ }
+
+ cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR);
+ /* nvidia ext cap is not always linked in ext cap chain */
+ if (!cap
+ && bridge->vendor == PCI_VENDOR_ID_NVIDIA
+ && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE)
+ cap = 0x160;
+
+ if (!cap)
+ return;
+
+ ret = pci_read_config_dword(bridge, cap + PCI_ERR_CAP, &err_cap);
+ if (ret) {
+ dev_err(dev, "failed reading ext-conf-space of %s\n",
+ pci_name(bridge));
+ dev_err(dev, "\t pci=nommconf in use? "
+ "or buggy/incomplete/absent ACPI MCFG attr?\n");
+ return;
+ }
+ if (!(err_cap & PCI_ERR_CAP_ECRC_GENC))
+ return;
+
+ err_cap |= PCI_ERR_CAP_ECRC_GENE;
+ pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap);
+ dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge));
+ mgp->tx.boundary = 4096;
+ mgp->fw_name = myri10ge_fw_aligned;
+}
+
+/*
+ * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput
+ * when the PCI-E Completion packets are aligned on an 8-byte
+ * boundary. Some PCI-E chip sets always align Completion packets; on
+ * the ones that do not, the alignment can be enforced by enabling
+ * ECRC generation (if supported).
+ *
+ * When PCI-E Completion packets are not aligned, it is actually more
+ * efficient to limit Read-DMA transactions to 2KB, rather than 4KB.
+ *
+ * If the driver can neither enable ECRC nor verify that it has
+ * already been enabled, then it must use a firmware image which works
+ * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it
+ * should also ensure that it never gives the device a Read-DMA which is
+ * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is
+ * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat)
+ * firmware image, and set tx.boundary to 4KB.
+ */
+
+#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
+
+static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *bridge = mgp->pdev->bus->self;
+
+ mgp->tx.boundary = 2048;
+ mgp->fw_name = myri10ge_fw_unaligned;
+
+ if (myri10ge_force_firmware == 0) {
+ myri10ge_enable_ecrc(mgp);
+
+ /* Check to see if the upstream bridge is known to
+ * provide aligned completions */
+ if (bridge
+ /* ServerWorks HT2000/HT1000 */
+ && bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
+ && bridge->device ==
+ PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE) {
+ dev_info(&mgp->pdev->dev,
+ "Assuming aligned completions (0x%x:0x%x)\n",
+ bridge->vendor, bridge->device);
+ mgp->tx.boundary = 4096;
+ mgp->fw_name = myri10ge_fw_aligned;
+ }
+ } else {
+ if (myri10ge_force_firmware == 1) {
+ dev_info(&mgp->pdev->dev,
+ "Assuming aligned completions (forced)\n");
+ mgp->tx.boundary = 4096;
+ mgp->fw_name = myri10ge_fw_aligned;
+ } else {
+ dev_info(&mgp->pdev->dev,
+ "Assuming unaligned completions (forced)\n");
+ mgp->tx.boundary = 2048;
+ mgp->fw_name = myri10ge_fw_unaligned;
+ }
+ }
+ if (myri10ge_fw_name != NULL) {
+ dev_info(&mgp->pdev->dev, "overriding firmware to %s\n",
+ myri10ge_fw_name);
+ mgp->fw_name = myri10ge_fw_name;
+ }
+}
+
+static void myri10ge_save_state(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ int cap;
+
+ pci_save_state(pdev);
+ /* now save PCIe and MSI state that Linux will not
+ * save for us */
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, &mgp->devctl);
+ cap = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+ pci_read_config_word(pdev, cap + PCI_MSI_FLAGS, &mgp->msi_flags);
+}
+
+static void myri10ge_restore_state(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ int cap;
+
+ /* restore PCIe and MSI state that linux will not */
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ pci_write_config_dword(pdev, cap + PCI_CAP_ID_EXP, mgp->devctl);
+ cap = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+ pci_write_config_word(pdev, cap + PCI_MSI_FLAGS, mgp->msi_flags);
+
+ pci_restore_state(pdev);
+}
+
+#ifdef CONFIG_PM
+
+static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct myri10ge_priv *mgp;
+ struct net_device *netdev;
+
+ mgp = pci_get_drvdata(pdev);
+ if (mgp == NULL)
+ return -EINVAL;
+ netdev = mgp->dev;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev)) {
+ printk(KERN_INFO "myri10ge: closing %s\n", netdev->name);
+ rtnl_lock();
+ myri10ge_close(netdev);
+ rtnl_unlock();
+ }
+ myri10ge_dummy_rdma(mgp, 0);
+ free_irq(pdev->irq, mgp);
+ myri10ge_save_state(mgp);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int myri10ge_resume(struct pci_dev *pdev)
+{
+ struct myri10ge_priv *mgp;
+ struct net_device *netdev;
+ int status;
+ u16 vendor;
+
+ mgp = pci_get_drvdata(pdev);
+ if (mgp == NULL)
+ return -EINVAL;
+ netdev = mgp->dev;
+ pci_set_power_state(pdev, 0); /* zeros conf space as a side effect */
+ msleep(5); /* give card time to respond */
+ pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor);
+ if (vendor == 0xffff) {
+ printk(KERN_ERR "myri10ge: %s: device disappeared!\n",
+ mgp->dev->name);
+ return -EIO;
+ }
+ myri10ge_restore_state(mgp);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+
+ status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ,
+ netdev->name, mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to allocate IRQ\n");
+ goto abort_with_msi;
+ }
+
+ myri10ge_reset(mgp);
+ myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096);
+
+ /* Save configuration space to be restored if the
+ * nic resets due to a parity error */
+ myri10ge_save_state(mgp);
+
+ if (netif_running(netdev)) {
+ rtnl_lock();
+ myri10ge_open(netdev);
+ rtnl_unlock();
+ }
+ netif_device_attach(netdev);
+
+ return 0;
+
+abort_with_msi:
+ return -EIO;
+
+}
+
+#endif /* CONFIG_PM */
+
+static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ int vs = mgp->vendor_specific_offset;
+ u32 reboot;
+
+ /*enter read32 mode */
+ pci_write_config_byte(pdev, vs + 0x10, 0x3);
+
+ /*read REBOOT_STATUS (0xfffffff0) */
+ pci_write_config_dword(pdev, vs + 0x18, 0xfffffff0);
+ pci_read_config_dword(pdev, vs + 0x14, &reboot);
+ return reboot;
+}
+
+/*
+ * This watchdog is used to check whether the board has suffered
+ * from a parity error and needs to be recovered.
+ */
+static void myri10ge_watchdog(void *arg)
+{
+ struct myri10ge_priv *mgp = arg;
+ u32 reboot;
+ int status;
+ u16 cmd, vendor;
+
+ mgp->watchdog_resets++;
+ pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd);
+ if ((cmd & PCI_COMMAND_MASTER) == 0) {
+ /* Bus master DMA disabled? Check to see
+ * if the card rebooted due to a parity error
+ * For now, just report it */
+ reboot = myri10ge_read_reboot(mgp);
+ printk(KERN_ERR
+ "myri10ge: %s: NIC rebooted (0x%x), resetting\n",
+ mgp->dev->name, reboot);
+ /*
+ * A rebooted nic will come back with config space as
+ * it was after power was applied to PCIe bus.
+ * Attempt to restore config space which was saved
+ * when the driver was loaded, or the last time the
+ * nic was resumed from power saving mode.
+ */
+ myri10ge_restore_state(mgp);
+ } else {
+ /* if we get back -1's from our slot, perhaps somebody
+ * powered off our card. Don't try to reset it in
+ * this case */
+ if (cmd == 0xffff) {
+ pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor);
+ if (vendor == 0xffff) {
+ printk(KERN_ERR
+ "myri10ge: %s: device disappeared!\n",
+ mgp->dev->name);
+ return;
+ }
+ }
+ /* Perhaps it is a software error. Try to reset */
+
+ printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
+ mgp->dev->name);
+ printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
+ mgp->dev->name, mgp->tx.req, mgp->tx.done,
+ mgp->tx.pkt_start, mgp->tx.pkt_done,
+ (int)ntohl(mgp->fw_stats->send_done_count));
+ msleep(2000);
+ printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
+ mgp->dev->name, mgp->tx.req, mgp->tx.done,
+ mgp->tx.pkt_start, mgp->tx.pkt_done,
+ (int)ntohl(mgp->fw_stats->send_done_count));
+ }
+ rtnl_lock();
+ myri10ge_close(mgp->dev);
+ status = myri10ge_load_firmware(mgp);
+ if (status != 0)
+ printk(KERN_ERR "myri10ge: %s: failed to load firmware\n",
+ mgp->dev->name);
+ else
+ myri10ge_open(mgp->dev);
+ rtnl_unlock();
+}
+
+/*
+ * We use our own timer routine rather than relying upon
+ * netdev->tx_timeout because we have a very large hardware transmit
+ * queue. Due to the large queue, the netdev->tx_timeout function
+ * cannot detect a NIC with a parity error in a timely fashion if the
+ * NIC is lightly loaded.
+ */
+static void myri10ge_watchdog_timer(unsigned long arg)
+{
+ struct myri10ge_priv *mgp;
+
+ mgp = (struct myri10ge_priv *)arg;
+ if (mgp->tx.req != mgp->tx.done &&
+ mgp->tx.done == mgp->watchdog_tx_done)
+ /* nic seems like it might be stuck.. */
+ schedule_work(&mgp->watchdog_work);
+ else
+ /* rearm timer */
+ mod_timer(&mgp->watchdog_timer,
+ jiffies + myri10ge_watchdog_timeout * HZ);
+
+ mgp->watchdog_tx_done = mgp->tx.done;
+}
+
+static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct myri10ge_priv *mgp;
+ struct device *dev = &pdev->dev;
+ size_t bytes;
+ int i;
+ int status = -ENXIO;
+ int cap;
+ int dac_enabled;
+ u16 val;
+
+ netdev = alloc_etherdev(sizeof(*mgp));
+ if (netdev == NULL) {
+ dev_err(dev, "Could not allocate ethernet device\n");
+ return -ENOMEM;
+ }
+
+ mgp = netdev_priv(netdev);
+ memset(mgp, 0, sizeof(*mgp));
+ mgp->dev = netdev;
+ mgp->pdev = pdev;
+ mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
+ mgp->pause = myri10ge_flow_control;
+ mgp->intr_coal_delay = myri10ge_intr_coal_delay;
+ init_waitqueue_head(&mgp->down_wq);
+
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev, "pci_enable_device call failed\n");
+ status = -ENODEV;
+ goto abort_with_netdev;
+ }
+ myri10ge_select_firmware(mgp);
+
+ /* Find the vendor-specific cap so we can check
+ * the reboot register later on */
+ mgp->vendor_specific_offset
+ = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
+
+ /* Set our max read request to 4KB */
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (cap < 64) {
+ dev_err(&pdev->dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
+ goto abort_with_netdev;
+ }
+ status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
+ if (status != 0) {
+ dev_err(&pdev->dev, "Error %d reading PCI_EXP_DEVCTL\n",
+ status);
+ goto abort_with_netdev;
+ }
+ val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
+ status = pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, val);
+ if (status != 0) {
+ dev_err(&pdev->dev, "Error %d writing PCI_EXP_DEVCTL\n",
+ status);
+ goto abort_with_netdev;
+ }
+
+ pci_set_master(pdev);
+ dac_enabled = 1;
+ status = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (status != 0) {
+ dac_enabled = 0;
+ dev_err(&pdev->dev,
+ "64-bit pci address mask was refused, trying 32-bit");
+ status = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ }
+ if (status != 0) {
+ dev_err(&pdev->dev, "Error %d setting DMA mask\n", status);
+ goto abort_with_netdev;
+ }
+ mgp->cmd = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ &mgp->cmd_bus, GFP_KERNEL);
+ if (mgp->cmd == NULL)
+ goto abort_with_netdev;
+
+ mgp->fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ &mgp->fw_stats_bus, GFP_KERNEL);
+ if (mgp->fw_stats == NULL)
+ goto abort_with_cmd;
+
+ mgp->board_span = pci_resource_len(pdev, 0);
+ mgp->iomem_base = pci_resource_start(pdev, 0);
+ mgp->mtrr = -1;
+#ifdef CONFIG_MTRR
+ mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span,
+ MTRR_TYPE_WRCOMB, 1);
+#endif
+ /* Hack. need to get rid of these magic numbers */
+ mgp->sram_size =
+ 2 * 1024 * 1024 - (2 * (48 * 1024) + (32 * 1024)) - 0x100;
+ if (mgp->sram_size > mgp->board_span) {
+ dev_err(&pdev->dev, "board span %ld bytes too small\n",
+ mgp->board_span);
+ goto abort_with_wc;
+ }
+ mgp->sram = ioremap(mgp->iomem_base, mgp->board_span);
+ if (mgp->sram == NULL) {
+ dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n",
+ mgp->board_span, mgp->iomem_base);
+ status = -ENXIO;
+ goto abort_with_wc;
+ }
+ memcpy_fromio(mgp->eeprom_strings,
+ mgp->sram + mgp->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE,
+ MYRI10GE_EEPROM_STRINGS_SIZE);
+ memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2);
+ status = myri10ge_read_mac_addr(mgp);
+ if (status)
+ goto abort_with_ioremap;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ netdev->dev_addr[i] = mgp->mac_addr[i];
+
+ /* allocate rx done ring */
+ bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ mgp->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+ &mgp->rx_done.bus, GFP_KERNEL);
+ if (mgp->rx_done.entry == NULL)
+ goto abort_with_ioremap;
+ memset(mgp->rx_done.entry, 0, bytes);
+
+ status = myri10ge_load_firmware(mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to load firmware\n");
+ goto abort_with_rx_done;
+ }
+
+ status = myri10ge_reset(mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed reset\n");
+ goto abort_with_firmware;
+ }
+
+ if (myri10ge_msi) {
+ status = pci_enable_msi(pdev);
+ if (status != 0)
+ dev_err(&pdev->dev,
+ "Error %d setting up MSI; falling back to xPIC\n",
+ status);
+ else
+ mgp->msi_enabled = 1;
+ }
+
+ status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ,
+ netdev->name, mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to allocate IRQ\n");
+ goto abort_with_firmware;
+ }
+
+ pci_set_drvdata(pdev, mgp);
+ if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU)
+ myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
+ if ((myri10ge_initial_mtu + ETH_HLEN) < 68)
+ myri10ge_initial_mtu = 68;
+ netdev->mtu = myri10ge_initial_mtu;
+ netdev->open = myri10ge_open;
+ netdev->stop = myri10ge_close;
+ netdev->hard_start_xmit = myri10ge_xmit;
+ netdev->get_stats = myri10ge_get_stats;
+ netdev->base_addr = mgp->iomem_base;
+ netdev->irq = pdev->irq;
+ netdev->change_mtu = myri10ge_change_mtu;
+ netdev->set_multicast_list = myri10ge_set_multicast_list;
+ netdev->set_mac_address = myri10ge_set_mac_address;
+ netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ if (dac_enabled)
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->poll = myri10ge_poll;
+ netdev->weight = myri10ge_napi_weight;
+
+ /* Save configuration space to be restored if the
+ * nic resets due to a parity error */
+ myri10ge_save_state(mgp);
+ /* Restore state immediately since pci_save_msi_state disables MSI */
+ myri10ge_restore_state(mgp);
+
+ /* Setup the watchdog timer */
+ setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer,
+ (unsigned long)mgp);
+
+ SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops);
+ INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog, mgp);
+ status = register_netdev(netdev);
+ if (status != 0) {
+ dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
+ goto abort_with_irq;
+ }
+
+ printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+ netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
+ pdev->irq, mgp->tx.boundary, mgp->fw_name,
+ (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+
+ return 0;
+
+abort_with_irq:
+ free_irq(pdev->irq, mgp);
+ if (mgp->msi_enabled)
+ pci_disable_msi(pdev);
+
+abort_with_firmware:
+ myri10ge_dummy_rdma(mgp, 0);
+
+abort_with_rx_done:
+ bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ dma_free_coherent(&pdev->dev, bytes,
+ mgp->rx_done.entry, mgp->rx_done.bus);
+
+abort_with_ioremap:
+ iounmap(mgp->sram);
+
+abort_with_wc:
+#ifdef CONFIG_MTRR
+ if (mgp->mtrr >= 0)
+ mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
+#endif
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ mgp->fw_stats, mgp->fw_stats_bus);
+
+abort_with_cmd:
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ mgp->cmd, mgp->cmd_bus);
+
+abort_with_netdev:
+
+ free_netdev(netdev);
+ return status;
+}
+
+/*
+ * myri10ge_remove
+ *
+ * Does what is necessary to shutdown one Myrinet device. Called
+ * once for each Myrinet card by the kernel when a module is
+ * unloaded.
+ */
+static void myri10ge_remove(struct pci_dev *pdev)
+{
+ struct myri10ge_priv *mgp;
+ struct net_device *netdev;
+ size_t bytes;
+
+ mgp = pci_get_drvdata(pdev);
+ if (mgp == NULL)
+ return;
+
+ flush_scheduled_work();
+ netdev = mgp->dev;
+ unregister_netdev(netdev);
+ free_irq(pdev->irq, mgp);
+ if (mgp->msi_enabled)
+ pci_disable_msi(pdev);
+
+ myri10ge_dummy_rdma(mgp, 0);
+
+ bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ dma_free_coherent(&pdev->dev, bytes,
+ mgp->rx_done.entry, mgp->rx_done.bus);
+
+ iounmap(mgp->sram);
+
+#ifdef CONFIG_MTRR
+ if (mgp->mtrr >= 0)
+ mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
+#endif
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ mgp->fw_stats, mgp->fw_stats_bus);
+
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ mgp->cmd, mgp->cmd_bus);
+
+ free_netdev(netdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008
+
+static struct pci_device_id myri10ge_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
+ {0},
+};
+
+static struct pci_driver myri10ge_driver = {
+ .name = "myri10ge",
+ .probe = myri10ge_probe,
+ .remove = myri10ge_remove,
+ .id_table = myri10ge_pci_tbl,
+#ifdef CONFIG_PM
+ .suspend = myri10ge_suspend,
+ .resume = myri10ge_resume,
+#endif
+};
+
+static __init int myri10ge_init_module(void)
+{
+ printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
+ MYRI10GE_VERSION_STR);
+ return pci_register_driver(&myri10ge_driver);
+}
+
+module_init(myri10ge_init_module);
+
+static __exit void myri10ge_cleanup_module(void)
+{
+ pci_unregister_driver(&myri10ge_driver);
+}
+
+module_exit(myri10ge_cleanup_module);
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
new file mode 100644
index 000000000000..0a6cae6cb186
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -0,0 +1,205 @@
+#ifndef __MYRI10GE_MCP_H__
+#define __MYRI10GE_MCP_H__
+
+#define MXGEFW_VERSION_MAJOR 1
+#define MXGEFW_VERSION_MINOR 4
+
+/* 8 Bytes */
+struct mcp_dma_addr {
+ u32 high;
+ u32 low;
+};
+
+/* 4 Bytes */
+struct mcp_slot {
+ u16 checksum;
+ u16 length;
+};
+
+/* 64 Bytes */
+struct mcp_cmd {
+ u32 cmd;
+ u32 data0; /* will be low portion if data > 32 bits */
+ /* 8 */
+ u32 data1; /* will be high portion if data > 32 bits */
+ u32 data2; /* currently unused.. */
+ /* 16 */
+ struct mcp_dma_addr response_addr;
+ /* 24 */
+ u8 pad[40];
+};
+
+/* 8 Bytes */
+struct mcp_cmd_response {
+ u32 data;
+ u32 result;
+};
+
+/*
+ * flags used in mcp_kreq_ether_send_t:
+ *
+ * The SMALL flag is only needed in the first segment. It is raised
+ * for packets that are total less or equal 512 bytes.
+ *
+ * The CKSUM flag must be set in all segments.
+ *
+ * The PADDED flags is set if the packet needs to be padded, and it
+ * must be set for all segments.
+ *
+ * The MXGEFW_FLAGS_ALIGN_ODD must be set if the cumulative
+ * length of all previous segments was odd.
+ */
+
+#define MXGEFW_FLAGS_SMALL 0x1
+#define MXGEFW_FLAGS_TSO_HDR 0x1
+#define MXGEFW_FLAGS_FIRST 0x2
+#define MXGEFW_FLAGS_ALIGN_ODD 0x4
+#define MXGEFW_FLAGS_CKSUM 0x8
+#define MXGEFW_FLAGS_TSO_LAST 0x8
+#define MXGEFW_FLAGS_NO_TSO 0x10
+#define MXGEFW_FLAGS_TSO_CHOP 0x10
+#define MXGEFW_FLAGS_TSO_PLD 0x20
+
+#define MXGEFW_SEND_SMALL_SIZE 1520
+#define MXGEFW_MAX_MTU 9400
+
+union mcp_pso_or_cumlen {
+ u16 pseudo_hdr_offset;
+ u16 cum_len;
+};
+
+#define MXGEFW_MAX_SEND_DESC 12
+#define MXGEFW_PAD 2
+
+/* 16 Bytes */
+struct mcp_kreq_ether_send {
+ u32 addr_high;
+ u32 addr_low;
+ u16 pseudo_hdr_offset;
+ u16 length;
+ u8 pad;
+ u8 rdma_count;
+ u8 cksum_offset; /* where to start computing cksum */
+ u8 flags; /* as defined above */
+};
+
+/* 8 Bytes */
+struct mcp_kreq_ether_recv {
+ u32 addr_high;
+ u32 addr_low;
+};
+
+/* Commands */
+
+#define MXGEFW_CMD_OFFSET 0xf80000
+
+enum myri10ge_mcp_cmd_type {
+ MXGEFW_CMD_NONE = 0,
+ /* Reset the mcp, it is left in a safe state, waiting
+ * for the driver to set all its parameters */
+ MXGEFW_CMD_RESET,
+
+ /* get the version number of the current firmware..
+ * (may be available in the eeprom strings..? */
+ MXGEFW_GET_MCP_VERSION,
+
+ /* Parameters which must be set by the driver before it can
+ * issue MXGEFW_CMD_ETHERNET_UP. They persist until the next
+ * MXGEFW_CMD_RESET is issued */
+
+ MXGEFW_CMD_SET_INTRQ_DMA,
+ MXGEFW_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */
+ MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */
+
+ /* Parameters which refer to lanai SRAM addresses where the
+ * driver must issue PIO writes for various things */
+
+ MXGEFW_CMD_GET_SEND_OFFSET,
+ MXGEFW_CMD_GET_SMALL_RX_OFFSET,
+ MXGEFW_CMD_GET_BIG_RX_OFFSET,
+ MXGEFW_CMD_GET_IRQ_ACK_OFFSET,
+ MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
+
+ /* Parameters which refer to rings stored on the MCP,
+ * and whose size is controlled by the mcp */
+
+ MXGEFW_CMD_GET_SEND_RING_SIZE, /* in bytes */
+ MXGEFW_CMD_GET_RX_RING_SIZE, /* in bytes */
+
+ /* Parameters which refer to rings stored in the host,
+ * and whose size is controlled by the host. Note that
+ * all must be physically contiguous and must contain
+ * a power of 2 number of entries. */
+
+ MXGEFW_CMD_SET_INTRQ_SIZE, /* in bytes */
+
+ /* command to bring ethernet interface up. Above parameters
+ * (plus mtu & mac address) must have been exchanged prior
+ * to issuing this command */
+ MXGEFW_CMD_ETHERNET_UP,
+
+ /* command to bring ethernet interface down. No further sends
+ * or receives may be processed until an MXGEFW_CMD_ETHERNET_UP
+ * is issued, and all interrupt queues must be flushed prior
+ * to ack'ing this command */
+
+ MXGEFW_CMD_ETHERNET_DOWN,
+
+ /* commands the driver may issue live, without resetting
+ * the nic. Note that increasing the mtu "live" should
+ * only be done if the driver has already supplied buffers
+ * sufficiently large to handle the new mtu. Decreasing
+ * the mtu live is safe */
+
+ MXGEFW_CMD_SET_MTU,
+ MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */
+ MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */
+ MXGEFW_CMD_SET_STATS_DMA,
+
+ MXGEFW_ENABLE_PROMISC,
+ MXGEFW_DISABLE_PROMISC,
+ MXGEFW_SET_MAC_ADDRESS,
+
+ MXGEFW_ENABLE_FLOW_CONTROL,
+ MXGEFW_DISABLE_FLOW_CONTROL,
+
+ /* do a DMA test
+ * data0,data1 = DMA address
+ * data2 = RDMA length (MSH), WDMA length (LSH)
+ * command return data = repetitions (MSH), 0.5-ms ticks (LSH)
+ */
+ MXGEFW_DMA_TEST
+};
+
+enum myri10ge_mcp_cmd_status {
+ MXGEFW_CMD_OK = 0,
+ MXGEFW_CMD_UNKNOWN,
+ MXGEFW_CMD_ERROR_RANGE,
+ MXGEFW_CMD_ERROR_BUSY,
+ MXGEFW_CMD_ERROR_EMPTY,
+ MXGEFW_CMD_ERROR_CLOSED,
+ MXGEFW_CMD_ERROR_HASH_ERROR,
+ MXGEFW_CMD_ERROR_BAD_PORT,
+ MXGEFW_CMD_ERROR_RESOURCES
+};
+
+/* 40 Bytes */
+struct mcp_irq_data {
+ u32 send_done_count;
+
+ u32 link_up;
+ u32 dropped_link_overflow;
+ u32 dropped_link_error_or_filtered;
+ u32 dropped_runt;
+ u32 dropped_overrun;
+ u32 dropped_no_small_buffer;
+ u32 dropped_no_big_buffer;
+ u32 rdma_tags_available;
+
+ u8 tx_stopped;
+ u8 link_down;
+ u8 stats_updated;
+ u8 valid;
+};
+
+#endif /* __MYRI10GE_MCP_H__ */
diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
new file mode 100644
index 000000000000..487f7792fd46
--- /dev/null
+++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
@@ -0,0 +1,58 @@
+#ifndef __MYRI10GE_MCP_GEN_HEADER_H__
+#define __MYRI10GE_MCP_GEN_HEADER_H__
+
+/* this file define a standard header used as a first entry point to
+ * exchange information between firmware/driver and driver. The
+ * header structure can be anywhere in the mcp. It will usually be in
+ * the .data section, because some fields needs to be initialized at
+ * compile time.
+ * The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must
+ * contains the location of the header.
+ *
+ * Typically a MCP will start with the following:
+ * .text
+ * .space 52 ! to help catch MEMORY_INT errors
+ * bt start ! jump to real code
+ * nop
+ * .long _gen_mcp_header
+ *
+ * The source will have a definition like:
+ *
+ * mcp_gen_header_t gen_mcp_header = {
+ * .header_length = sizeof(mcp_gen_header_t),
+ * .mcp_type = MCP_TYPE_XXX,
+ * .version = "something $Id: mcp_gen_header.h,v 1.2 2006/05/13 10:04:35 bgoglin Exp $",
+ * .mcp_globals = (unsigned)&Globals
+ * };
+ */
+
+#define MCP_HEADER_PTR_OFFSET 0x3c
+
+#define MCP_TYPE_MX 0x4d582020 /* "MX " */
+#define MCP_TYPE_PCIE 0x70636965 /* "PCIE" pcie-only MCP */
+#define MCP_TYPE_ETH 0x45544820 /* "ETH " */
+#define MCP_TYPE_MCP0 0x4d435030 /* "MCP0" */
+
+struct mcp_gen_header {
+ /* the first 4 fields are filled at compile time */
+ unsigned header_length;
+ unsigned mcp_type;
+ char version[128];
+ unsigned mcp_globals; /* pointer to mcp-type specific structure */
+
+ /* filled by the MCP at run-time */
+ unsigned sram_size;
+ unsigned string_specs; /* either the original STRING_SPECS or a superset */
+ unsigned string_specs_len;
+
+ /* Fields above this comment are guaranteed to be present.
+ *
+ * Fields below this comment are extensions added in later versions
+ * of this struct, drivers should compare the header_length against
+ * offsetof(field) to check wether a given MCP implements them.
+ *
+ * Never remove any field. Keep everything naturally align.
+ */
+};
+
+#endif /* __MYRI10GE_MCP_GEN_HEADER_H__ */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 90627756d6fa..2e4ecedba057 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -318,12 +318,12 @@ performance critical codepaths:
The rx process only runs in the interrupt handler. Access from outside
the interrupt handler is only permitted after disable_irq().
-The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
+The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
is set, then access is permitted under spin_lock_irq(&np->lock).
Thus configuration functions that want to access everything must call
disable_irq(dev->irq);
- spin_lock_bh(dev->xmit_lock);
+ netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
IV. Notes
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 93c494bcd18d..963a11fa9fe2 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -139,8 +139,9 @@ bad_clone_list[] __initdata = {
#if defined(CONFIG_PLAT_MAPPI)
# define DCR_VAL 0x4b
-#elif defined(CONFIG_PLAT_OAKS32R)
-# define DCR_VAL 0x48
+#elif defined(CONFIG_PLAT_OAKS32R) || \
+ defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
+# define DCR_VAL 0x48 /* 8-bit mode */
#else
# define DCR_VAL 0x49
#endif
@@ -396,10 +397,22 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
/* We must set the 8390 for word mode. */
outb_p(DCR_VAL, ioaddr + EN0_DCFG);
start_page = NESM_START_PG;
- stop_page = NESM_STOP_PG;
+
+ /*
+ * Realtek RTL8019AS datasheet says that the PSTOP register
+ * shouldn't exceed 0x60 in 8-bit mode.
+ * This chip can be identified by reading the signature from
+ * the remote byte count registers (otherwise write-only)...
+ */
+ if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */
+ inb(ioaddr + EN0_RCNTLO) == 0x50 &&
+ inb(ioaddr + EN0_RCNTHI) == 0x70)
+ stop_page = 0x60;
+ else
+ stop_page = NESM_STOP_PG;
} else {
start_page = NE1SM_START_PG;
- stop_page = NE1SM_STOP_PG;
+ stop_page = NE1SM_STOP_PG;
}
#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R)
@@ -509,15 +522,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
ei_status.name = name;
ei_status.tx_start_page = start_page;
ei_status.stop_page = stop_page;
-#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
- wordlength = 1;
-#endif
-#ifdef CONFIG_PLAT_OAKS32R
- ei_status.word16 = 0;
-#else
- ei_status.word16 = (wordlength == 2);
-#endif
+ /* Use 16-bit mode only if this wasn't overridden by DCR_VAL */
+ ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01));
ei_status.rx_start_page = start_page + TX_PAGES;
#ifdef PACKETBUF_MEMSIZE
@@ -822,7 +829,7 @@ that the ne2k probe is the last 8390 based probe to take place (as it
is at boot) and so the probe will get confused by any other 8390 cards.
ISA device autoprobes on a running machine are not recommended anyway. */
-int init_module(void)
+int __init init_module(void)
{
int this_dev, found = 0;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 2aa7b77f84f8..eebf5f02b476 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -780,7 +780,7 @@ MODULE_PARM_DESC(bad, "(ignored)");
/* Module code fixed by David Weinehall */
-int init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 66e74f740261..bf58db29e2ed 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -107,7 +107,7 @@ static int init_netconsole(void)
if(!configured) {
printk("netconsole: not configured, aborting\n");
- return -EINVAL;
+ return 0;
}
if(netpoll_setup(&np))
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 448a09488529..2ea66aca648b 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1691,17 +1691,6 @@ static void do_set_multicast_list(struct net_device *dev)
memset(ei_local->mcfilter, 0xFF, 8);
}
- /*
- * DP8390 manuals don't specify any magic sequence for altering
- * the multicast regs on an already running card. To be safe, we
- * ensure multicast mode is off prior to loading up the new hash
- * table. If this proves to be not enough, we can always resort
- * to stopping the NIC, loading the table and then restarting.
- */
-
- if (netif_running(dev))
- outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
-
outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
for(i = 0; i < 8; i++)
{
@@ -1715,6 +1704,8 @@ static void do_set_multicast_list(struct net_device *dev)
outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
else
outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
+
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
}
/*
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 4260c2128f47..a8f6bfc96fd2 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1204,7 +1204,7 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt)
dev->last_rx = jiffies;
lp->linux_stats.rx_packets++;
- lp->linux_stats.rx_bytes += skb->len;
+ lp->linux_stats.rx_bytes += pkt_len;
outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
continue;
} else {
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 506e777c5f06..661bfe54ff5d 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -12,7 +12,7 @@
Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
pcnet_cs.c 1.153 2003/11/09 18:53:09
-
+
The network driver code is based on Donald Becker's NE2000 code:
Written 1992,1993 by Donald Becker.
@@ -146,7 +146,7 @@ typedef struct hw_info_t {
#define MII_PHYID_REG2 0x03
static hw_info_t hw_info[] = {
- { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
+ { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
{ /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
{ /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
{ /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
@@ -193,7 +193,7 @@ static hw_info_t hw_info[] = {
{ /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
{ /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
HAS_MISC_REG | HAS_IBM_MISC },
- { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
+ { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
HAS_MISC_REG | HAS_IBM_MISC },
{ /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
{ /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
@@ -330,7 +330,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
for (j = 0; j < 6; j++)
dev->dev_addr[j] = readb(base + (j<<1));
}
-
+
iounmap(virt);
j = pcmcia_release_window(link->win);
if (j != CS_SUCCESS)
@@ -490,7 +490,7 @@ static int try_io_port(struct pcmcia_device *link)
if (link->io.NumPorts2 > 0) {
/* for master/slave multifunction cards */
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->irq.Attributes =
+ link->irq.Attributes =
IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
}
} else {
@@ -543,19 +543,19 @@ static int pcnet_config(struct pcmcia_device *link)
manfid = le16_to_cpu(buf[0]);
prodid = le16_to_cpu(buf[1]);
}
-
+
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
tuple.Attributes = 0;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
while (last_ret == CS_SUCCESS) {
cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
cistpl_io_t *io = &(parse.cftable_entry.io);
-
+
if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
cfg->index == 0 || cfg->io.nwin == 0)
goto next_entry;
-
+
link->conf.ConfigIndex = cfg->index;
/* For multifunction cards, by convention, we configure the
network function with window 0, and serial with window 1 */
@@ -584,7 +584,7 @@ static int pcnet_config(struct pcmcia_device *link)
}
CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-
+
if (link->io.NumPorts2 == 8) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
@@ -592,7 +592,7 @@ static int pcnet_config(struct pcmcia_device *link)
if ((manfid == MANFID_IBM) &&
(prodid == PRODID_IBM_HOME_AND_AWAY))
link->conf.ConfigIndex |= 0x10;
-
+
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
@@ -614,7 +614,7 @@ static int pcnet_config(struct pcmcia_device *link)
hw_info = get_ax88190(link);
if (hw_info == NULL)
hw_info = get_hwired(link);
-
+
if (hw_info == NULL) {
printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
" address for io base %#3lx\n", dev->base_addr);
@@ -631,7 +631,7 @@ static int pcnet_config(struct pcmcia_device *link)
info->flags &= ~USE_BIG_BUF;
if (!use_big_buf)
info->flags &= ~USE_BIG_BUF;
-
+
if (info->flags & USE_BIG_BUF) {
start_pg = SOCKET_START_PG;
stop_pg = SOCKET_STOP_PG;
@@ -929,7 +929,7 @@ static void set_misc_reg(struct net_device *dev)
kio_addr_t nic_base = dev->base_addr;
pcnet_dev_t *info = PRIV(dev);
u_char tmp;
-
+
if (info->flags & HAS_MISC_REG) {
tmp = inb_p(nic_base + PCNET_MISC) & ~3;
if (dev->if_port == 2)
@@ -1022,7 +1022,7 @@ static int pcnet_close(struct net_device *dev)
ei_close(dev);
free_irq(dev->irq, dev);
-
+
link->open--;
netif_stop_queue(dev);
del_timer_sync(&info->watchdog);
@@ -1054,12 +1054,12 @@ static void pcnet_reset_8390(struct net_device *dev)
udelay(100);
}
outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
-
+
if (i == 100)
printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
dev->name);
set_misc_reg(dev);
-
+
} /* pcnet_reset_8390 */
/*====================================================================*/
@@ -1233,7 +1233,7 @@ static void dma_get_8390_hdr(struct net_device *dev,
dev->name, ei_status.dmaing, ei_status.irqlock);
return;
}
-
+
ei_status.dmaing |= 0x01;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
@@ -1458,7 +1458,7 @@ static void shmem_get_8390_hdr(struct net_device *dev,
void __iomem *xfer_start = ei_status.mem + (TX_PAGES<<8)
+ (ring_page << 8)
- (ei_status.rx_start_page << 8);
-
+
copyin(hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
/* Fix for big endian systems */
hdr->count = le16_to_cpu(hdr->count);
@@ -1473,7 +1473,7 @@ static void shmem_block_input(struct net_device *dev, int count,
unsigned long offset = (TX_PAGES<<8) + ring_offset
- (ei_status.rx_start_page << 8);
char *buf = skb->data;
-
+
if (offset + count > ei_status.priv) {
/* We must wrap the input move. */
int semi_count = ei_status.priv - offset;
@@ -1541,7 +1541,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
info->base = NULL; link->win = NULL;
goto failed;
}
-
+
ei_status.mem = info->base + offset;
ei_status.priv = req.Size;
dev->mem_start = (u_long)ei_status.mem;
@@ -1639,6 +1639,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
@@ -1767,6 +1768,8 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "NE2K.cis"),
PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"),
PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "tamarack.cis"),
+ PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0",
+ 0xb4be14e3, 0x43ac239b, 0x0877b627),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 07c31f19c6ba..fc08c4af506c 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1774,8 +1774,6 @@ static int pcnet32_open(struct net_device *dev)
lp->rx_dma_addr[i] = 0;
}
- pcnet32_free_ring(dev);
-
/*
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index fa39b944bc46..cda3e53d6917 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -45,5 +45,11 @@ config CICADA_PHY
---help---
Currently supports the cis8204
+config SMSC_PHY
+ tristate "Drivers for SMSC PHYs"
+ depends on PHYLIB
+ ---help---
+ Currently supports the LAN83C185 PHY
+
endmenu
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e4116a5fbb4c..d9614134cc06 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+obj-$(CONFIG_SMSC_PHY) += smsc.o
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 459443b572ce..1b236bdf6b92 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -60,8 +60,10 @@ int mdiobus_register(struct mii_bus *bus)
for (i = 0; i < PHY_MAX_ADDR; i++) {
struct phy_device *phydev;
- if (bus->phy_mask & (1 << i))
+ if (bus->phy_mask & (1 << i)) {
+ bus->phy_map[i] = NULL;
continue;
+ }
phydev = get_phy_device(bus, i);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
new file mode 100644
index 000000000000..25e31fb5cb31
--- /dev/null
+++ b/drivers/net/phy/smsc.c
@@ -0,0 +1,101 @@
+/*
+ * drivers/net/phy/smsc.c
+ *
+ * Driver for SMSC PHYs
+ *
+ * Author: Herbert Valerio Riedel
+ *
+ * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+
+#define MII_LAN83C185_ISF 29 /* Interrupt Source Flags */
+#define MII_LAN83C185_IM 30 /* Interrupt Mask */
+
+#define MII_LAN83C185_ISF_INT1 (1<<1) /* Auto-Negotiation Page Received */
+#define MII_LAN83C185_ISF_INT2 (1<<2) /* Parallel Detection Fault */
+#define MII_LAN83C185_ISF_INT3 (1<<3) /* Auto-Negotiation LP Ack */
+#define MII_LAN83C185_ISF_INT4 (1<<4) /* Link Down */
+#define MII_LAN83C185_ISF_INT5 (1<<5) /* Remote Fault Detected */
+#define MII_LAN83C185_ISF_INT6 (1<<6) /* Auto-Negotiation complete */
+#define MII_LAN83C185_ISF_INT7 (1<<7) /* ENERGYON */
+
+#define MII_LAN83C185_ISF_INT_ALL (0x0e)
+
+#define MII_LAN83C185_ISF_INT_PHYLIB_EVENTS \
+ (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
+
+
+static int lan83c185_config_intr(struct phy_device *phydev)
+{
+ int rc = phy_write (phydev, MII_LAN83C185_IM,
+ ((PHY_INTERRUPT_ENABLED == phydev->interrupts)
+ ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
+ : 0));
+
+ return rc < 0 ? rc : 0;
+}
+
+static int lan83c185_ack_interrupt(struct phy_device *phydev)
+{
+ int rc = phy_read (phydev, MII_LAN83C185_ISF);
+
+ return rc < 0 ? rc : 0;
+}
+
+static int lan83c185_config_init(struct phy_device *phydev)
+{
+ return lan83c185_ack_interrupt (phydev);
+}
+
+
+static struct phy_driver lan83c185_driver = {
+ .phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN83C185",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = lan83c185_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = lan83c185_ack_interrupt,
+ .config_intr = lan83c185_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static int __init smsc_init(void)
+{
+ return phy_driver_register (&lan83c185_driver);
+}
+
+static void __exit smsc_exit(void)
+{
+ phy_driver_unregister (&lan83c185_driver);
+}
+
+MODULE_DESCRIPTION("SMSC PHY driver");
+MODULE_AUTHOR("Herbert Valerio Riedel");
+MODULE_LICENSE("GPL");
+
+module_init(smsc_init);
+module_exit(smsc_exit);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index b2073fce8216..01cd8ec751ea 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1609,8 +1609,6 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
kfree_skb(skb);
skb = ns;
}
- else if (!pskb_may_pull(skb, skb->len))
- goto err;
else
skb->ip_summed = CHECKSUM_NONE;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 475dc930380f..0d101a18026a 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -861,6 +861,9 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
* give dev_queue_xmit something it can free.
*/
skb2 = skb_clone(skb, GFP_ATOMIC);
+
+ if (skb2 == NULL)
+ goto abort;
}
ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 0ad3310290f1..9945cc6b8d90 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -184,6 +184,7 @@ static const struct {
static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), },
{ PCI_DEVICE(0x16ec, 0x0116), },
{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, },
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 00179bc3437f..0ef525899566 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -167,6 +167,7 @@ typedef struct _XENA_dev_config {
u8 unused4[0x08];
u64 gpio_int_reg;
+#define GPIO_INT_REG_DP_ERR_INT BIT(0)
#define GPIO_INT_REG_LINK_DOWN BIT(1)
#define GPIO_INT_REG_LINK_UP BIT(2)
u64 gpio_int_mask;
@@ -187,7 +188,7 @@ typedef struct _XENA_dev_config {
/* PIC Control registers */
u64 pic_control;
#define PIC_CNTL_RX_ALARM_MAP_1 BIT(0)
-#define PIC_CNTL_SHARED_SPLITS(n) vBIT(n,11,4)
+#define PIC_CNTL_SHARED_SPLITS(n) vBIT(n,11,5)
u64 swapper_ctrl;
#define SWAPPER_CTRL_PIF_R_FE BIT(0)
@@ -267,6 +268,21 @@ typedef struct _XENA_dev_config {
/* General Configuration */
u64 mdio_control;
+#define MDIO_MMD_INDX_ADDR(val) vBIT(val, 0, 16)
+#define MDIO_MMD_DEV_ADDR(val) vBIT(val, 19, 5)
+#define MDIO_MMD_PMA_DEV_ADDR 0x1
+#define MDIO_MMD_PMD_DEV_ADDR 0x1
+#define MDIO_MMD_WIS_DEV_ADDR 0x2
+#define MDIO_MMD_PCS_DEV_ADDR 0x3
+#define MDIO_MMD_PHYXS_DEV_ADDR 0x4
+#define MDIO_MMS_PRT_ADDR(val) vBIT(val, 27, 5)
+#define MDIO_CTRL_START_TRANS(val) vBIT(val, 56, 4)
+#define MDIO_OP(val) vBIT(val, 60, 2)
+#define MDIO_OP_ADDR_TRANS 0x0
+#define MDIO_OP_WRITE_TRANS 0x1
+#define MDIO_OP_READ_POST_INC_TRANS 0x2
+#define MDIO_OP_READ_TRANS 0x3
+#define MDIO_MDIO_DATA(val) vBIT(val, 32, 16)
u64 dtx_control;
@@ -284,9 +300,13 @@ typedef struct _XENA_dev_config {
u64 gpio_control;
#define GPIO_CTRL_GPIO_0 BIT(8)
u64 misc_control;
+#define EXT_REQ_EN BIT(1)
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
- u8 unused7_1[0x240 - 0x208];
+ u8 unused7_1[0x230 - 0x208];
+
+ u64 pic_control2;
+ u64 ini_dperr_ctrl;
u64 wreq_split_mask;
#define WREQ_SPLIT_MASK_SET_MASK(val) vBIT(val, 52, 12)
@@ -493,6 +513,7 @@ typedef struct _XENA_dev_config {
#define PRC_CTRL_NO_SNOOP_DESC BIT(22)
#define PRC_CTRL_NO_SNOOP_BUFF BIT(23)
#define PRC_CTRL_BIMODAL_INTERRUPT BIT(37)
+#define PRC_CTRL_GROUP_READS BIT(38)
#define PRC_CTRL_RXD_BACKOFF_INTERVAL(val) vBIT(val,40,24)
u64 prc_alarm_action;
@@ -541,7 +562,12 @@ typedef struct _XENA_dev_config {
#define RX_PA_CFG_IGNORE_LLC_CTRL BIT(3)
#define RX_PA_CFG_IGNORE_L2_ERR BIT(6)
- u8 unused12[0x700 - 0x1D8];
+ u64 unused_11_1;
+
+ u64 ring_bump_counter1;
+ u64 ring_bump_counter2;
+
+ u8 unused12[0x700 - 0x1F0];
u64 rxdma_debug_ctrl;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 79208f434ac1..cac9fdd2e1d5 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -26,15 +26,22 @@
*
* The module loadable parameters that are supported by the driver and a brief
* explaination of all the variables.
+ *
* rx_ring_num : This can be used to program the number of receive rings used
* in the driver.
- * rx_ring_sz: This defines the number of descriptors each ring can have. This
- * is also an array of size 8.
+ * rx_ring_sz: This defines the number of receive blocks each ring can have.
+ * This is also an array of size 8.
* rx_ring_mode: This defines the operation mode of all 8 rings. The valid
* values are 1, 2 and 3.
* tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
* tx_fifo_len: This too is an array of 8. Each element defines the number of
* Tx descriptors that can be associated with each corresponding FIFO.
+ * intr_type: This defines the type of interrupt. The values can be 0(INTA),
+ * 1(MSI), 2(MSI_X). Default value is '0(INTA)'
+ * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
+ * Possible values '1' for enable '0' for disable. Default is '0'
+ * lro_max_pkts: This parameter defines maximum number of packets can be
+ * aggregated as a single large packet
************************************************************************/
#include <linux/config.h>
@@ -70,7 +77,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.11.2"
+#define DRV_VERSION "2.0.14.2"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -106,18 +113,14 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp)
#define LOW 2
static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
{
- int level = 0;
mac_info_t *mac_control;
mac_control = &sp->mac_control;
- if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) {
- level = LOW;
- if (rxb_size <= rxd_count[sp->rxd_mode]) {
- level = PANIC;
- }
- }
-
- return level;
+ if (rxb_size <= rxd_count[sp->rxd_mode])
+ return PANIC;
+ else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16)
+ return LOW;
+ return 0;
}
/* Ethtool related variables and Macros. */
@@ -136,7 +139,11 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"tmac_mcst_frms"},
{"tmac_bcst_frms"},
{"tmac_pause_ctrl_frms"},
+ {"tmac_ttl_octets"},
+ {"tmac_ucst_frms"},
+ {"tmac_nucst_frms"},
{"tmac_any_err_frms"},
+ {"tmac_ttl_less_fb_octets"},
{"tmac_vld_ip_octets"},
{"tmac_vld_ip"},
{"tmac_drop_ip"},
@@ -151,13 +158,27 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"rmac_vld_mcst_frms"},
{"rmac_vld_bcst_frms"},
{"rmac_in_rng_len_err_frms"},
+ {"rmac_out_rng_len_err_frms"},
{"rmac_long_frms"},
{"rmac_pause_ctrl_frms"},
+ {"rmac_unsup_ctrl_frms"},
+ {"rmac_ttl_octets"},
+ {"rmac_accepted_ucst_frms"},
+ {"rmac_accepted_nucst_frms"},
{"rmac_discarded_frms"},
+ {"rmac_drop_events"},
+ {"rmac_ttl_less_fb_octets"},
+ {"rmac_ttl_frms"},
{"rmac_usized_frms"},
{"rmac_osized_frms"},
{"rmac_frag_frms"},
{"rmac_jabber_frms"},
+ {"rmac_ttl_64_frms"},
+ {"rmac_ttl_65_127_frms"},
+ {"rmac_ttl_128_255_frms"},
+ {"rmac_ttl_256_511_frms"},
+ {"rmac_ttl_512_1023_frms"},
+ {"rmac_ttl_1024_1518_frms"},
{"rmac_ip"},
{"rmac_ip_octets"},
{"rmac_hdr_err_ip"},
@@ -166,12 +187,82 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"rmac_tcp"},
{"rmac_udp"},
{"rmac_err_drp_udp"},
+ {"rmac_xgmii_err_sym"},
+ {"rmac_frms_q0"},
+ {"rmac_frms_q1"},
+ {"rmac_frms_q2"},
+ {"rmac_frms_q3"},
+ {"rmac_frms_q4"},
+ {"rmac_frms_q5"},
+ {"rmac_frms_q6"},
+ {"rmac_frms_q7"},
+ {"rmac_full_q0"},
+ {"rmac_full_q1"},
+ {"rmac_full_q2"},
+ {"rmac_full_q3"},
+ {"rmac_full_q4"},
+ {"rmac_full_q5"},
+ {"rmac_full_q6"},
+ {"rmac_full_q7"},
{"rmac_pause_cnt"},
+ {"rmac_xgmii_data_err_cnt"},
+ {"rmac_xgmii_ctrl_err_cnt"},
{"rmac_accepted_ip"},
{"rmac_err_tcp"},
+ {"rd_req_cnt"},
+ {"new_rd_req_cnt"},
+ {"new_rd_req_rtry_cnt"},
+ {"rd_rtry_cnt"},
+ {"wr_rtry_rd_ack_cnt"},
+ {"wr_req_cnt"},
+ {"new_wr_req_cnt"},
+ {"new_wr_req_rtry_cnt"},
+ {"wr_rtry_cnt"},
+ {"wr_disc_cnt"},
+ {"rd_rtry_wr_ack_cnt"},
+ {"txp_wr_cnt"},
+ {"txd_rd_cnt"},
+ {"txd_wr_cnt"},
+ {"rxd_rd_cnt"},
+ {"rxd_wr_cnt"},
+ {"txf_rd_cnt"},
+ {"rxf_wr_cnt"},
+ {"rmac_ttl_1519_4095_frms"},
+ {"rmac_ttl_4096_8191_frms"},
+ {"rmac_ttl_8192_max_frms"},
+ {"rmac_ttl_gt_max_frms"},
+ {"rmac_osized_alt_frms"},
+ {"rmac_jabber_alt_frms"},
+ {"rmac_gt_max_alt_frms"},
+ {"rmac_vlan_frms"},
+ {"rmac_len_discard"},
+ {"rmac_fcs_discard"},
+ {"rmac_pf_discard"},
+ {"rmac_da_discard"},
+ {"rmac_red_discard"},
+ {"rmac_rts_discard"},
+ {"rmac_ingm_full_discard"},
+ {"link_fault_cnt"},
{"\n DRIVER STATISTICS"},
{"single_bit_ecc_errs"},
{"double_bit_ecc_errs"},
+ {"parity_err_cnt"},
+ {"serious_err_cnt"},
+ {"soft_reset_cnt"},
+ {"fifo_full_cnt"},
+ {"ring_full_cnt"},
+ ("alarm_transceiver_temp_high"),
+ ("alarm_transceiver_temp_low"),
+ ("alarm_laser_bias_current_high"),
+ ("alarm_laser_bias_current_low"),
+ ("alarm_laser_output_power_high"),
+ ("alarm_laser_output_power_low"),
+ ("warn_transceiver_temp_high"),
+ ("warn_transceiver_temp_low"),
+ ("warn_laser_bias_current_high"),
+ ("warn_laser_bias_current_low"),
+ ("warn_laser_output_power_high"),
+ ("warn_laser_output_power_low"),
("lro_aggregated_pkts"),
("lro_flush_both_count"),
("lro_out_of_sequence_pkts"),
@@ -220,9 +311,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
* the XAUI.
*/
-#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL
#define END_SIGN 0x0
-
static const u64 herc_act_dtx_cfg[] = {
/* Set address */
0x8000051536750000ULL, 0x80000515367500E0ULL,
@@ -244,37 +333,19 @@ static const u64 herc_act_dtx_cfg[] = {
END_SIGN
};
-static const u64 xena_mdio_cfg[] = {
- /* Reset PMA PLL */
- 0xC001010000000000ULL, 0xC0010100000000E0ULL,
- 0xC0010100008000E4ULL,
- /* Remove Reset from PMA PLL */
- 0xC001010000000000ULL, 0xC0010100000000E0ULL,
- 0xC0010100000000E4ULL,
- END_SIGN
-};
-
static const u64 xena_dtx_cfg[] = {
+ /* Set address */
0x8000051500000000ULL, 0x80000515000000E0ULL,
- 0x80000515D93500E4ULL, 0x8001051500000000ULL,
- 0x80010515000000E0ULL, 0x80010515001E00E4ULL,
- 0x8002051500000000ULL, 0x80020515000000E0ULL,
- 0x80020515F21000E4ULL,
- /* Set PADLOOPBACKN */
- 0x8002051500000000ULL, 0x80020515000000E0ULL,
- 0x80020515B20000E4ULL, 0x8003051500000000ULL,
- 0x80030515000000E0ULL, 0x80030515B20000E4ULL,
- 0x8004051500000000ULL, 0x80040515000000E0ULL,
- 0x80040515B20000E4ULL, 0x8005051500000000ULL,
- 0x80050515000000E0ULL, 0x80050515B20000E4ULL,
- SWITCH_SIGN,
- /* Remove PADLOOPBACKN */
+ /* Write data */
+ 0x80000515D9350004ULL, 0x80000515D93500E4ULL,
+ /* Set address */
+ 0x8001051500000000ULL, 0x80010515000000E0ULL,
+ /* Write data */
+ 0x80010515001E0004ULL, 0x80010515001E00E4ULL,
+ /* Set address */
0x8002051500000000ULL, 0x80020515000000E0ULL,
- 0x80020515F20000E4ULL, 0x8003051500000000ULL,
- 0x80030515000000E0ULL, 0x80030515F20000E4ULL,
- 0x8004051500000000ULL, 0x80040515000000E0ULL,
- 0x80040515F20000E4ULL, 0x8005051500000000ULL,
- 0x80050515000000E0ULL, 0x80050515F20000E4ULL,
+ /* Write data */
+ 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
END_SIGN
};
@@ -303,15 +374,15 @@ static const u64 fix_mac[] = {
/* Module Loadable parameters. */
static unsigned int tx_fifo_num = 1;
static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
- {[0 ...(MAX_TX_FIFOS - 1)] = 0 };
+ {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
static unsigned int rx_ring_num = 1;
static unsigned int rx_ring_sz[MAX_RX_RINGS] =
- {[0 ...(MAX_RX_RINGS - 1)] = 0 };
+ {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
static unsigned int rts_frm_len[MAX_RX_RINGS] =
{[0 ...(MAX_RX_RINGS - 1)] = 0 };
static unsigned int rx_ring_mode = 1;
static unsigned int use_continuous_tx_intrs = 1;
-static unsigned int rmac_pause_time = 65535;
+static unsigned int rmac_pause_time = 0x100;
static unsigned int mc_pause_threshold_q0q3 = 187;
static unsigned int mc_pause_threshold_q4q7 = 187;
static unsigned int shared_splits;
@@ -549,11 +620,6 @@ static int init_shared_mem(struct s2io_nic *nic)
rx_blocks->block_dma_addr +
(rxd_size[nic->rxd_mode] * l);
}
-
- mac_control->rings[i].rx_blocks[j].block_virt_addr =
- tmp_v_addr;
- mac_control->rings[i].rx_blocks[j].block_dma_addr =
- tmp_p_addr;
}
/* Interlinking all Rx Blocks */
for (j = 0; j < blk_cnt; j++) {
@@ -772,7 +838,21 @@ static int s2io_verify_pci_mode(nic_t *nic)
return mode;
}
+#define NEC_VENID 0x1033
+#define NEC_DEVID 0x0125
+static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
+{
+ struct pci_dev *tdev = NULL;
+ while ((tdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
+ if ((tdev->vendor == NEC_VENID) && (tdev->device == NEC_DEVID)){
+ if (tdev->bus == s2io_pdev->bus->parent)
+ return 1;
+ }
+ }
+ return 0;
+}
+static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
/**
* s2io_print_pci_mode -
*/
@@ -789,6 +869,14 @@ static int s2io_print_pci_mode(nic_t *nic)
if ( val64 & PCI_MODE_UNKNOWN_MODE)
return -1; /* Unknown PCI mode */
+ config->bus_speed = bus_speed[mode];
+
+ if (s2io_on_nec_bridge(nic->pdev)) {
+ DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
+ nic->dev->name);
+ return mode;
+ }
+
if (val64 & PCI_MODE_32_BITS) {
DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name);
} else {
@@ -798,35 +886,27 @@ static int s2io_print_pci_mode(nic_t *nic)
switch(mode) {
case PCI_MODE_PCI_33:
DBG_PRINT(ERR_DBG, "33MHz PCI bus\n");
- config->bus_speed = 33;
break;
case PCI_MODE_PCI_66:
DBG_PRINT(ERR_DBG, "66MHz PCI bus\n");
- config->bus_speed = 133;
break;
case PCI_MODE_PCIX_M1_66:
DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n");
- config->bus_speed = 133; /* Herc doubles the clock rate */
break;
case PCI_MODE_PCIX_M1_100:
DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n");
- config->bus_speed = 200;
break;
case PCI_MODE_PCIX_M1_133:
DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n");
- config->bus_speed = 266;
break;
case PCI_MODE_PCIX_M2_66:
DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n");
- config->bus_speed = 133;
break;
case PCI_MODE_PCIX_M2_100:
DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n");
- config->bus_speed = 200;
break;
case PCI_MODE_PCIX_M2_133:
DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n");
- config->bus_speed = 266;
break;
default:
return -1; /* Unsupported bus speed */
@@ -854,7 +934,7 @@ static int init_nic(struct s2io_nic *nic)
int i, j;
mac_info_t *mac_control;
struct config_param *config;
- int mdio_cnt = 0, dtx_cnt = 0;
+ int dtx_cnt = 0;
unsigned long long mem_share;
int mem_size;
@@ -901,20 +981,6 @@ static int init_nic(struct s2io_nic *nic)
val64 = dev->mtu;
writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
- /*
- * Configuring the XAUI Interface of Xena.
- * ***************************************
- * To Configure the Xena's XAUI, one has to write a series
- * of 64 bit values into two registers in a particular
- * sequence. Hence a macro 'SWITCH_SIGN' has been defined
- * which will be defined in the array of configuration values
- * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places
- * to switch writing from one regsiter to another. We continue
- * writing these values until we encounter the 'END_SIGN' macro.
- * For example, After making a series of 21 writes into
- * dtx_control register the 'SWITCH_SIGN' appears and hence we
- * start writing into mdio_control until we encounter END_SIGN.
- */
if (nic->device_type & XFRAME_II_DEVICE) {
while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
@@ -924,35 +990,11 @@ static int init_nic(struct s2io_nic *nic)
dtx_cnt++;
}
} else {
- while (1) {
- dtx_cfg:
- while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
- if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
- dtx_cnt++;
- goto mdio_cfg;
- }
- SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
- &bar0->dtx_control, UF);
- val64 = readq(&bar0->dtx_control);
- dtx_cnt++;
- }
- mdio_cfg:
- while (xena_mdio_cfg[mdio_cnt] != END_SIGN) {
- if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
- mdio_cnt++;
- goto dtx_cfg;
- }
- SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt],
- &bar0->mdio_control, UF);
- val64 = readq(&bar0->mdio_control);
- mdio_cnt++;
- }
- if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) &&
- (xena_mdio_cfg[mdio_cnt] == END_SIGN)) {
- break;
- } else {
- goto dtx_cfg;
- }
+ while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
+ SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
+ &bar0->dtx_control, UF);
+ val64 = readq(&bar0->dtx_control);
+ dtx_cnt++;
}
}
@@ -994,11 +1036,6 @@ static int init_nic(struct s2io_nic *nic)
}
}
- /* Enable Tx FIFO partition 0. */
- val64 = readq(&bar0->tx_fifo_partition_0);
- val64 |= BIT(0); /* To enable the FIFO partition. */
- writeq(val64, &bar0->tx_fifo_partition_0);
-
/*
* Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
* SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
@@ -1177,6 +1214,11 @@ static int init_nic(struct s2io_nic *nic)
break;
}
+ /* Enable Tx FIFO partition 0. */
+ val64 = readq(&bar0->tx_fifo_partition_0);
+ val64 |= (TX_FIFO_PARTITION_EN);
+ writeq(val64, &bar0->tx_fifo_partition_0);
+
/* Filling the Rx round robin registers as per the
* number of Rings and steering based on QoS.
*/
@@ -1545,19 +1587,26 @@ static int init_nic(struct s2io_nic *nic)
val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
writeq(val64, &bar0->pic_control);
+ if (nic->config.bus_speed == 266) {
+ writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
+ writeq(0x0, &bar0->read_retry_delay);
+ writeq(0x0, &bar0->write_retry_delay);
+ }
+
/*
* Programming the Herc to split every write transaction
* that does not start on an ADB to reduce disconnects.
*/
if (nic->device_type == XFRAME_II_DEVICE) {
- val64 = WREQ_SPLIT_MASK_SET_MASK(255);
- writeq(val64, &bar0->wreq_split_mask);
- }
-
- /* Setting Link stability period to 64 ms */
- if (nic->device_type == XFRAME_II_DEVICE) {
- val64 = MISC_LINK_STABILITY_PRD(3);
+ val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
+ val64 = readq(&bar0->pic_control2);
+ val64 &= ~(BIT(13)|BIT(14)|BIT(15));
+ writeq(val64, &bar0->pic_control2);
+ }
+ if (strstr(nic->product_name, "CX4")) {
+ val64 = TMAC_AVG_IPG(0x17);
+ writeq(val64, &bar0->tmac_avg_ipg);
}
return SUCCESS;
@@ -1948,6 +1997,10 @@ static int start_nic(struct s2io_nic *nic)
val64 |= PRC_CTRL_RC_ENABLED;
else
val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
+ if (nic->device_type == XFRAME_II_DEVICE)
+ val64 |= PRC_CTRL_GROUP_READS;
+ val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
+ val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
writeq(val64, &bar0->prc_ctrl_n[i]);
}
@@ -2018,6 +2071,13 @@ static int start_nic(struct s2io_nic *nic)
val64 |= ADAPTER_EOI_TX_ON;
writeq(val64, &bar0->adapter_control);
+ if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
+ /*
+ * Dont see link state interrupts initally on some switches,
+ * so directly scheduling the link state task here.
+ */
+ schedule_work(&nic->set_link_task);
+ }
/* SXE-002: Initialize link and activity LED */
subid = nic->pdev->subsystem_device;
if (((subid & 0xFF) >= 0x07) &&
@@ -2029,12 +2089,6 @@ static int start_nic(struct s2io_nic *nic)
writeq(val64, (void __iomem *)bar0 + 0x2700);
}
- /*
- * Don't see link state interrupts on certain switches, so
- * directly scheduling a link state task from here.
- */
- schedule_work(&nic->set_link_task);
-
return SUCCESS;
}
/**
@@ -2134,7 +2188,7 @@ static void stop_nic(struct s2io_nic *nic)
{
XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
- u16 interruptible, i;
+ u16 interruptible;
mac_info_t *mac_control;
struct config_param *config;
@@ -2147,12 +2201,10 @@ static void stop_nic(struct s2io_nic *nic)
interruptible |= TX_MAC_INTR | RX_MAC_INTR;
en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
- /* Disable PRCs */
- for (i = 0; i < config->rx_ring_num; i++) {
- val64 = readq(&bar0->prc_ctrl_n[i]);
- val64 &= ~((u64) PRC_CTRL_RC_ENABLED);
- writeq(val64, &bar0->prc_ctrl_n[i]);
- }
+ /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
+ val64 = readq(&bar0->adapter_control);
+ val64 &= ~(ADAPTER_CNTL_EN);
+ writeq(val64, &bar0->adapter_control);
}
static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
@@ -2231,13 +2283,12 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
atomic_read(&nic->rx_bufs_left[ring_no]);
+ block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
+ off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
while (alloc_tab < alloc_cnt) {
block_no = mac_control->rings[ring_no].rx_curr_put_info.
block_index;
- block_no1 = mac_control->rings[ring_no].rx_curr_get_info.
- block_index;
off = mac_control->rings[ring_no].rx_curr_put_info.offset;
- off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
rxdp = mac_control->rings[ring_no].
rx_blocks[block_no].rxds[off].virt_addr;
@@ -2307,9 +2358,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
memset(rxdp, 0, sizeof(RxD1_t));
skb_reserve(skb, NET_IP_ALIGN);
((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
- (nic->pdev, skb->data, size, PCI_DMA_FROMDEVICE);
- rxdp->Control_2 &= (~MASK_BUFFER0_SIZE_1);
- rxdp->Control_2 |= SET_BUFFER0_SIZE_1(size);
+ (nic->pdev, skb->data, size - NET_IP_ALIGN,
+ PCI_DMA_FROMDEVICE);
+ rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
} else if (nic->rxd_mode >= RXD_MODE_3A) {
/*
@@ -2516,7 +2567,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
mac_info_t *mac_control;
struct config_param *config;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64;
+ u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
atomic_inc(&nic->isr_cnt);
@@ -2528,8 +2579,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
nic->pkts_to_process = dev->quota;
org_pkts_to_process = nic->pkts_to_process;
- val64 = readq(&bar0->rx_traffic_int);
writeq(val64, &bar0->rx_traffic_int);
+ val64 = readl(&bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) {
rx_intr_handler(&mac_control->rings[i]);
@@ -2554,7 +2605,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
}
}
/* Re enable the Rx interrupts. */
- en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS);
+ writeq(0x0, &bar0->rx_traffic_mask);
+ val64 = readl(&bar0->rx_traffic_mask);
atomic_dec(&nic->isr_cnt);
return 0;
@@ -2666,6 +2718,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
((RxD3_t*)rxdp)->Buffer2_ptr,
dev->mtu, PCI_DMA_FROMDEVICE);
}
+ prefetch(skb->data);
rx_osm_handler(ring_data, rxdp);
get_info.offset++;
ring_data->rx_curr_get_info.offset = get_info.offset;
@@ -2737,6 +2790,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
if (txdlp->Control_1 & TXD_T_CODE) {
unsigned long long err;
err = txdlp->Control_1 & TXD_T_CODE;
+ if (err & 0x1) {
+ nic->mac_control.stats_info->sw_stat.
+ parity_err_cnt++;
+ }
if ((err >> 48) == 0xA) {
DBG_PRINT(TX_DBG, "TxD returned due \
to loss of link\n");
@@ -2760,7 +2817,8 @@ to loss of link\n");
dev_kfree_skb_irq(skb);
get_info.offset++;
- get_info.offset %= get_info.fifo_len + 1;
+ if (get_info.offset == get_info.fifo_len + 1)
+ get_info.offset = 0;
txdlp = (TxD_t *) fifo_data->list_info
[get_info.offset].list_virt_addr;
fifo_data->tx_curr_get_info.offset =
@@ -2774,6 +2832,256 @@ to loss of link\n");
}
/**
+ * s2io_mdio_write - Function to write in to MDIO registers
+ * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
+ * @addr : address value
+ * @value : data value
+ * @dev : pointer to net_device structure
+ * Description:
+ * This function is used to write values to the MDIO registers
+ * NONE
+ */
+static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
+{
+ u64 val64 = 0x0;
+ nic_t *sp = dev->priv;
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+
+ //address transaction
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+ | MDIO_MMD_DEV_ADDR(mmd_type)
+ | MDIO_MMS_PRT_ADDR(0x0);
+ writeq(val64, &bar0->mdio_control);
+ val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
+ writeq(val64, &bar0->mdio_control);
+ udelay(100);
+
+ //Data transaction
+ val64 = 0x0;
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+ | MDIO_MMD_DEV_ADDR(mmd_type)
+ | MDIO_MMS_PRT_ADDR(0x0)
+ | MDIO_MDIO_DATA(value)
+ | MDIO_OP(MDIO_OP_WRITE_TRANS);
+ writeq(val64, &bar0->mdio_control);
+ val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
+ writeq(val64, &bar0->mdio_control);
+ udelay(100);
+
+ val64 = 0x0;
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+ | MDIO_MMD_DEV_ADDR(mmd_type)
+ | MDIO_MMS_PRT_ADDR(0x0)
+ | MDIO_OP(MDIO_OP_READ_TRANS);
+ writeq(val64, &bar0->mdio_control);
+ val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
+ writeq(val64, &bar0->mdio_control);
+ udelay(100);
+
+}
+
+/**
+ * s2io_mdio_read - Function to write in to MDIO registers
+ * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS)
+ * @addr : address value
+ * @dev : pointer to net_device structure
+ * Description:
+ * This function is used to read values to the MDIO registers
+ * NONE
+ */
+static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
+{
+ u64 val64 = 0x0;
+ u64 rval64 = 0x0;
+ nic_t *sp = dev->priv;
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+
+ /* address transaction */
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+ | MDIO_MMD_DEV_ADDR(mmd_type)
+ | MDIO_MMS_PRT_ADDR(0x0);
+ writeq(val64, &bar0->mdio_control);
+ val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
+ writeq(val64, &bar0->mdio_control);
+ udelay(100);
+
+ /* Data transaction */
+ val64 = 0x0;
+ val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
+ | MDIO_MMD_DEV_ADDR(mmd_type)
+ | MDIO_MMS_PRT_ADDR(0x0)
+ | MDIO_OP(MDIO_OP_READ_TRANS);
+ writeq(val64, &bar0->mdio_control);
+ val64 = val64 | MDIO_CTRL_START_TRANS(0xE);
+ writeq(val64, &bar0->mdio_control);
+ udelay(100);
+
+ /* Read the value from regs */
+ rval64 = readq(&bar0->mdio_control);
+ rval64 = rval64 & 0xFFFF0000;
+ rval64 = rval64 >> 16;
+ return rval64;
+}
+/**
+ * s2io_chk_xpak_counter - Function to check the status of the xpak counters
+ * @counter : couter value to be updated
+ * @flag : flag to indicate the status
+ * @type : counter type
+ * Description:
+ * This function is to check the status of the xpak counters value
+ * NONE
+ */
+
+static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type)
+{
+ u64 mask = 0x3;
+ u64 val64;
+ int i;
+ for(i = 0; i <index; i++)
+ mask = mask << 0x2;
+
+ if(flag > 0)
+ {
+ *counter = *counter + 1;
+ val64 = *regs_stat & mask;
+ val64 = val64 >> (index * 0x2);
+ val64 = val64 + 1;
+ if(val64 == 3)
+ {
+ switch(type)
+ {
+ case 1:
+ DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
+ "service. Excessive temperatures may "
+ "result in premature transceiver "
+ "failure \n");
+ break;
+ case 2:
+ DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
+ "service Excessive bias currents may "
+ "indicate imminent laser diode "
+ "failure \n");
+ break;
+ case 3:
+ DBG_PRINT(ERR_DBG, "Take Xframe NIC out of "
+ "service Excessive laser output "
+ "power may saturate far-end "
+ "receiver\n");
+ break;
+ default:
+ DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm "
+ "type \n");
+ }
+ val64 = 0x0;
+ }
+ val64 = val64 << (index * 0x2);
+ *regs_stat = (*regs_stat & (~mask)) | (val64);
+
+ } else {
+ *regs_stat = *regs_stat & (~mask);
+ }
+}
+
+/**
+ * s2io_updt_xpak_counter - Function to update the xpak counters
+ * @dev : pointer to net_device struct
+ * Description:
+ * This function is to upate the status of the xpak counters value
+ * NONE
+ */
+static void s2io_updt_xpak_counter(struct net_device *dev)
+{
+ u16 flag = 0x0;
+ u16 type = 0x0;
+ u16 val16 = 0x0;
+ u64 val64 = 0x0;
+ u64 addr = 0x0;
+
+ nic_t *sp = dev->priv;
+ StatInfo_t *stat_info = sp->mac_control.stats_info;
+
+ /* Check the communication with the MDIO slave */
+ addr = 0x0000;
+ val64 = 0x0;
+ val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
+ if((val64 == 0xFFFF) || (val64 == 0x0000))
+ {
+ DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - "
+ "Returned %llx\n", (unsigned long long)val64);
+ return;
+ }
+
+ /* Check for the expecte value of 2040 at PMA address 0x0000 */
+ if(val64 != 0x2040)
+ {
+ DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - ");
+ DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n",
+ (unsigned long long)val64);
+ return;
+ }
+
+ /* Loading the DOM register to MDIO register */
+ addr = 0xA100;
+ s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev);
+ val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
+
+ /* Reading the Alarm flags */
+ addr = 0xA070;
+ val64 = 0x0;
+ val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
+
+ flag = CHECKBIT(val64, 0x7);
+ type = 1;
+ s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high,
+ &stat_info->xpak_stat.xpak_regs_stat,
+ 0x0, flag, type);
+
+ if(CHECKBIT(val64, 0x6))
+ stat_info->xpak_stat.alarm_transceiver_temp_low++;
+
+ flag = CHECKBIT(val64, 0x3);
+ type = 2;
+ s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high,
+ &stat_info->xpak_stat.xpak_regs_stat,
+ 0x2, flag, type);
+
+ if(CHECKBIT(val64, 0x2))
+ stat_info->xpak_stat.alarm_laser_bias_current_low++;
+
+ flag = CHECKBIT(val64, 0x1);
+ type = 3;
+ s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high,
+ &stat_info->xpak_stat.xpak_regs_stat,
+ 0x4, flag, type);
+
+ if(CHECKBIT(val64, 0x0))
+ stat_info->xpak_stat.alarm_laser_output_power_low++;
+
+ /* Reading the Warning flags */
+ addr = 0xA074;
+ val64 = 0x0;
+ val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev);
+
+ if(CHECKBIT(val64, 0x7))
+ stat_info->xpak_stat.warn_transceiver_temp_high++;
+
+ if(CHECKBIT(val64, 0x6))
+ stat_info->xpak_stat.warn_transceiver_temp_low++;
+
+ if(CHECKBIT(val64, 0x3))
+ stat_info->xpak_stat.warn_laser_bias_current_high++;
+
+ if(CHECKBIT(val64, 0x2))
+ stat_info->xpak_stat.warn_laser_bias_current_low++;
+
+ if(CHECKBIT(val64, 0x1))
+ stat_info->xpak_stat.warn_laser_output_power_high++;
+
+ if(CHECKBIT(val64, 0x0))
+ stat_info->xpak_stat.warn_laser_output_power_low++;
+}
+
+/**
* alarm_intr_handler - Alarm Interrrupt handler
* @nic: device private variable
* Description: If the interrupt was neither because of Rx packet or Tx
@@ -2790,6 +3098,18 @@ static void alarm_intr_handler(struct s2io_nic *nic)
struct net_device *dev = (struct net_device *) nic->dev;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
register u64 val64 = 0, err_reg = 0;
+ u64 cnt;
+ int i;
+ nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
+ /* Handling the XPAK counters update */
+ if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
+ /* waiting for an hour */
+ nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
+ } else {
+ s2io_updt_xpak_counter(dev);
+ /* reset the count to zero */
+ nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
+ }
/* Handling link status change error Intr */
if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
@@ -2816,6 +3136,8 @@ static void alarm_intr_handler(struct s2io_nic *nic)
MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
netif_stop_queue(dev);
schedule_work(&nic->rst_timer_task);
+ nic->mac_control.stats_info->sw_stat.
+ soft_reset_cnt++;
}
}
} else {
@@ -2827,11 +3149,13 @@ static void alarm_intr_handler(struct s2io_nic *nic)
/* In case of a serious error, the device will be Reset. */
val64 = readq(&bar0->serr_source);
if (val64 & SERR_SOURCE_ANY) {
+ nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
(unsigned long long)val64);
netif_stop_queue(dev);
schedule_work(&nic->rst_timer_task);
+ nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
}
/*
@@ -2849,6 +3173,35 @@ static void alarm_intr_handler(struct s2io_nic *nic)
ac = readq(&bar0->adapter_control);
schedule_work(&nic->set_link_task);
}
+ /* Check for data parity error */
+ val64 = readq(&bar0->pic_int_status);
+ if (val64 & PIC_INT_GPIO) {
+ val64 = readq(&bar0->gpio_int_reg);
+ if (val64 & GPIO_INT_REG_DP_ERR_INT) {
+ nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
+ schedule_work(&nic->rst_timer_task);
+ nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
+ }
+ }
+
+ /* Check for ring full counter */
+ if (nic->device_type & XFRAME_II_DEVICE) {
+ val64 = readq(&bar0->ring_bump_counter1);
+ for (i=0; i<4; i++) {
+ cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
+ cnt >>= 64 - ((i+1)*16);
+ nic->mac_control.stats_info->sw_stat.ring_full_cnt
+ += cnt;
+ }
+
+ val64 = readq(&bar0->ring_bump_counter2);
+ for (i=0; i<4; i++) {
+ cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
+ cnt >>= 64 - ((i+1)*16);
+ nic->mac_control.stats_info->sw_stat.ring_full_cnt
+ += cnt;
+ }
+ }
/* Other type of interrupts are not being handled now, TODO */
}
@@ -2864,23 +3217,26 @@ static void alarm_intr_handler(struct s2io_nic *nic)
* SUCCESS on success and FAILURE on failure.
*/
-static int wait_for_cmd_complete(nic_t * sp)
+static int wait_for_cmd_complete(void *addr, u64 busy_bit)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
int ret = FAILURE, cnt = 0;
u64 val64;
while (TRUE) {
- val64 = readq(&bar0->rmac_addr_cmd_mem);
- if (!(val64 & RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
+ val64 = readq(addr);
+ if (!(val64 & busy_bit)) {
ret = SUCCESS;
break;
}
- msleep(50);
+
+ if(in_interrupt())
+ mdelay(50);
+ else
+ msleep(50);
+
if (cnt++ > 10)
break;
}
-
return ret;
}
@@ -2919,6 +3275,9 @@ static void s2io_reset(nic_t * sp)
* PCI write to sw_reset register is done by this time.
*/
msleep(250);
+ if (strstr(sp->product_name, "CX4")) {
+ msleep(750);
+ }
/* Restore the PCI state saved during initialization. */
pci_restore_state(sp->pdev);
@@ -3137,7 +3496,7 @@ static void restore_xmsi_data(nic_t *nic)
u64 val64;
int i;
- for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
+ for (i=0; i< nic->avail_msix_vectors; i++) {
writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
@@ -3156,7 +3515,7 @@ static void store_xmsi_data(nic_t *nic)
int i;
/* Store and display */
- for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
+ for (i=0; i< nic->avail_msix_vectors; i++) {
val64 = (BIT(15) | vBIT(i, 26, 6));
writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) {
@@ -3284,15 +3643,24 @@ static int s2io_enable_msi_x(nic_t *nic)
writeq(tx_mat, &bar0->tx_mat0_n[7]);
}
+ nic->avail_msix_vectors = 0;
ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
+ /* We fail init if error or we get less vectors than min required */
+ if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
+ nic->avail_msix_vectors = ret;
+ ret = pci_enable_msix(nic->pdev, nic->entries, ret);
+ }
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries);
kfree(nic->s2io_entries);
nic->entries = NULL;
nic->s2io_entries = NULL;
+ nic->avail_msix_vectors = 0;
return -ENOMEM;
}
+ if (!nic->avail_msix_vectors)
+ nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
/*
* To enable MSI-X, MSI also needs to be enabled, due to a bug
@@ -3325,8 +3693,6 @@ static int s2io_open(struct net_device *dev)
{
nic_t *sp = dev->priv;
int err = 0;
- int i;
- u16 msi_control; /* Temp variable */
/*
* Make sure you have link off by default every time
@@ -3336,11 +3702,14 @@ static int s2io_open(struct net_device *dev)
sp->last_link_state = 0;
/* Initialize H/W and enable interrupts */
- if (s2io_card_up(sp)) {
+ err = s2io_card_up(sp);
+ if (err) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name);
- err = -ENODEV;
- goto hw_init_failed;
+ if (err == -ENODEV)
+ goto hw_init_failed;
+ else
+ goto hw_enable_failed;
}
/* Store the values of the MSIX table in the nic_t structure */
@@ -3357,6 +3726,8 @@ failed\n", dev->name);
}
}
if (sp->intr_type == MSI_X) {
+ int i;
+
for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
sprintf(sp->desc1, "%s:MSI-X-%d-TX",
@@ -3409,24 +3780,26 @@ setting_mac_address_failed:
isr_registration_failed:
del_timer_sync(&sp->alarm_timer);
if (sp->intr_type == MSI_X) {
- if (sp->device_type == XFRAME_II_DEVICE) {
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
+ int i;
+ u16 msi_control; /* Temp variable */
- free_irq(vector, arg);
- }
- pci_disable_msix(sp->pdev);
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
- /* Temp */
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
+ free_irq(vector, arg);
}
+ pci_disable_msix(sp->pdev);
+
+ /* Temp */
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
}
else if (sp->intr_type == MSI)
pci_disable_msi(sp->pdev);
+hw_enable_failed:
s2io_reset(sp);
hw_init_failed:
if (sp->intr_type == MSI_X) {
@@ -3454,35 +3827,12 @@ hw_init_failed:
static int s2io_close(struct net_device *dev)
{
nic_t *sp = dev->priv;
- int i;
- u16 msi_control;
flush_scheduled_work();
netif_stop_queue(dev);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
- s2io_card_down(sp);
-
- if (sp->intr_type == MSI_X) {
- if (sp->device_type == XFRAME_II_DEVICE) {
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
+ s2io_card_down(sp, 1);
- free_irq(vector, arg);
- }
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
-
- pci_disable_msix(sp->pdev);
- }
- }
- else {
- free_irq(sp->pdev->irq, dev);
- if (sp->intr_type == MSI)
- pci_disable_msi(sp->pdev);
- }
sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
}
@@ -3545,7 +3895,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
/* Avoid "put" pointer going beyond "get" pointer */
- if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
+ if (txdp->Host_Control ||
+ ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
netif_stop_queue(dev);
dev_kfree_skb(skb);
@@ -3655,11 +4006,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
mmiowb();
put_off++;
- put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
+ if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
+ put_off = 0;
mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
/* Avoid "put" pointer going beyond "get" pointer */
- if (((put_off + 1) % queue_len) == get_off) {
+ if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
+ sp->mac_control.stats_info->sw_stat.fifo_full_cnt++;
DBG_PRINT(TX_DBG,
"No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
put_off, get_off);
@@ -3795,7 +4148,6 @@ s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
-
static void s2io_txpic_intr_handle(nic_t *sp)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -3806,41 +4158,56 @@ static void s2io_txpic_intr_handle(nic_t *sp)
val64 = readq(&bar0->gpio_int_reg);
if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
(val64 & GPIO_INT_REG_LINK_UP)) {
+ /*
+ * This is unstable state so clear both up/down
+ * interrupt and adapter to re-evaluate the link state.
+ */
val64 |= GPIO_INT_REG_LINK_DOWN;
val64 |= GPIO_INT_REG_LINK_UP;
writeq(val64, &bar0->gpio_int_reg);
- goto masking;
- }
-
- if (((sp->last_link_state == LINK_UP) &&
- (val64 & GPIO_INT_REG_LINK_DOWN)) ||
- ((sp->last_link_state == LINK_DOWN) &&
- (val64 & GPIO_INT_REG_LINK_UP))) {
val64 = readq(&bar0->gpio_int_mask);
- val64 |= GPIO_INT_MASK_LINK_DOWN;
- val64 |= GPIO_INT_MASK_LINK_UP;
+ val64 &= ~(GPIO_INT_MASK_LINK_UP |
+ GPIO_INT_MASK_LINK_DOWN);
writeq(val64, &bar0->gpio_int_mask);
- s2io_set_link((unsigned long)sp);
}
-masking:
- if (sp->last_link_state == LINK_UP) {
- /*enable down interrupt */
- val64 = readq(&bar0->gpio_int_mask);
- /* unmasks link down intr */
- val64 &= ~GPIO_INT_MASK_LINK_DOWN;
- /* masks link up intr */
- val64 |= GPIO_INT_MASK_LINK_UP;
- writeq(val64, &bar0->gpio_int_mask);
- } else {
- /*enable UP Interrupt */
- val64 = readq(&bar0->gpio_int_mask);
- /* unmasks link up interrupt */
- val64 &= ~GPIO_INT_MASK_LINK_UP;
- /* masks link down interrupt */
- val64 |= GPIO_INT_MASK_LINK_DOWN;
- writeq(val64, &bar0->gpio_int_mask);
+ else if (val64 & GPIO_INT_REG_LINK_UP) {
+ val64 = readq(&bar0->adapter_status);
+ if (verify_xena_quiescence(sp, val64,
+ sp->device_enabled_once)) {
+ /* Enable Adapter */
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
+ writeq(val64, &bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ if (!sp->device_enabled_once)
+ sp->device_enabled_once = 1;
+
+ s2io_link(sp, LINK_UP);
+ /*
+ * unmask link down interrupt and mask link-up
+ * intr
+ */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+ val64 |= GPIO_INT_MASK_LINK_UP;
+ writeq(val64, &bar0->gpio_int_mask);
+
+ }
+ }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
+ val64 = readq(&bar0->adapter_status);
+ if (verify_xena_quiescence(sp, val64,
+ sp->device_enabled_once)) {
+ s2io_link(sp, LINK_DOWN);
+ /* Link is down so unmaks link up interrupt */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_UP;
+ val64 |= GPIO_INT_MASK_LINK_DOWN;
+ writeq(val64, &bar0->gpio_int_mask);
+ }
}
}
+ val64 = readq(&bar0->gpio_int_mask);
}
/**
@@ -3863,7 +4230,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
nic_t *sp = dev->priv;
XENA_dev_config_t __iomem *bar0 = sp->bar0;
int i;
- u64 reason = 0, val64;
+ u64 reason = 0, val64, org_mask;
mac_info_t *mac_control;
struct config_param *config;
@@ -3887,43 +4254,41 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE;
}
+ val64 = 0xFFFFFFFFFFFFFFFFULL;
+ /* Store current mask before masking all interrupts */
+ org_mask = readq(&bar0->general_int_mask);
+ writeq(val64, &bar0->general_int_mask);
+
#ifdef CONFIG_S2IO_NAPI
if (reason & GEN_INTR_RXTRAFFIC) {
if (netif_rx_schedule_prep(dev)) {
- en_dis_able_nic_intrs(sp, RX_TRAFFIC_INTR,
- DISABLE_INTRS);
+ writeq(val64, &bar0->rx_traffic_mask);
__netif_rx_schedule(dev);
}
}
#else
- /* If Intr is because of Rx Traffic */
- if (reason & GEN_INTR_RXTRAFFIC) {
- /*
- * rx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- val64 = 0xFFFFFFFFFFFFFFFFULL;
- writeq(val64, &bar0->rx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
+ /*
+ * Rx handler is called by default, without checking for the
+ * cause of interrupt.
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ writeq(val64, &bar0->rx_traffic_int);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ rx_intr_handler(&mac_control->rings[i]);
}
#endif
- /* If Intr is because of Tx Traffic */
- if (reason & GEN_INTR_TXTRAFFIC) {
- /*
- * tx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- val64 = 0xFFFFFFFFFFFFFFFFULL;
- writeq(val64, &bar0->tx_traffic_int);
+ /*
+ * tx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ writeq(val64, &bar0->tx_traffic_int);
- for (i = 0; i < config->tx_fifo_num; i++)
- tx_intr_handler(&mac_control->fifos[i]);
- }
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
if (reason & GEN_INTR_TXPIC)
s2io_txpic_intr_handle(sp);
@@ -3949,6 +4314,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
DBG_PRINT(ERR_DBG, " in ISR!!\n");
clear_bit(0, (&sp->tasklet_status));
atomic_dec(&sp->isr_cnt);
+ writeq(org_mask, &bar0->general_int_mask);
return IRQ_HANDLED;
}
clear_bit(0, (&sp->tasklet_status));
@@ -3964,7 +4330,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
}
}
#endif
-
+ writeq(org_mask, &bar0->general_int_mask);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4067,7 +4433,8 @@ static void s2io_set_multicast(struct net_device *dev)
RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
- wait_for_cmd_complete(sp);
+ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
sp->m_cast_flg = 1;
sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
@@ -4082,7 +4449,8 @@ static void s2io_set_multicast(struct net_device *dev)
RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
- wait_for_cmd_complete(sp);
+ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
sp->m_cast_flg = 0;
sp->all_multi_pos = 0;
@@ -4147,7 +4515,8 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait for command completes */
- if (wait_for_cmd_complete(sp)) {
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
DBG_PRINT(ERR_DBG, "%s: Adding ",
dev->name);
DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4177,7 +4546,8 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait for command completes */
- if (wait_for_cmd_complete(sp)) {
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
DBG_PRINT(ERR_DBG, "%s: Adding ",
dev->name);
DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4222,7 +4592,8 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
RMAC_ADDR_CMD_MEM_OFFSET(0);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
- if (wait_for_cmd_complete(sp)) {
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
return FAILURE;
}
@@ -4619,6 +4990,44 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
return ret;
}
+static void s2io_vpd_read(nic_t *nic)
+{
+ u8 vpd_data[256],data;
+ int i=0, cnt, fail = 0;
+ int vpd_addr = 0x80;
+
+ if (nic->device_type == XFRAME_II_DEVICE) {
+ strcpy(nic->product_name, "Xframe II 10GbE network adapter");
+ vpd_addr = 0x80;
+ }
+ else {
+ strcpy(nic->product_name, "Xframe I 10GbE network adapter");
+ vpd_addr = 0x50;
+ }
+
+ for (i = 0; i < 256; i +=4 ) {
+ pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
+ pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
+ pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0);
+ for (cnt = 0; cnt <5; cnt++) {
+ msleep(2);
+ pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data);
+ if (data == 0x80)
+ break;
+ }
+ if (cnt >= 5) {
+ DBG_PRINT(ERR_DBG, "Read of VPD data failed\n");
+ fail = 1;
+ break;
+ }
+ pci_read_config_dword(nic->pdev, (vpd_addr + 4),
+ (u32 *)&vpd_data[i]);
+ }
+ if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+ memset(nic->product_name, 0, vpd_data[1]);
+ memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
+ }
+}
/**
* s2io_ethtool_geeprom - reads the value stored in the Eeprom.
@@ -4931,8 +5340,10 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
u64 val64;
val64 = readq(&bar0->adapter_status);
- if (val64 & ADAPTER_STATUS_RMAC_LOCAL_FAULT)
+ if(!(LINK_IS_UP(val64)))
*data = 1;
+ else
+ *data = 0;
return 0;
}
@@ -5112,7 +5523,6 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
int i = 0;
nic_t *sp = dev->priv;
StatInfo_t *stat_info = sp->mac_control.stats_info;
- u64 tmp;
s2io_updt_stats(sp);
tmp_stats[i++] =
@@ -5129,9 +5539,19 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
(u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 |
le32_to_cpu(stat_info->tmac_bcst_frms);
tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 |
+ le32_to_cpu(stat_info->tmac_ttl_octets);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 |
+ le32_to_cpu(stat_info->tmac_ucst_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 |
+ le32_to_cpu(stat_info->tmac_nucst_frms);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 |
le32_to_cpu(stat_info->tmac_any_err_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets);
tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 |
@@ -5163,11 +5583,27 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
(u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 |
le32_to_cpu(stat_info->rmac_vld_bcst_frms);
tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms);
tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms);
tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 |
+ le32_to_cpu(stat_info->rmac_ttl_octets);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow)
+ << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow)
+ << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 |
le32_to_cpu(stat_info->rmac_discarded_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow)
+ << 32 | le32_to_cpu(stat_info->rmac_drop_events);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 |
le32_to_cpu(stat_info->rmac_usized_frms);
@@ -5180,40 +5616,129 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 |
le32_to_cpu(stat_info->rmac_jabber_frms);
- tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms);
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 |
le32_to_cpu(stat_info->rmac_ip);
tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets);
tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip);
- tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 |
le32_to_cpu(stat_info->rmac_drop_ip);
- tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 |
le32_to_cpu(stat_info->rmac_icmp);
tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp);
- tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
+ tmp_stats[i++] =
+ (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 |
le32_to_cpu(stat_info->rmac_udp);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 |
le32_to_cpu(stat_info->rmac_err_drp_udp);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6);
+ tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 |
le32_to_cpu(stat_info->rmac_pause_cnt);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt);
tmp_stats[i++] =
(u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 |
le32_to_cpu(stat_info->rmac_accepted_ip);
tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
tmp_stats[i++] = 0;
tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
+ tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high;
+ tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high;
+ tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low;
tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
tmp_stats[i++] = stat_info->sw_stat.sending_both;
tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
- tmp = 0;
if (stat_info->sw_stat.num_aggregations) {
- tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
- do_div(tmp, stat_info->sw_stat.num_aggregations);
+ u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
+ int count = 0;
+ /*
+ * Since 64-bit divide does not work on all platforms,
+ * do repeated subtraction.
+ */
+ while (tmp >= stat_info->sw_stat.num_aggregations) {
+ tmp -= stat_info->sw_stat.num_aggregations;
+ count++;
+ }
+ tmp_stats[i++] = count;
}
- tmp_stats[i++] = tmp;
+ else
+ tmp_stats[i++] = 0;
}
static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5351,7 +5876,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu;
if (netif_running(dev)) {
- s2io_card_down(sp);
+ s2io_card_down(sp, 0);
netif_stop_queue(dev);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
@@ -5489,12 +6014,172 @@ static void s2io_set_link(unsigned long data)
clear_bit(0, &(nic->link_state));
}
-static void s2io_card_down(nic_t * sp)
+static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
+ struct sk_buff **skb, u64 *temp0, u64 *temp1,
+ u64 *temp2, int size)
+{
+ struct net_device *dev = sp->dev;
+ struct sk_buff *frag_list;
+
+ if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
+ /* allocate skb */
+ if (*skb) {
+ DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
+ /*
+ * As Rx frame are not going to be processed,
+ * using same mapped address for the Rxd
+ * buffer pointer
+ */
+ ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+ } else {
+ *skb = dev_alloc_skb(size);
+ if (!(*skb)) {
+ DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ return -ENOMEM ;
+ }
+ /* storing the mapped addr in a temp variable
+ * such it will be used for next rxd whose
+ * Host Control is NULL
+ */
+ ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+ pci_map_single( sp->pdev, (*skb)->data,
+ size - NET_IP_ALIGN,
+ PCI_DMA_FROMDEVICE);
+ rxdp->Host_Control = (unsigned long) (*skb);
+ }
+ } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
+ /* Two buffer Mode */
+ if (*skb) {
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
+ ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ } else {
+ *skb = dev_alloc_skb(size);
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ pci_map_single(sp->pdev, (*skb)->data,
+ dev->mtu + 4,
+ PCI_DMA_FROMDEVICE);
+ ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
+ PCI_DMA_FROMDEVICE);
+ rxdp->Host_Control = (unsigned long) (*skb);
+
+ /* Buffer-1 will be dummy buffer not used */
+ ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
+ PCI_DMA_FROMDEVICE);
+ }
+ } else if ((rxdp->Host_Control == 0)) {
+ /* Three buffer mode */
+ if (*skb) {
+ ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
+ ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ } else {
+ *skb = dev_alloc_skb(size);
+
+ ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
+ PCI_DMA_FROMDEVICE);
+ /* Buffer-1 receives L3/L4 headers */
+ ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ pci_map_single( sp->pdev, (*skb)->data,
+ l3l4hdr_size + 4,
+ PCI_DMA_FROMDEVICE);
+ /*
+ * skb_shinfo(skb)->frag_list will have L4
+ * data payload
+ */
+ skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
+ ALIGN_SIZE);
+ if (skb_shinfo(*skb)->frag_list == NULL) {
+ DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
+ failed\n ", dev->name);
+ return -ENOMEM ;
+ }
+ frag_list = skb_shinfo(*skb)->frag_list;
+ frag_list->next = NULL;
+ /*
+ * Buffer-2 receives L4 data payload
+ */
+ ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ pci_map_single( sp->pdev, frag_list->data,
+ dev->mtu, PCI_DMA_FROMDEVICE);
+ }
+ }
+ return 0;
+}
+static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+{
+ struct net_device *dev = sp->dev;
+ if (sp->rxd_mode == RXD_MODE_1) {
+ rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN);
+ } else if (sp->rxd_mode == RXD_MODE_3B) {
+ rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
+ rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
+ rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
+ } else {
+ rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
+ rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
+ rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
+ }
+}
+
+static int rxd_owner_bit_reset(nic_t *sp)
+{
+ int i, j, k, blk_cnt = 0, size;
+ mac_info_t * mac_control = &sp->mac_control;
+ struct config_param *config = &sp->config;
+ struct net_device *dev = sp->dev;
+ RxD_t *rxdp = NULL;
+ struct sk_buff *skb = NULL;
+ buffAdd_t *ba = NULL;
+ u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
+
+ /* Calculate the size based on ring mode */
+ size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
+ HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
+ if (sp->rxd_mode == RXD_MODE_1)
+ size += NET_IP_ALIGN;
+ else if (sp->rxd_mode == RXD_MODE_3B)
+ size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
+ else
+ size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
+
+ for (i = 0; i < config->rx_ring_num; i++) {
+ blk_cnt = config->rx_cfg[i].num_rxd /
+ (rxd_count[sp->rxd_mode] +1);
+
+ for (j = 0; j < blk_cnt; j++) {
+ for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
+ rxdp = mac_control->rings[i].
+ rx_blocks[j].rxds[k].virt_addr;
+ if(sp->rxd_mode >= RXD_MODE_3A)
+ ba = &mac_control->rings[i].ba[j][k];
+ set_rxd_buffer_pointer(sp, rxdp, ba,
+ &skb,(u64 *)&temp0_64,
+ (u64 *)&temp1_64,
+ (u64 *)&temp2_64, size);
+
+ set_rxd_buffer_size(sp, rxdp, size);
+ wmb();
+ /* flip the Ownership bit to Hardware */
+ rxdp->Control_1 |= RXD_OWN_XENA;
+ }
+ }
+ }
+ return 0;
+
+}
+
+static void s2io_card_down(nic_t * sp, int flag)
{
int cnt = 0;
XENA_dev_config_t __iomem *bar0 = sp->bar0;
unsigned long flags;
register u64 val64 = 0;
+ struct net_device *dev = sp->dev;
del_timer_sync(&sp->alarm_timer);
/* If s2io_set_link task is executing, wait till it completes. */
@@ -5505,12 +6190,51 @@ static void s2io_card_down(nic_t * sp)
/* disable Tx and Rx traffic on the NIC */
stop_nic(sp);
+ if (flag) {
+ if (sp->intr_type == MSI_X) {
+ int i;
+ u16 msi_control;
+
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+
+ free_irq(vector, arg);
+ }
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+ pci_disable_msix(sp->pdev);
+ } else {
+ free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type == MSI)
+ pci_disable_msi(sp->pdev);
+ }
+ }
+ /* Waiting till all Interrupt handlers are complete */
+ cnt = 0;
+ do {
+ msleep(10);
+ if (!atomic_read(&sp->isr_cnt))
+ break;
+ cnt++;
+ } while(cnt < 5);
/* Kill tasklet. */
tasklet_kill(&sp->task);
/* Check if the device is Quiescent and then Reset the NIC */
do {
+ /* As per the HW requirement we need to replenish the
+ * receive buffer to avoid the ring bump. Since there is
+ * no intention of processing the Rx frame at this pointwe are
+ * just settting the ownership bit of rxd in Each Rx
+ * ring to HW and set the appropriate buffer size
+ * based on the ring mode
+ */
+ rxd_owner_bit_reset(sp);
+
val64 = readq(&bar0->adapter_status);
if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
break;
@@ -5528,15 +6252,6 @@ static void s2io_card_down(nic_t * sp)
} while (1);
s2io_reset(sp);
- /* Waiting till all Interrupt handlers are complete */
- cnt = 0;
- do {
- msleep(10);
- if (!atomic_read(&sp->isr_cnt))
- break;
- cnt++;
- } while(cnt < 5);
-
spin_lock_irqsave(&sp->tx_lock, flags);
/* Free all Tx buffers */
free_tx_buffers(sp);
@@ -5637,7 +6352,7 @@ static void s2io_restart_nic(unsigned long data)
struct net_device *dev = (struct net_device *) data;
nic_t *sp = dev->priv;
- s2io_card_down(sp);
+ s2io_card_down(sp, 0);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
dev->name);
@@ -5667,6 +6382,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
if (netif_carrier_ok(dev)) {
schedule_work(&sp->rst_timer_task);
+ sp->mac_control.stats_info->sw_stat.soft_reset_cnt++;
}
}
@@ -5695,18 +6411,33 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
u16 l3_csum, l4_csum;
+ unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
lro_t *lro;
skb->dev = dev;
- if (rxdp->Control_1 & RXD_T_CODE) {
- unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
- DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
- dev->name, err);
- dev_kfree_skb(skb);
- sp->stats.rx_crc_errors++;
- atomic_dec(&sp->rx_bufs_left[ring_no]);
- rxdp->Host_Control = 0;
- return 0;
+
+ if (err) {
+ /* Check for parity error */
+ if (err & 0x1) {
+ sp->mac_control.stats_info->sw_stat.parity_err_cnt++;
+ }
+
+ /*
+ * Drop the packet if bad transfer code. Exception being
+ * 0x5, which could be due to unsupported IPv6 extension header.
+ * In this case, we let stack handle the packet.
+ * Note that in this case, since checksum will be incorrect,
+ * stack will validate the same.
+ */
+ if (err && ((err >> 48) != 0x5)) {
+ DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n",
+ dev->name, err);
+ sp->stats.rx_crc_errors++;
+ dev_kfree_skb(skb);
+ atomic_dec(&sp->rx_bufs_left[ring_no]);
+ rxdp->Host_Control = 0;
+ return 0;
+ }
}
/* Updating statistics */
@@ -5792,6 +6523,9 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
clear_lro_session(lro);
goto send_up;
case 0: /* sessions exceeded */
+ case -1: /* non-TCP or not
+ * L2 aggregatable
+ */
case 5: /*
* First pkt in session not
* L3/L4 aggregatable
@@ -5918,13 +6652,6 @@ static void s2io_init_pci(nic_t * sp)
pci_write_config_word(sp->pdev, PCI_COMMAND,
(pci_cmd | PCI_COMMAND_PARITY));
pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
-
- /* Forcibly disabling relaxed ordering capability of the card. */
- pcix_cmd &= 0xfffd;
- pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
- pcix_cmd);
- pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
- &(pcix_cmd));
}
MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
@@ -5954,6 +6681,55 @@ module_param(intr_type, int, 0);
module_param(lro, int, 0);
module_param(lro_max_pkts, int, 0);
+static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
+{
+ if ( tx_fifo_num > 8) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
+ "supported\n");
+ DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
+ tx_fifo_num = 8;
+ }
+ if ( rx_ring_num > 8) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
+ "supported\n");
+ DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
+ rx_ring_num = 8;
+ }
+#ifdef CONFIG_S2IO_NAPI
+ if (*dev_intr_type != INTA) {
+ DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
+ "MSI/MSI-X is enabled. Defaulting to INTA\n");
+ *dev_intr_type = INTA;
+ }
+#endif
+#ifndef CONFIG_PCI_MSI
+ if (*dev_intr_type != INTA) {
+ DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
+ "MSI/MSI-X. Defaulting to INTA\n");
+ *dev_intr_type = INTA;
+ }
+#else
+ if (*dev_intr_type > MSI_X) {
+ DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
+ "Defaulting to INTA\n");
+ *dev_intr_type = INTA;
+ }
+#endif
+ if ((*dev_intr_type == MSI_X) &&
+ ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
+ (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
+ DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
+ "Defaulting to INTA\n");
+ *dev_intr_type = INTA;
+ }
+ if (rx_ring_mode > 3) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
+ DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
+ rx_ring_mode = 3;
+ }
+ return SUCCESS;
+}
+
/**
* s2io_init_nic - Initialization of the adapter .
* @pdev : structure containing the PCI related information of the device.
@@ -5984,15 +6760,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
int mode;
u8 dev_intr_type = intr_type;
-#ifdef CONFIG_S2IO_NAPI
- if (dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \
-is enabled. Defaulting to INTA\n");
- dev_intr_type = INTA;
- }
- else
- DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
-#endif
+ if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
+ return ret;
if ((ret = pci_enable_device(pdev))) {
DBG_PRINT(ERR_DBG,
@@ -6017,14 +6786,6 @@ is enabled. Defaulting to INTA\n");
pci_disable_device(pdev);
return -ENOMEM;
}
-
- if ((dev_intr_type == MSI_X) &&
- ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
- (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
- DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \
-Defaulting to INTA\n");
- dev_intr_type = INTA;
- }
if (dev_intr_type != MSI_X) {
if (pci_request_regions(pdev, s2io_driver_name)) {
DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
@@ -6100,8 +6861,6 @@ Defaulting to INTA\n");
config = &sp->config;
/* Tx side parameters. */
- if (tx_fifo_len[0] == 0)
- tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
config->tx_fifo_num = tx_fifo_num;
for (i = 0; i < MAX_TX_FIFOS; i++) {
config->tx_cfg[i].fifo_len = tx_fifo_len[i];
@@ -6125,8 +6884,6 @@ Defaulting to INTA\n");
config->max_txds = MAX_SKB_FRAGS + 2;
/* Rx side parameters. */
- if (rx_ring_sz[0] == 0)
- rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
config->rx_ring_num = rx_ring_num;
for (i = 0; i < MAX_RX_RINGS; i++) {
config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
@@ -6267,8 +7024,8 @@ Defaulting to INTA\n");
val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
writeq(val64, &bar0->rmac_addr_cmd_mem);
- wait_for_cmd_complete(sp);
-
+ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
tmp64 = readq(&bar0->rmac_addr_data0_mem);
mac_down = (u32) tmp64;
mac_up = (u32) (tmp64 >> 32);
@@ -6322,82 +7079,63 @@ Defaulting to INTA\n");
ret = -ENODEV;
goto register_failed;
}
-
- if (sp->device_type & XFRAME_II_DEVICE) {
- DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
- dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
+ s2io_vpd_read(sp);
+ DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name);
+ DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n",
get_xena_rev_id(sp->pdev),
s2io_driver_version);
- switch(sp->intr_type) {
- case INTA:
- DBG_PRINT(ERR_DBG, ", Intr type INTA");
- break;
- case MSI:
- DBG_PRINT(ERR_DBG, ", Intr type MSI");
- break;
- case MSI_X:
- DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
- break;
- }
-
- DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
- DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
sp->def_mac_addr[0].mac_addr[2],
sp->def_mac_addr[0].mac_addr[3],
sp->def_mac_addr[0].mac_addr[4],
sp->def_mac_addr[0].mac_addr[5]);
+ if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
if (mode < 0) {
- DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode ");
+ DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n");
ret = -EBADSLT;
+ unregister_netdev(dev);
goto set_swap_failed;
}
- } else {
- DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
- dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
- get_xena_rev_id(sp->pdev),
- s2io_driver_version);
- switch(sp->intr_type) {
- case INTA:
- DBG_PRINT(ERR_DBG, ", Intr type INTA");
- break;
- case MSI:
- DBG_PRINT(ERR_DBG, ", Intr type MSI");
- break;
- case MSI_X:
- DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
- break;
- }
- DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
- DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
- sp->def_mac_addr[0].mac_addr[0],
- sp->def_mac_addr[0].mac_addr[1],
- sp->def_mac_addr[0].mac_addr[2],
- sp->def_mac_addr[0].mac_addr[3],
- sp->def_mac_addr[0].mac_addr[4],
- sp->def_mac_addr[0].mac_addr[5]);
}
- if (sp->rxd_mode == RXD_MODE_3B)
- DBG_PRINT(ERR_DBG, "%s: 2-Buffer mode support has been "
- "enabled\n",dev->name);
- if (sp->rxd_mode == RXD_MODE_3A)
- DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been "
- "enabled\n",dev->name);
-
+ switch(sp->rxd_mode) {
+ case RXD_MODE_1:
+ DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
+ dev->name);
+ break;
+ case RXD_MODE_3B:
+ DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
+ dev->name);
+ break;
+ case RXD_MODE_3A:
+ DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
+ dev->name);
+ break;
+ }
+#ifdef CONFIG_S2IO_NAPI
+ DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
+#endif
+ switch(sp->intr_type) {
+ case INTA:
+ DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
+ break;
+ case MSI:
+ DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
+ break;
+ case MSI_X:
+ DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
+ break;
+ }
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
- dev->name);
+ dev->name);
/* Initialize device name */
- strcpy(sp->name, dev->name);
- if (sp->device_type & XFRAME_II_DEVICE)
- strcat(sp->name, ": Neterion Xframe II 10GbE adapter");
- else
- strcat(sp->name, ": Neterion Xframe I 10GbE adapter");
+ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
/* Initialize bimodal Interrupts */
sp->config.bimodal = bimodal;
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 0a0b5b29d81e..3203732a668d 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -31,6 +31,8 @@
#define SUCCESS 0
#define FAILURE -1
+#define CHECKBIT(value, nbit) (value & (1 << nbit))
+
/* Maximum time to flicker LED when asked to identify NIC using ethtool */
#define MAX_FLICKER_TIME 60000 /* 60 Secs */
@@ -78,6 +80,11 @@ static int debug_level = ERR_DBG;
typedef struct {
unsigned long long single_ecc_errs;
unsigned long long double_ecc_errs;
+ unsigned long long parity_err_cnt;
+ unsigned long long serious_err_cnt;
+ unsigned long long soft_reset_cnt;
+ unsigned long long fifo_full_cnt;
+ unsigned long long ring_full_cnt;
/* LRO statistics */
unsigned long long clubbed_frms_cnt;
unsigned long long sending_both;
@@ -87,6 +94,25 @@ typedef struct {
unsigned long long num_aggregations;
} swStat_t;
+/* Xpak releated alarm and warnings */
+typedef struct {
+ u64 alarm_transceiver_temp_high;
+ u64 alarm_transceiver_temp_low;
+ u64 alarm_laser_bias_current_high;
+ u64 alarm_laser_bias_current_low;
+ u64 alarm_laser_output_power_high;
+ u64 alarm_laser_output_power_low;
+ u64 warn_transceiver_temp_high;
+ u64 warn_transceiver_temp_low;
+ u64 warn_laser_bias_current_high;
+ u64 warn_laser_bias_current_low;
+ u64 warn_laser_output_power_high;
+ u64 warn_laser_output_power_low;
+ u64 xpak_regs_stat;
+ u32 xpak_timer_count;
+} xpakStat_t;
+
+
/* The statistics block of Xena */
typedef struct stat_block {
/* Tx MAC statistics counters. */
@@ -263,7 +289,9 @@ typedef struct stat_block {
u32 rmac_accepted_ip_oflow;
u32 reserved_14;
u32 link_fault_cnt;
+ u8 buffer[20];
swStat_t sw_stat;
+ xpakStat_t xpak_stat;
} StatInfo_t;
/*
@@ -659,7 +687,8 @@ typedef struct {
} usr_addr_t;
/* Default Tunable parameters of the NIC. */
-#define DEFAULT_FIFO_LEN 4096
+#define DEFAULT_FIFO_0_LEN 4096
+#define DEFAULT_FIFO_1_7_LEN 512
#define SMALL_BLK_CNT 30
#define LARGE_BLK_CNT 100
@@ -732,7 +761,7 @@ struct s2io_nic {
int device_close_flag;
int device_enabled_once;
- char name[50];
+ char name[60];
struct tasklet_struct task;
volatile unsigned long tasklet_status;
@@ -803,6 +832,8 @@ struct s2io_nic {
char desc1[35];
char desc2[35];
+ int avail_msix_vectors; /* No. of MSI-X vectors granted by system */
+
struct msix_info_st msix_info[0x3f];
#define XFRAME_I_DEVICE 1
@@ -824,6 +855,8 @@ struct s2io_nic {
spinlock_t rx_lock;
atomic_t isr_cnt;
u64 *ufo_in_band_v;
+#define VPD_PRODUCT_NAME_LEN 50
+ u8 product_name[VPD_PRODUCT_NAME_LEN];
};
#define RESET_ERROR 1;
@@ -848,28 +881,32 @@ static inline void writeq(u64 val, void __iomem *addr)
writel((u32) (val), addr);
writel((u32) (val >> 32), (addr + 4));
}
+#endif
-/* In 32 bit modes, some registers have to be written in a
- * particular order to expect correct hardware operation. The
- * macro SPECIAL_REG_WRITE is used to perform such ordered
- * writes. Defines UF (Upper First) and LF (Lower First) will
- * be used to specify the required write order.
+/*
+ * Some registers have to be written in a particular order to
+ * expect correct hardware operation. The macro SPECIAL_REG_WRITE
+ * is used to perform such ordered writes. Defines UF (Upper First)
+ * and LF (Lower First) will be used to specify the required write order.
*/
#define UF 1
#define LF 2
static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order)
{
+ u32 ret;
+
if (order == LF) {
writel((u32) (val), addr);
+ ret = readl(addr);
writel((u32) (val >> 32), (addr + 4));
+ ret = readl(addr + 4);
} else {
writel((u32) (val >> 32), (addr + 4));
+ ret = readl(addr + 4);
writel((u32) (val), addr);
+ ret = readl(addr);
}
}
-#else
-#define SPECIAL_REG_WRITE(val, addr, dummy) writeq(val, addr)
-#endif
/* Interrupt related values of Xena */
@@ -965,7 +1002,7 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
+static void s2io_card_down(nic_t *nic, int flag);
static int s2io_card_up(nic_t *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
static void restore_xmsi_data(nic_t *nic);
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index b82191d2bee1..d05874172209 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1,6 +1,6 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.08.09 Sep. 19 2005
+ Revision: 1.08.10 Apr. 2 2006
Modified from the driver which is originally written by Donald Becker.
@@ -17,9 +17,10 @@
SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
preliminary Rev. 1.0 Jan. 18, 1998
+ Rev 1.08.10 Apr. 2 2006 Daniele Venzano add vlan (jumbo packets) support
Rev 1.08.09 Sep. 19 2005 Daniele Venzano add Wake on LAN support
Rev 1.08.08 Jan. 22 2005 Daniele Venzano use netif_msg for debugging messages
- Rev 1.08.07 Nov. 2 2003 Daniele Venzano <webvenza@libero.it> add suspend/resume support
+ Rev 1.08.07 Nov. 2 2003 Daniele Venzano <venza@brownhat.org> add suspend/resume support
Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support
Rev 1.08.05 Jun. 6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary
Rev 1.08.04 Apr. 25 2002 Mufasa Yang <mufasa@sis.com.tw> added SiS962 support
@@ -77,7 +78,7 @@
#include "sis900.h"
#define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.09 Sep. 19 2005"
+#define SIS900_DRV_VERSION "v1.08.10 Apr. 2 2006"
static char version[] __devinitdata =
KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -127,6 +128,7 @@ static const struct mii_chip_info {
} mii_chip_table[] = {
{ "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN },
{ "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN },
+ { "SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, LAN },
{ "Altimata AC101LF PHY", 0x0022, 0x5520, LAN },
{ "ADM 7001 LAN PHY", 0x002e, 0xcc60, LAN },
{ "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN },
@@ -1401,6 +1403,11 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex)
rx_flags |= RxATX;
}
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ /* Can accept Jumbo packet */
+ rx_flags |= RxAJAB;
+#endif
+
outl (tx_flags, ioaddr + txcfg);
outl (rx_flags, ioaddr + rxcfg);
}
@@ -1713,18 +1720,26 @@ static int sis900_rx(struct net_device *net_dev)
while (rx_status & OWN) {
unsigned int rx_size;
+ unsigned int data_size;
if (--rx_work_limit < 0)
break;
- rx_size = (rx_status & DSIZE) - CRC_SIZE;
+ data_size = rx_status & DSIZE;
+ rx_size = data_size - CRC_SIZE;
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ /* ``TOOLONG'' flag means jumbo packet recived. */
+ if ((rx_status & TOOLONG) && data_size <= MAX_FRAME_SIZE)
+ rx_status &= (~ ((unsigned int)TOOLONG));
+#endif
if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
/* corrupted packet received */
if (netif_msg_rx_err(sis_priv))
printk(KERN_DEBUG "%s: Corrupted packet "
- "received, buffer status = 0x%8.8x.\n",
- net_dev->name, rx_status);
+ "received, buffer status = 0x%8.8x/%d.\n",
+ net_dev->name, rx_status, data_size);
sis_priv->stats.rx_errors++;
if (rx_status & OVERRUN)
sis_priv->stats.rx_over_errors++;
diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
index 50323941e3c0..4834e3a15694 100644
--- a/drivers/net/sis900.h
+++ b/drivers/net/sis900.h
@@ -310,8 +310,14 @@ enum sis630_revision_id {
#define CRC_SIZE 4
#define MAC_HEADER_SIZE 14
-#define TX_BUF_SIZE 1536
-#define RX_BUF_SIZE 1536
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define MAX_FRAME_SIZE (1518 + 4)
+#else
+#define MAX_FRAME_SIZE 1518
+#endif /* CONFIG_VLAN_802_1Q */
+
+#define TX_BUF_SIZE (MAX_FRAME_SIZE+18)
+#define RX_BUF_SIZE (MAX_FRAME_SIZE+18)
#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */
#define NUM_RX_DESC 16 /* Number of Rx descriptor registers. */
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index a70c2b0cc104..536dd1cf7f79 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -44,12 +44,13 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.5"
+#define DRV_VERSION "1.6"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define DEFAULT_RX_RING_SIZE 512
#define MAX_TX_RING_SIZE 1024
+#define TX_LOW_WATER (MAX_SKB_FRAGS + 1)
#define MAX_RX_RING_SIZE 4096
#define RX_COPY_THRESHOLD 128
#define RX_BUF_SIZE 1536
@@ -78,8 +79,7 @@ static const struct pci_device_id skge_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* DGE-530T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
@@ -402,7 +402,7 @@ static int skge_set_ring_param(struct net_device *dev,
int err;
if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
- p->tx_pending == 0 || p->tx_pending > MAX_TX_RING_SIZE)
+ p->tx_pending < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE)
return -EINVAL;
skge->rx_ring.count = p->rx_pending;
@@ -604,7 +604,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
struct skge_hw *hw = skge->hw;
int port = skge->port;
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
if (hw->chip_id == CHIP_ID_GENESIS) {
switch (mode) {
case LED_MODE_OFF:
@@ -664,7 +664,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
PHY_M_LED_MO_RX(MO_LED_ON));
}
}
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
}
/* blink LED's for finding board */
@@ -2039,7 +2039,7 @@ static void skge_phy_reset(struct skge_port *skge)
netif_stop_queue(skge->netdev);
netif_carrier_off(skge->netdev);
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
if (hw->chip_id == CHIP_ID_GENESIS) {
genesis_reset(hw, port);
genesis_mac_init(hw, port);
@@ -2047,7 +2047,7 @@ static void skge_phy_reset(struct skge_port *skge)
yukon_reset(hw, port);
yukon_init(hw, port);
}
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
}
/* Basic MII support */
@@ -2068,12 +2068,12 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* fallthru */
case SIOCGMIIREG: {
u16 val = 0;
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
if (hw->chip_id == CHIP_ID_GENESIS)
err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
else
err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
data->val_out = val;
break;
}
@@ -2082,14 +2082,14 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
if (hw->chip_id == CHIP_ID_GENESIS)
err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f,
data->val_in);
else
err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f,
data->val_in);
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
break;
}
return err;
@@ -2192,12 +2192,12 @@ static int skge_up(struct net_device *dev)
goto free_rx_ring;
/* Initialize MAC */
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_init(hw, port);
else
yukon_mac_init(hw, port);
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
/* Configure RAMbuffers */
chunk = hw->ram_size / ((hw->ports + 1)*2);
@@ -2303,21 +2303,20 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- struct skge_ring *ring = &skge->tx_ring;
struct skge_element *e;
struct skge_tx_desc *td;
int i;
u32 control, len;
u64 map;
+ unsigned long flags;
skb = skb_padto(skb, ETH_ZLEN);
if (!skb)
return NETDEV_TX_OK;
- if (!spin_trylock(&skge->tx_lock)) {
+ if (!spin_trylock_irqsave(&skge->tx_lock, flags))
/* Collision - tell upper layer to requeue */
return NETDEV_TX_LOCKED;
- }
if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) {
if (!netif_queue_stopped(dev)) {
@@ -2326,12 +2325,13 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
dev->name);
}
- spin_unlock(&skge->tx_lock);
+ spin_unlock_irqrestore(&skge->tx_lock, flags);
return NETDEV_TX_BUSY;
}
- e = ring->to_use;
+ e = skge->tx_ring.to_use;
td = e->desc;
+ BUG_ON(td->control & BMU_OWN);
e->skb = skb;
len = skb_headlen(skb);
map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
@@ -2372,8 +2372,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
frag->size, PCI_DMA_TODEVICE);
e = e->next;
- e->skb = NULL;
+ e->skb = skb;
tf = e->desc;
+ BUG_ON(tf->control & BMU_OWN);
+
tf->dma_lo = map;
tf->dma_hi = (u64) map >> 32;
pci_unmap_addr_set(e, mapaddr, map);
@@ -2390,56 +2392,68 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START);
- if (netif_msg_tx_queued(skge))
+ if (unlikely(netif_msg_tx_queued(skge)))
printk(KERN_DEBUG "%s: tx queued, slot %td, len %d\n",
- dev->name, e - ring->start, skb->len);
+ dev->name, e - skge->tx_ring.start, skb->len);
- ring->to_use = e->next;
- if (skge_avail(&skge->tx_ring) <= MAX_SKB_FRAGS + 1) {
+ skge->tx_ring.to_use = e->next;
+ if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
pr_debug("%s: transmit queue full\n", dev->name);
netif_stop_queue(dev);
}
- mmiowb();
- spin_unlock(&skge->tx_lock);
+ spin_unlock_irqrestore(&skge->tx_lock, flags);
dev->trans_start = jiffies;
return NETDEV_TX_OK;
}
-static void skge_tx_complete(struct skge_port *skge, struct skge_element *last)
+
+/* Free resources associated with this reing element */
+static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
+ u32 control)
{
struct pci_dev *pdev = skge->hw->pdev;
- struct skge_element *e;
- for (e = skge->tx_ring.to_clean; e != last; e = e->next) {
- struct sk_buff *skb = e->skb;
- int i;
+ BUG_ON(!e->skb);
- e->skb = NULL;
+ /* skb header vs. fragment */
+ if (control & BMU_STF)
pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
- skb_headlen(skb), PCI_DMA_TODEVICE);
+ pci_unmap_len(e, maplen),
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_page(pdev, pci_unmap_addr(e, mapaddr),
+ pci_unmap_len(e, maplen),
+ PCI_DMA_TODEVICE);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- e = e->next;
- pci_unmap_page(pdev, pci_unmap_addr(e, mapaddr),
- skb_shinfo(skb)->frags[i].size,
- PCI_DMA_TODEVICE);
- }
+ if (control & BMU_EOF) {
+ if (unlikely(netif_msg_tx_done(skge)))
+ printk(KERN_DEBUG PFX "%s: tx done slot %td\n",
+ skge->netdev->name, e - skge->tx_ring.start);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(e->skb);
}
- skge->tx_ring.to_clean = e;
+ e->skb = NULL;
}
+/* Free all buffers in transmit ring */
static void skge_tx_clean(struct skge_port *skge)
{
+ struct skge_element *e;
+ unsigned long flags;
+
+ spin_lock_irqsave(&skge->tx_lock, flags);
+ for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
+ struct skge_tx_desc *td = e->desc;
+ skge_tx_free(skge, e, td->control);
+ td->control = 0;
+ }
- spin_lock_bh(&skge->tx_lock);
- skge_tx_complete(skge, skge->tx_ring.to_use);
+ skge->tx_ring.to_clean = e;
netif_wake_queue(skge->netdev);
- spin_unlock_bh(&skge->tx_lock);
+ spin_unlock_irqrestore(&skge->tx_lock, flags);
}
static void skge_tx_timeout(struct net_device *dev)
@@ -2665,32 +2679,28 @@ resubmit:
return NULL;
}
-static void skge_tx_done(struct skge_port *skge)
+/* Free all buffers in Tx ring which are no longer owned by device */
+static void skge_txirq(struct net_device *dev)
{
+ struct skge_port *skge = netdev_priv(dev);
struct skge_ring *ring = &skge->tx_ring;
- struct skge_element *e, *last;
+ struct skge_element *e;
+
+ rmb();
spin_lock(&skge->tx_lock);
- last = ring->to_clean;
for (e = ring->to_clean; e != ring->to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
if (td->control & BMU_OWN)
break;
- if (td->control & BMU_EOF) {
- last = e->next;
- if (unlikely(netif_msg_tx_done(skge)))
- printk(KERN_DEBUG PFX "%s: tx done slot %td\n",
- skge->netdev->name, e - ring->start);
- }
+ skge_tx_free(skge, e, td->control);
}
+ skge->tx_ring.to_clean = e;
- skge_tx_complete(skge, last);
-
- skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
-
- if (skge_avail(&skge->tx_ring) > MAX_SKB_FRAGS + 1)
+ if (netif_queue_stopped(skge->netdev)
+ && skge_avail(&skge->tx_ring) > TX_LOW_WATER)
netif_wake_queue(skge->netdev);
spin_unlock(&skge->tx_lock);
@@ -2705,8 +2715,6 @@ static int skge_poll(struct net_device *dev, int *budget)
int to_do = min(dev->quota, *budget);
int work_done = 0;
- skge_tx_done(skge);
-
for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
struct sk_buff *skb;
@@ -2717,8 +2725,7 @@ static int skge_poll(struct net_device *dev, int *budget)
if (control & BMU_OWN)
break;
- skb = skge_rx_get(skge, e, control, rd->status,
- le16_to_cpu(rd->csum2));
+ skb = skge_rx_get(skge, e, control, rd->status, rd->csum2);
if (likely(skb)) {
dev->last_rx = jiffies;
netif_receive_skb(skb);
@@ -2739,10 +2746,12 @@ static int skge_poll(struct net_device *dev, int *budget)
return 1; /* not done */
netif_rx_complete(dev);
- mmiowb();
- hw->intr_mask |= skge->port == 0 ? (IS_R1_F|IS_XA1_F) : (IS_R2_F|IS_XA2_F);
+ spin_lock_irq(&hw->hw_lock);
+ hw->intr_mask |= rxirqmask[skge->port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ mmiowb();
+ spin_unlock_irq(&hw->hw_lock);
return 0;
}
@@ -2849,16 +2858,16 @@ static void skge_error_irq(struct skge_hw *hw)
}
/*
- * Interrupt from PHY are handled in tasklet (soft irq)
+ * Interrupt from PHY are handled in work queue
* because accessing phy registers requires spin wait which might
* cause excess interrupt latency.
*/
-static void skge_extirq(unsigned long data)
+static void skge_extirq(void *arg)
{
- struct skge_hw *hw = (struct skge_hw *) data;
+ struct skge_hw *hw = arg;
int port;
- spin_lock(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
for (port = 0; port < hw->ports; port++) {
struct net_device *dev = hw->dev[port];
struct skge_port *skge = netdev_priv(dev);
@@ -2870,10 +2879,12 @@ static void skge_extirq(unsigned long data)
bcom_phy_intr(skge);
}
}
- spin_unlock(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
+ spin_lock_irq(&hw->hw_lock);
hw->intr_mask |= IS_EXT_REG;
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ spin_unlock_irq(&hw->hw_lock);
}
static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -2886,54 +2897,68 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
if (status == 0)
return IRQ_NONE;
+ spin_lock(&hw->hw_lock);
+ status &= hw->intr_mask;
if (status & IS_EXT_REG) {
hw->intr_mask &= ~IS_EXT_REG;
- tasklet_schedule(&hw->ext_tasklet);
+ schedule_work(&hw->phy_work);
}
- if (status & (IS_R1_F|IS_XA1_F)) {
- skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F);
- hw->intr_mask &= ~(IS_R1_F|IS_XA1_F);
- netif_rx_schedule(hw->dev[0]);
+ if (status & IS_XA1_F) {
+ skge_write8(hw, Q_ADDR(Q_XA1, Q_CSR), CSR_IRQ_CL_F);
+ skge_txirq(hw->dev[0]);
}
- if (status & (IS_R2_F|IS_XA2_F)) {
- skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F);
- hw->intr_mask &= ~(IS_R2_F|IS_XA2_F);
- netif_rx_schedule(hw->dev[1]);
+ if (status & IS_R1_F) {
+ skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F);
+ hw->intr_mask &= ~IS_R1_F;
+ netif_rx_schedule(hw->dev[0]);
}
- if (likely((status & hw->intr_mask) == 0))
- return IRQ_HANDLED;
+ if (status & IS_PA_TO_TX1)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
if (status & IS_PA_TO_RX1) {
struct skge_port *skge = netdev_priv(hw->dev[0]);
- ++skge->net_stats.rx_over_errors;
- skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
- }
- if (status & IS_PA_TO_RX2) {
- struct skge_port *skge = netdev_priv(hw->dev[1]);
++skge->net_stats.rx_over_errors;
- skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
}
- if (status & IS_PA_TO_TX1)
- skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
-
- if (status & IS_PA_TO_TX2)
- skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
if (status & IS_MAC1)
skge_mac_intr(hw, 0);
- if (status & IS_MAC2)
- skge_mac_intr(hw, 1);
+ if (hw->dev[1]) {
+ if (status & IS_XA2_F) {
+ skge_write8(hw, Q_ADDR(Q_XA2, Q_CSR), CSR_IRQ_CL_F);
+ skge_txirq(hw->dev[1]);
+ }
+
+ if (status & IS_R2_F) {
+ skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F);
+ hw->intr_mask &= ~IS_R2_F;
+ netif_rx_schedule(hw->dev[1]);
+ }
+
+ if (status & IS_PA_TO_RX2) {
+ struct skge_port *skge = netdev_priv(hw->dev[1]);
+ ++skge->net_stats.rx_over_errors;
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+ }
+
+ if (status & IS_PA_TO_TX2)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
+
+ if (status & IS_MAC2)
+ skge_mac_intr(hw, 1);
+ }
if (status & IS_HW_ERR)
skge_error_irq(hw);
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ spin_unlock(&hw->hw_lock);
return IRQ_HANDLED;
}
@@ -2959,7 +2984,7 @@ static int skge_set_mac_address(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
memcpy_toio(hw->regs + B2_MAC_1 + port*8,
dev->dev_addr, ETH_ALEN);
@@ -2972,7 +2997,7 @@ static int skge_set_mac_address(struct net_device *dev, void *p)
gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr);
gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr);
}
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
return 0;
}
@@ -3084,6 +3109,7 @@ static int skge_reset(struct skge_hw *hw)
else
hw->ram_size = t8 * 4096;
+ spin_lock_init(&hw->hw_lock);
hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
if (hw->ports > 1)
hw->intr_mask |= IS_PORT_2;
@@ -3152,14 +3178,14 @@ static int skge_reset(struct skge_hw *hw)
skge_write32(hw, B0_IMSK, hw->intr_mask);
- spin_lock_bh(&hw->phy_lock);
+ mutex_lock(&hw->phy_mutex);
for (i = 0; i < hw->ports; i++) {
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_reset(hw, i);
else
yukon_reset(hw, i);
}
- spin_unlock_bh(&hw->phy_lock);
+ mutex_unlock(&hw->phy_mutex);
return 0;
}
@@ -3307,8 +3333,8 @@ static int __devinit skge_probe(struct pci_dev *pdev,
}
hw->pdev = pdev;
- spin_lock_init(&hw->phy_lock);
- tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw);
+ mutex_init(&hw->phy_mutex);
+ INIT_WORK(&hw->phy_work, skge_extirq, hw);
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
@@ -3336,6 +3362,14 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
goto err_out_led_off;
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
+ pci_name(pdev));
+ err = -EIO;
+ goto err_out_free_netdev;
+ }
+
+
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "%s: cannot register net device\n",
@@ -3390,11 +3424,15 @@ static void __devexit skge_remove(struct pci_dev *pdev)
dev0 = hw->dev[0];
unregister_netdev(dev0);
+ spin_lock_irq(&hw->hw_lock);
+ hw->intr_mask = 0;
skge_write32(hw, B0_IMSK, 0);
+ spin_unlock_irq(&hw->hw_lock);
+
skge_write16(hw, B0_LED, LED_STAT_OFF);
skge_write8(hw, B0_CTST, CS_RST_SET);
- tasklet_kill(&hw->ext_tasklet);
+ flush_scheduled_work();
free_irq(pdev->irq, hw);
pci_release_regions(pdev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 1f1ce88c8186..ed19ff47ce11 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -2388,6 +2388,7 @@ struct skge_ring {
struct skge_hw {
void __iomem *regs;
struct pci_dev *pdev;
+ spinlock_t hw_lock;
u32 intr_mask;
struct net_device *dev[2];
@@ -2399,9 +2400,8 @@ struct skge_hw {
u32 ram_size;
u32 ram_offset;
u16 phy_addr;
-
- struct tasklet_struct ext_tasklet;
- spinlock_t phy_lock;
+ struct work_struct phy_work;
+ struct mutex phy_mutex;
};
enum {
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 67b0eab16589..fba1e4d4d83d 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -51,7 +51,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "1.4"
#define PFX DRV_NAME " "
/*
@@ -79,6 +79,8 @@
#define NAPI_WEIGHT 64
#define PHY_RETRIES 1000
+#define RING_NEXT(x,s) (((x)+1) & ((s)-1))
+
static const u32 default_msg =
NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
@@ -96,9 +98,14 @@ static int disable_msi = 0;
module_param(disable_msi, int, 0);
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+static int idle_timeout = 100;
+module_param(idle_timeout, int, 0);
+MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)");
+
static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
@@ -122,6 +129,7 @@ MODULE_DEVICE_TABLE(pci, sky2_id_table);
/* Avoid conditionals by using array */
static const unsigned txqaddr[] = { Q_XA1, Q_XA2 };
static const unsigned rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
/* This driver supports yukon2 chipset only */
static const char *yukon2_name[] = {
@@ -179,12 +187,11 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
return v;
}
-static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
+static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
{
u16 power_control;
u32 reg1;
int vaux;
- int ret = 0;
pr_debug("sky2_set_power_state %d\n", state);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -228,6 +235,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
}
if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
sky2_pci_write32(hw, PCI_DEV_REG3, 0);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
reg1 &= P_ASPM_CONTROL_MSK;
@@ -266,12 +274,10 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
break;
default:
printk(KERN_ERR PFX "Unknown power state %d\n", state);
- ret = -1;
}
sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
- return ret;
}
static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
@@ -298,7 +304,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
- if (sky2->autoneg == AUTONEG_ENABLE && hw->chip_id != CHIP_ID_YUKON_XL) {
+ if (sky2->autoneg == AUTONEG_ENABLE &&
+ !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -326,7 +333,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
if (sky2->autoneg == AUTONEG_ENABLE &&
- hw->chip_id == CHIP_ID_YUKON_XL) {
+ (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
}
@@ -442,10 +449,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
/* set LED Function Control register */
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */
- PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */
- PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
- PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */
+ PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */
+ PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+ PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */
/* set Polarity Control register */
gm_phy_write(hw, port, PHY_MARV_PHY_STAT,
@@ -459,6 +467,25 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* restore page register */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
break;
+ case CHIP_ID_YUKON_EC_U:
+ pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+ /* select page 3 to access LED control register */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
+
+ /* set LED Function Control register */
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */
+ PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */
+ PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+ PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */
+
+ /* set Blink Rate in LED Timer Control Register */
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK,
+ ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS));
+ /* restore page register */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+ break;
default:
/* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
@@ -467,19 +494,21 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
}
- if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) {
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) {
/* apply fixes in PHY AFE */
- gm_phy_write(hw, port, 22, 255);
+ pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
+
/* increase differential signal amplitude in 10BASE-T */
- gm_phy_write(hw, port, 24, 0xaa99);
- gm_phy_write(hw, port, 23, 0x2011);
+ gm_phy_write(hw, port, 0x18, 0xaa99);
+ gm_phy_write(hw, port, 0x17, 0x2011);
/* fix for IEEE A/B Symmetry failure in 1000BASE-T */
- gm_phy_write(hw, port, 24, 0xa204);
- gm_phy_write(hw, port, 23, 0x2002);
+ gm_phy_write(hw, port, 0x18, 0xa204);
+ gm_phy_write(hw, port, 0x17, 0x2002);
/* set page register to 0 */
- gm_phy_write(hw, port, 22, 0);
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
} else {
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
@@ -553,6 +582,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
if (sky2->duplex == DUPLEX_FULL)
reg |= GM_GPCR_DUP_FULL;
+
+ /* turn off pause in 10/100mbps half duplex */
+ else if (sky2->speed != SPEED_1000 &&
+ hw->chip_id != CHIP_ID_YUKON_EC_U)
+ sky2->tx_pause = sky2->rx_pause = 0;
} else
reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
@@ -719,7 +753,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2)
{
struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod;
- sky2->tx_prod = (sky2->tx_prod + 1) % TX_RING_SIZE;
+ sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE);
return le;
}
@@ -735,7 +769,7 @@ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
{
struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put;
- sky2->rx_put = (sky2->rx_put + 1) % RX_LE_SIZE;
+ sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE);
return le;
}
@@ -925,8 +959,7 @@ static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask)
skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
if (likely(skb)) {
unsigned long p = (unsigned long) skb->data;
- skb_reserve(skb,
- ((p + RX_SKB_ALIGN - 1) & ~(RX_SKB_ALIGN - 1)) - p);
+ skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
}
return skb;
@@ -943,6 +976,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
struct sky2_hw *hw = sky2->hw;
unsigned rxq = rxqaddr[sky2->port];
int i;
+ unsigned thresh;
sky2->rx_put = sky2->rx_next = 0;
sky2_qset(hw, rxq);
@@ -967,9 +1001,21 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_rx_add(sky2, re->mapaddr);
}
- /* Truncate oversize frames */
- sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), sky2->rx_bufsize - 8);
- sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+
+ /*
+ * The receiver hangs if it receives frames larger than the
+ * packet buffer. As a workaround, truncate oversize frames, but
+ * the register is limited to 9 bits, so if you do frames > 2052
+ * you better get the MTU right!
+ */
+ thresh = (sky2->rx_bufsize - 8) / sizeof(u32);
+ if (thresh > 0x1ff)
+ sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
+ else {
+ sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), thresh);
+ sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+ }
+
/* Tell chip about available buffers */
sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put);
@@ -986,7 +1032,25 @@ static int sky2_up(struct net_device *dev)
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
u32 ramsize, rxspace, imask;
- int err = -ENOMEM;
+ int cap, err = -ENOMEM;
+ struct net_device *otherdev = hw->dev[sky2->port^1];
+
+ /*
+ * On dual port PCI-X card, there is an problem where status
+ * can be received out of order due to split transactions
+ */
+ if (otherdev && netif_running(otherdev) &&
+ (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
+ struct sky2_port *osky2 = netdev_priv(otherdev);
+ u16 cmd;
+
+ cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+ cmd &= ~PCI_X_CMD_MAX_SPLIT;
+ sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+
+ sky2->rx_csum = 0;
+ osky2->rx_csum = 0;
+ }
if (netif_msg_ifup(sky2))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
@@ -1051,7 +1115,7 @@ static int sky2_up(struct net_device *dev)
/* Enable interrupts from phy/mac for port */
imask = sky2_read32(hw, B0_IMSK);
- imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+ imask |= portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
return 0;
@@ -1079,7 +1143,7 @@ err_out:
/* Modular subtraction in ring */
static inline int tx_dist(unsigned tail, unsigned head)
{
- return (head - tail) % TX_RING_SIZE;
+ return (head - tail) & (TX_RING_SIZE - 1);
}
/* Number of list elements available for next tx */
@@ -1256,7 +1320,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
le->opcode = OP_BUFFER | HW_OWNER;
fre = sky2->tx_ring
- + ((re - sky2->tx_ring) + i + 1) % TX_RING_SIZE;
+ + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE);
pci_unmap_addr_set(fre, mapaddr, mapping);
}
@@ -1316,7 +1380,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
struct tx_ring_info *fre;
- fre = sky2->tx_ring + (put + i + 1) % TX_RING_SIZE;
+ fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE);
pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr),
skb_shinfo(skb)->frags[i].size,
PCI_DMA_TODEVICE);
@@ -1402,7 +1466,7 @@ static int sky2_down(struct net_device *dev)
/* Disable port IRQ */
imask = sky2_read32(hw, B0_IMSK);
- imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+ imask &= ~portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
/* turn off LED's */
@@ -1499,17 +1563,26 @@ static void sky2_link_up(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+ u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
+
+ switch(sky2->speed) {
+ case SPEED_10:
+ led |= PHY_M_LEDC_INIT_CTRL(7);
+ break;
+
+ case SPEED_100:
+ led |= PHY_M_LEDC_STA1_CTRL(7);
+ break;
+
+ case SPEED_1000:
+ led |= PHY_M_LEDC_STA0_CTRL(7);
+ break;
+ }
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */
- PHY_M_LEDC_INIT_CTRL(sky2->speed ==
- SPEED_10 ? 7 : 0) |
- PHY_M_LEDC_STA1_CTRL(sky2->speed ==
- SPEED_100 ? 7 : 0) |
- PHY_M_LEDC_STA0_CTRL(sky2->speed ==
- SPEED_1000 ? 7 : 0));
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led);
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
}
@@ -1584,7 +1657,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
sky2->speed = sky2_phy_speed(hw, aux);
/* Pause bits are offset (9..8) */
- if (hw->chip_id == CHIP_ID_YUKON_XL)
+ if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
aux >>= 6;
sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
@@ -1686,13 +1759,12 @@ static void sky2_tx_timeout(struct net_device *dev)
}
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
/* Want receive buffer size to be multiple of 64 bits
* and incl room for vlan and truncation
*/
static inline unsigned sky2_buf_size(int mtu)
{
- return roundup(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
+ return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
}
static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1857,39 +1929,38 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
}
}
+/* Is status ring empty or is there more to do? */
+static inline int sky2_more_work(const struct sky2_hw *hw)
+{
+ return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
+}
+
/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do)
{
int work_done = 0;
+ u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
rmb();
- for(;;) {
+ while (hw->st_idx != hwidx) {
struct sky2_status_le *le = hw->st_le + hw->st_idx;
struct net_device *dev;
struct sky2_port *sky2;
struct sk_buff *skb;
u32 status;
u16 length;
- u8 link, opcode;
-
- opcode = le->opcode;
- if (!opcode)
- break;
- opcode &= ~HW_OWNER;
- hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE;
- le->opcode = 0;
+ hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
- link = le->link;
- BUG_ON(link >= 2);
- dev = hw->dev[link];
+ BUG_ON(le->link >= 2);
+ dev = hw->dev[le->link];
sky2 = netdev_priv(dev);
length = le->length;
status = le->status;
- switch (opcode) {
+ switch (le->opcode & ~HW_OWNER) {
case OP_RXSTAT:
skb = sky2_receive(sky2, length, status);
if (!skb)
@@ -1929,7 +2000,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
case OP_TXINDEXLE:
/* TX index reports status for both ports */
- sky2_tx_done(hw->dev[0], status & 0xffff);
+ BUILD_BUG_ON(TX_RING_SIZE > 0x1000);
+ sky2_tx_done(hw->dev[0], status & 0xfff);
if (hw->dev[1])
sky2_tx_done(hw->dev[1],
((status >> 24) & 0xff)
@@ -1939,8 +2011,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
default:
if (net_ratelimit())
printk(KERN_WARNING PFX
- "unknown status opcode 0x%x\n", opcode);
- break;
+ "unknown status opcode 0x%x\n", le->opcode);
+ goto exit_loop;
}
}
@@ -2086,6 +2158,28 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
}
}
+/* If idle then force a fake soft NAPI poll once a second
+ * to work around cases where sharing an edge triggered interrupt.
+ */
+static inline void sky2_idle_start(struct sky2_hw *hw)
+{
+ if (idle_timeout > 0)
+ mod_timer(&hw->idle_timer,
+ jiffies + msecs_to_jiffies(idle_timeout));
+}
+
+static void sky2_idle(unsigned long arg)
+{
+ struct sky2_hw *hw = (struct sky2_hw *) arg;
+ struct net_device *dev = hw->dev[0];
+
+ if (__netif_rx_schedule_prep(dev))
+ __netif_rx_schedule(dev);
+
+ mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout));
+}
+
+
static int sky2_poll(struct net_device *dev0, int *budget)
{
struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
@@ -2093,49 +2187,49 @@ static int sky2_poll(struct net_device *dev0, int *budget)
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
- if (unlikely(status & ~Y2_IS_STAT_BMU)) {
- if (status & Y2_IS_HW_ERR)
- sky2_hw_intr(hw);
+ if (!~status)
+ goto out;
- if (status & Y2_IS_IRQ_PHY1)
- sky2_phy_intr(hw, 0);
+ if (status & Y2_IS_HW_ERR)
+ sky2_hw_intr(hw);
- if (status & Y2_IS_IRQ_PHY2)
- sky2_phy_intr(hw, 1);
+ if (status & Y2_IS_IRQ_PHY1)
+ sky2_phy_intr(hw, 0);
- if (status & Y2_IS_IRQ_MAC1)
- sky2_mac_intr(hw, 0);
+ if (status & Y2_IS_IRQ_PHY2)
+ sky2_phy_intr(hw, 1);
- if (status & Y2_IS_IRQ_MAC2)
- sky2_mac_intr(hw, 1);
+ if (status & Y2_IS_IRQ_MAC1)
+ sky2_mac_intr(hw, 0);
- if (status & Y2_IS_CHK_RX1)
- sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
+ if (status & Y2_IS_IRQ_MAC2)
+ sky2_mac_intr(hw, 1);
- if (status & Y2_IS_CHK_RX2)
- sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
+ if (status & Y2_IS_CHK_RX1)
+ sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
- if (status & Y2_IS_CHK_TXA1)
- sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
+ if (status & Y2_IS_CHK_RX2)
+ sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
- if (status & Y2_IS_CHK_TXA2)
- sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
- }
+ if (status & Y2_IS_CHK_TXA1)
+ sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
- if (status & Y2_IS_STAT_BMU) {
- work_done = sky2_status_intr(hw, work_limit);
- *budget -= work_done;
- dev0->quota -= work_done;
+ if (status & Y2_IS_CHK_TXA2)
+ sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
- if (work_done >= work_limit)
- return 1;
+ work_done = sky2_status_intr(hw, work_limit);
+ *budget -= work_done;
+ dev0->quota -= work_done;
+ if (status & Y2_IS_STAT_BMU)
sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
- }
+ if (sky2_more_work(hw))
+ return 1;
+out:
netif_rx_complete(dev0);
- status = sky2_read32(hw, B0_Y2_SP_LISR);
+ sky2_read32(hw, B0_Y2_SP_LISR);
return 0;
}
@@ -2153,8 +2247,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
prefetch(&hw->st_le[hw->st_idx]);
if (likely(__netif_rx_schedule_prep(dev0)))
__netif_rx_schedule(dev0);
- else
- printk(KERN_DEBUG PFX "irq race detected\n");
return IRQ_HANDLED;
}
@@ -2163,8 +2255,10 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
static void sky2_netpoll(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
+ struct net_device *dev0 = sky2->hw->dev[0];
- sky2_intr(sky2->hw->pdev->irq, sky2->hw, NULL);
+ if (netif_running(dev) && __netif_rx_schedule_prep(dev0))
+ __netif_rx_schedule(dev0);
}
#endif
@@ -2193,7 +2287,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_reset(struct sky2_hw *hw)
{
u16 status;
u8 t8, pmd_type;
@@ -2218,13 +2312,6 @@ static int sky2_reset(struct sky2_hw *hw)
return -EOPNOTSUPP;
}
- /* This chip is new and not tested yet */
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n",
- pci_name(hw->pdev));
- pr_info("Please report success/failure to maintainer <shemminger@osdl.org>\n");
- }
-
/* disable ASF */
if (hw->chip_id <= CHIP_ID_YUKON_EC) {
sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
@@ -3028,12 +3115,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->duplex = -1;
sky2->speed = -1;
sky2->advertising = sky2_supported_modes(hw);
-
- /* Receive checksum disabled for Yukon XL
- * because of observed problems with incorrect
- * values when multiple packets are received in one interrupt
- */
- sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL);
+ sky2->rx_csum = 1;
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
@@ -3276,6 +3358,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+ setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
+ sky2_idle_start(hw);
+
pci_set_drvdata(pdev, hw);
return 0;
@@ -3311,13 +3396,17 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
if (!hw)
return;
+ del_timer_sync(&hw->idle_timer);
+
+ sky2_write32(hw, B0_IMSK, 0);
+ synchronize_irq(hw->pdev->irq);
+
dev0 = hw->dev[0];
dev1 = hw->dev[1];
if (dev1)
unregister_netdev(dev1);
unregister_netdev(dev0);
- sky2_write32(hw, B0_IMSK, 0);
sky2_set_power_state(hw, PCI_D3hot);
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
sky2_write8(hw, B0_CTST, CS_RST_SET);
@@ -3343,8 +3432,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
int i;
+ pci_power_t pstate = pci_choose_state(pdev, state);
+
+ if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
+ return -EINVAL;
- for (i = 0; i < 2; i++) {
+ del_timer_sync(&hw->idle_timer);
+
+ for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
if (dev) {
@@ -3353,10 +3448,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
sky2_down(dev);
netif_device_detach(dev);
+ netif_poll_disable(dev);
}
}
- return sky2_set_power_state(hw, pci_choose_state(pdev, state));
+ sky2_write32(hw, B0_IMSK, 0);
+ pci_save_state(pdev);
+ sky2_set_power_state(hw, pstate);
+ return 0;
}
static int sky2_resume(struct pci_dev *pdev)
@@ -3366,27 +3465,31 @@ static int sky2_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D0, 0);
- err = sky2_set_power_state(hw, PCI_D0);
- if (err)
- goto out;
+ sky2_set_power_state(hw, PCI_D0);
err = sky2_reset(hw);
if (err)
goto out;
- for (i = 0; i < 2; i++) {
+ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+
+ for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
if (dev && netif_running(dev)) {
netif_device_attach(dev);
+ netif_poll_enable(dev);
+
err = sky2_up(dev);
if (err) {
printk(KERN_ERR PFX "%s: could not up: %d\n",
dev->name, err);
dev_close(dev);
- break;
+ goto out;
}
}
}
+
+ sky2_idle_start(hw);
out:
return err;
}
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 89dd18cd12f0..8a0bc5525f0a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -214,6 +214,8 @@ enum csr_regs {
enum {
Y2_VMAIN_AVAIL = 1<<17,/* VMAIN available (YUKON-2 only) */
Y2_VAUX_AVAIL = 1<<16,/* VAUX available (YUKON-2 only) */
+ Y2_HW_WOL_ON = 1<<15,/* HW WOL On (Yukon-EC Ultra A1 only) */
+ Y2_HW_WOL_OFF = 1<<14,/* HW WOL On (Yukon-EC Ultra A1 only) */
Y2_ASF_ENABLE = 1<<13,/* ASF Unit Enable (YUKON-2 only) */
Y2_ASF_DISABLE = 1<<12,/* ASF Unit Disable (YUKON-2 only) */
Y2_CLK_RUN_ENA = 1<<11,/* CLK_RUN Enable (YUKON-2 only) */
@@ -378,6 +380,9 @@ enum {
CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */
CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */
CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */
+
+ CHIP_REV_YU_EC_U_A0 = 0,
+ CHIP_REV_YU_EC_U_A1 = 1,
};
/* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */
@@ -1880,6 +1885,8 @@ struct sky2_hw {
struct sky2_status_le *st_le;
u32 st_idx;
dma_addr_t st_dma;
+
+ struct timer_list idle_timer;
int msi_detected;
wait_queue_head_t msi_wait;
};
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 3db30cd0625e..5b4e8529d4ab 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -553,7 +553,7 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
+int __init
init_module(void)
{
struct net_device *dev;
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index b3e397d7ca85..ff9bd97746dc 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -421,7 +421,7 @@ static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
MODULE_LICENSE("GPL");
-int init_module(void)
+int __init init_module(void)
{
int this_dev, found = 0;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
new file mode 100644
index 000000000000..bdd8702ead54
--- /dev/null
+++ b/drivers/net/smc911x.c
@@ -0,0 +1,2307 @@
+/*
+ * smc911x.c
+ * This is a driver for SMSC's LAN911{5,6,7,8} single-chip Ethernet devices.
+ *
+ * Copyright (C) 2005 Sensoria Corp
+ * Derived from the unified SMC91x driver by Nicolas Pitre
+ * and the smsc911x.c reference driver by SMSC
+ *
+ * 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
+ *
+ * Arguments:
+ * watchdog = TX watchdog timeout
+ * tx_fifo_kb = Size of TX FIFO in KB
+ *
+ * History:
+ * 04/16/05 Dustin McIntire Initial version
+ */
+static const char version[] =
+ "smc911x.c: v1.0 04-16-2005 by Dustin McIntire <dustin@sensoria.com>\n";
+
+/* Debugging options */
+#define ENABLE_SMC_DEBUG_RX 0
+#define ENABLE_SMC_DEBUG_TX 0
+#define ENABLE_SMC_DEBUG_DMA 0
+#define ENABLE_SMC_DEBUG_PKTS 0
+#define ENABLE_SMC_DEBUG_MISC 0
+#define ENABLE_SMC_DEBUG_FUNC 0
+
+#define SMC_DEBUG_RX ((ENABLE_SMC_DEBUG_RX ? 1 : 0) << 0)
+#define SMC_DEBUG_TX ((ENABLE_SMC_DEBUG_TX ? 1 : 0) << 1)
+#define SMC_DEBUG_DMA ((ENABLE_SMC_DEBUG_DMA ? 1 : 0) << 2)
+#define SMC_DEBUG_PKTS ((ENABLE_SMC_DEBUG_PKTS ? 1 : 0) << 3)
+#define SMC_DEBUG_MISC ((ENABLE_SMC_DEBUG_MISC ? 1 : 0) << 4)
+#define SMC_DEBUG_FUNC ((ENABLE_SMC_DEBUG_FUNC ? 1 : 0) << 5)
+
+#ifndef SMC_DEBUG
+#define SMC_DEBUG ( SMC_DEBUG_RX | \
+ SMC_DEBUG_TX | \
+ SMC_DEBUG_DMA | \
+ SMC_DEBUG_PKTS | \
+ SMC_DEBUG_MISC | \
+ SMC_DEBUG_FUNC \
+ )
+#endif
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/workqueue.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "smc911x.h"
+
+/*
+ * Transmit timeout, default 5 seconds.
+ */
+static int watchdog = 5000;
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+
+static int tx_fifo_kb=8;
+module_param(tx_fifo_kb, int, 0400);
+MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)");
+
+MODULE_LICENSE("GPL");
+
+/*
+ * The internal workings of the driver. If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ */
+#define CARDNAME "smc911x"
+
+/*
+ * Use power-down feature of the chip
+ */
+#define POWER_DOWN 1
+
+
+/* store this information for the driver.. */
+struct smc911x_local {
+ /*
+ * If I have to wait until the DMA is finished and ready to reload a
+ * packet, I will store the skbuff here. Then, the DMA will send it
+ * out and free it.
+ */
+ struct sk_buff *pending_tx_skb;
+
+ /*
+ * these are things that the kernel wants me to keep, so users
+ * can find out semi-useless statistics of how well the card is
+ * performing
+ */
+ struct net_device_stats stats;
+
+ /* version/revision of the SMC911x chip */
+ u16 version;
+ u16 revision;
+
+ /* FIFO sizes */
+ int tx_fifo_kb;
+ int tx_fifo_size;
+ int rx_fifo_size;
+ int afc_cfg;
+
+ /* Contains the current active receive/phy mode */
+ int ctl_rfduplx;
+ int ctl_rspeed;
+
+ u32 msg_enable;
+ u32 phy_type;
+ struct mii_if_info mii;
+
+ /* work queue */
+ struct work_struct phy_configure;
+ int work_pending;
+
+ int tx_throttle;
+ spinlock_t lock;
+
+#ifdef SMC_USE_DMA
+ /* DMA needs the physical address of the chip */
+ u_long physaddr;
+ int rxdma;
+ int txdma;
+ int rxdma_active;
+ int txdma_active;
+ struct sk_buff *current_rx_skb;
+ struct sk_buff *current_tx_skb;
+ struct device *dev;
+#endif
+};
+
+#if SMC_DEBUG > 0
+#define DBG(n, args...) \
+ do { \
+ if (SMC_DEBUG & (n)) \
+ printk(args); \
+ } while (0)
+
+#define PRINTK(args...) printk(args)
+#else
+#define DBG(n, args...) do { } while (0)
+#define PRINTK(args...) printk(KERN_DEBUG args)
+#endif
+
+#if SMC_DEBUG_PKTS > 0
+static void PRINT_PKT(u_char *buf, int length)
+{
+ int i;
+ int remainder;
+ int lines;
+
+ lines = length / 16;
+ remainder = length % 16;
+
+ for (i = 0; i < lines ; i ++) {
+ int cur;
+ for (cur = 0; cur < 8; cur++) {
+ u_char a, b;
+ a = *buf++;
+ b = *buf++;
+ printk("%02x%02x ", a, b);
+ }
+ printk("\n");
+ }
+ for (i = 0; i < remainder/2 ; i++) {
+ u_char a, b;
+ a = *buf++;
+ b = *buf++;
+ printk("%02x%02x ", a, b);
+ }
+ printk("\n");
+}
+#else
+#define PRINT_PKT(x...) do { } while (0)
+#endif
+
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) do { \
+ unsigned int __mask; \
+ unsigned long __flags; \
+ spin_lock_irqsave(&lp->lock, __flags); \
+ __mask = SMC_GET_INT_EN(); \
+ __mask |= (x); \
+ SMC_SET_INT_EN(__mask); \
+ spin_unlock_irqrestore(&lp->lock, __flags); \
+} while (0)
+
+/* this disables an interrupt from the interrupt mask register */
+#define SMC_DISABLE_INT(x) do { \
+ unsigned int __mask; \
+ unsigned long __flags; \
+ spin_lock_irqsave(&lp->lock, __flags); \
+ __mask = SMC_GET_INT_EN(); \
+ __mask &= ~(x); \
+ SMC_SET_INT_EN(__mask); \
+ spin_unlock_irqrestore(&lp->lock, __flags); \
+} while (0)
+
+/*
+ * this does a soft reset on the device
+ */
+static void smc911x_reset(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned int reg, timeout=0, resets=1;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ /* Take out of PM setting first */
+ if ((SMC_GET_PMT_CTRL() & PMT_CTRL_READY_) == 0) {
+ /* Write to the bytetest will take out of powerdown */
+ SMC_SET_BYTE_TEST(0);
+ timeout=10;
+ do {
+ udelay(10);
+ reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_;
+ } while ( timeout-- && !reg);
+ if (timeout == 0) {
+ PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name);
+ return;
+ }
+ }
+
+ /* Disable all interrupts */
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_SET_INT_EN(0);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ while (resets--) {
+ SMC_SET_HW_CFG(HW_CFG_SRST_);
+ timeout=10;
+ do {
+ udelay(10);
+ reg = SMC_GET_HW_CFG();
+ /* If chip indicates reset timeout then try again */
+ if (reg & HW_CFG_SRST_TO_) {
+ PRINTK("%s: chip reset timeout, retrying...\n", dev->name);
+ resets++;
+ break;
+ }
+ } while ( timeout-- && (reg & HW_CFG_SRST_));
+ }
+ if (timeout == 0) {
+ PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name);
+ return;
+ }
+
+ /* make sure EEPROM has finished loading before setting GPIO_CFG */
+ timeout=1000;
+ while ( timeout-- && (SMC_GET_E2P_CMD() & E2P_CMD_EPC_BUSY_)) {
+ udelay(10);
+ }
+ if (timeout == 0){
+ PRINTK("%s: smc911x_reset timeout waiting for EEPROM busy\n", dev->name);
+ return;
+ }
+
+ /* Initialize interrupts */
+ SMC_SET_INT_EN(0);
+ SMC_ACK_INT(-1);
+
+ /* Reset the FIFO level and flow control settings */
+ SMC_SET_HW_CFG((lp->tx_fifo_kb & 0xF) << 16);
+//TODO: Figure out what appropriate pause time is
+ SMC_SET_FLOW(FLOW_FCPT_ | FLOW_FCEN_);
+ SMC_SET_AFC_CFG(lp->afc_cfg);
+
+
+ /* Set to LED outputs */
+ SMC_SET_GPIO_CFG(0x70070000);
+
+ /*
+ * Deassert IRQ for 1*10us for edge type interrupts
+ * and drive IRQ pin push-pull
+ */
+ SMC_SET_IRQ_CFG( (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
+
+ /* clear anything saved */
+ if (lp->pending_tx_skb != NULL) {
+ dev_kfree_skb (lp->pending_tx_skb);
+ lp->pending_tx_skb = NULL;
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+ }
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static void smc911x_enable(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned mask, cfg, cr;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ SMC_SET_MAC_ADDR(dev->dev_addr);
+
+ /* Enable TX */
+ cfg = SMC_GET_HW_CFG();
+ cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF;
+ cfg |= HW_CFG_SF_;
+ SMC_SET_HW_CFG(cfg);
+ SMC_SET_FIFO_TDA(0xFF);
+ /* Update TX stats on every 64 packets received or every 1 sec */
+ SMC_SET_FIFO_TSL(64);
+ SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_GET_MAC_CR(cr);
+ cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_;
+ SMC_SET_MAC_CR(cr);
+ SMC_SET_TX_CFG(TX_CFG_TX_ON_);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ /* Add 2 byte padding to start of packets */
+ SMC_SET_RX_CFG((2<<8) & RX_CFG_RXDOFF_);
+
+ /* Turn on receiver and enable RX */
+ if (cr & MAC_CR_RXEN_)
+ DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_SET_MAC_CR( cr | MAC_CR_RXEN_ );
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ /* Interrupt on every received packet */
+ SMC_SET_FIFO_RSA(0x01);
+ SMC_SET_FIFO_RSL(0x00);
+
+ /* now, enable interrupts */
+ mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
+ INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ |
+ INT_EN_PHY_INT_EN_;
+ if (IS_REV_A(lp->revision))
+ mask|=INT_EN_RDFL_EN_;
+ else {
+ mask|=INT_EN_RDFO_EN_;
+ }
+ SMC_ENABLE_INT(mask);
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void smc911x_shutdown(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned cr;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __FUNCTION__);
+
+ /* Disable IRQ's */
+ SMC_SET_INT_EN(0);
+
+ /* Turn of Rx and TX */
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_GET_MAC_CR(cr);
+ cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
+ SMC_SET_MAC_CR(cr);
+ SMC_SET_TX_CFG(TX_CFG_STOP_TX_);
+ spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static inline void smc911x_drop_pkt(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int fifo_count, timeout, reg;
+
+ DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __FUNCTION__);
+ fifo_count = SMC_GET_RX_FIFO_INF() & 0xFFFF;
+ if (fifo_count <= 4) {
+ /* Manually dump the packet data */
+ while (fifo_count--)
+ SMC_GET_RX_FIFO();
+ } else {
+ /* Fast forward through the bad packet */
+ SMC_SET_RX_DP_CTRL(RX_DP_CTRL_FFWD_BUSY_);
+ timeout=50;
+ do {
+ udelay(10);
+ reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_;
+ } while ( timeout-- && reg);
+ if (timeout == 0) {
+ PRINTK("%s: timeout waiting for RX fast forward\n", dev->name);
+ }
+ }
+}
+
+/*
+ * This is the procedure to handle the receipt of a packet.
+ * It should be called after checking for packet presence in
+ * the RX status FIFO. It must be called with the spin lock
+ * already held.
+ */
+static inline void smc911x_rcv(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int pkt_len, status;
+ struct sk_buff *skb;
+ unsigned char *data;
+
+ DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
+ dev->name, __FUNCTION__);
+ status = SMC_GET_RX_STS_FIFO();
+ DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n",
+ dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
+ pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
+ if (status & RX_STS_ES_) {
+ /* Deal with a bad packet */
+ lp->stats.rx_errors++;
+ if (status & RX_STS_CRC_ERR_)
+ lp->stats.rx_crc_errors++;
+ else {
+ if (status & RX_STS_LEN_ERR_)
+ lp->stats.rx_length_errors++;
+ if (status & RX_STS_MCAST_)
+ lp->stats.multicast++;
+ }
+ /* Remove the bad packet data from the RX FIFO */
+ smc911x_drop_pkt(dev);
+ } else {
+ /* Receive a valid packet */
+ /* Alloc a buffer with extra room for DMA alignment */
+ skb=dev_alloc_skb(pkt_len+32);
+ if (unlikely(skb == NULL)) {
+ PRINTK( "%s: Low memory, rcvd packet dropped.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ smc911x_drop_pkt(dev);
+ return;
+ }
+ /* Align IP header to 32 bits
+ * Note that the device is configured to add a 2
+ * byte padding to the packet start, so we really
+ * want to write to the orignal data pointer */
+ data = skb->data;
+ skb_reserve(skb, 2);
+ skb_put(skb,pkt_len-4);
+#ifdef SMC_USE_DMA
+ {
+ unsigned int fifo;
+ /* Lower the FIFO threshold if possible */
+ fifo = SMC_GET_FIFO_INT();
+ if (fifo & 0xFF) fifo--;
+ DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n",
+ dev->name, fifo & 0xff);
+ SMC_SET_FIFO_INT(fifo);
+ /* Setup RX DMA */
+ SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_));
+ lp->rxdma_active = 1;
+ lp->current_rx_skb = skb;
+ SMC_PULL_DATA(data, (pkt_len+2+15) & ~15);
+ /* Packet processing deferred to DMA RX interrupt */
+ }
+#else
+ SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
+ SMC_PULL_DATA(data, pkt_len+2+3);
+
+ DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+ PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
+ dev->last_rx = jiffies;
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len-4;
+#endif
+ }
+}
+
+/*
+ * This is called to actually send a packet to the chip.
+ */
+static void smc911x_hardware_send_pkt(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ struct sk_buff *skb;
+ unsigned int cmdA, cmdB, len;
+ unsigned char *buf;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __FUNCTION__);
+ BUG_ON(lp->pending_tx_skb == NULL);
+
+ skb = lp->pending_tx_skb;
+ lp->pending_tx_skb = NULL;
+
+ /* cmdA {25:24] data alignment [20:16] start offset [10:0] buffer length */
+ /* cmdB {31:16] pkt tag [10:0] length */
+#ifdef SMC_USE_DMA
+ /* 16 byte buffer alignment mode */
+ buf = (char*)((u32)(skb->data) & ~0xF);
+ len = (skb->len + 0xF + ((u32)skb->data & 0xF)) & ~0xF;
+ cmdA = (1<<24) | (((u32)skb->data & 0xF)<<16) |
+ TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+ skb->len;
+#else
+ buf = (char*)((u32)skb->data & ~0x3);
+ len = (skb->len + 3 + ((u32)skb->data & 3)) & ~0x3;
+ cmdA = (((u32)skb->data & 0x3) << 16) |
+ TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+ skb->len;
+#endif
+ /* tag is packet length so we can use this in stats update later */
+ cmdB = (skb->len << 16) | (skb->len & 0x7FF);
+
+ DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n",
+ dev->name, len, len, buf, cmdA, cmdB);
+ SMC_SET_TX_FIFO(cmdA);
+ SMC_SET_TX_FIFO(cmdB);
+
+ DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name);
+ PRINT_PKT(buf, len <= 64 ? len : 64);
+
+ /* Send pkt via PIO or DMA */
+#ifdef SMC_USE_DMA
+ lp->current_tx_skb = skb;
+ SMC_PUSH_DATA(buf, len);
+ /* DMA complete IRQ will free buffer and set jiffies */
+#else
+ SMC_PUSH_DATA(buf, len);
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+#endif
+ spin_lock_irqsave(&lp->lock, flags);
+ if (!lp->tx_throttle) {
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+ SMC_ENABLE_INT(INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_);
+}
+
+/*
+ * Since I am not sure if I will have enough room in the chip's ram
+ * to store the packet, I call this routine which either sends it
+ * now, or set the card to generates an interrupt when ready
+ * for the packet.
+ */
+static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int free;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
+ dev->name, __FUNCTION__);
+
+ BUG_ON(lp->pending_tx_skb != NULL);
+
+ free = SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TDFREE_;
+ DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free);
+
+ /* Turn off the flow when running out of space in FIFO */
+ if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) {
+ DBG(SMC_DEBUG_TX, "%s: Disabling data flow due to low FIFO space (%d)\n",
+ dev->name, free);
+ spin_lock_irqsave(&lp->lock, flags);
+ /* Reenable when at least 1 packet of size MTU present */
+ SMC_SET_FIFO_TDA((SMC911X_TX_FIFO_LOW_THRESHOLD)/64);
+ lp->tx_throttle = 1;
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+
+ /* Drop packets when we run out of space in TX FIFO
+ * Account for overhead required for:
+ *
+ * Tx command words 8 bytes
+ * Start offset 15 bytes
+ * End padding 15 bytes
+ */
+ if (unlikely(free < (skb->len + 8 + 15 + 15))) {
+ printk("%s: No Tx free space %d < %d\n",
+ dev->name, free, skb->len);
+ lp->pending_tx_skb = NULL;
+ lp->stats.tx_errors++;
+ lp->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+#ifdef SMC_USE_DMA
+ {
+ /* If the DMA is already running then defer this packet Tx until
+ * the DMA IRQ starts it
+ */
+ spin_lock_irqsave(&lp->lock, flags);
+ if (lp->txdma_active) {
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Tx DMA running, deferring packet\n", dev->name);
+ lp->pending_tx_skb = skb;
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ return 0;
+ } else {
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
+ lp->txdma_active = 1;
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+#endif
+ lp->pending_tx_skb = skb;
+ smc911x_hardware_send_pkt(dev);
+
+ return 0;
+}
+
+/*
+ * This handles a TX status interrupt, which is only called when:
+ * - a TX error occurred, or
+ * - TX of a packet completed.
+ */
+static void smc911x_tx(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned int tx_status;
+
+ DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
+ dev->name, __FUNCTION__);
+
+ /* Collect the TX status */
+ while (((SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
+ DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n",
+ dev->name,
+ (SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16);
+ tx_status = SMC_GET_TX_STS_FIFO();
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes+=tx_status>>16;
+ DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
+ dev->name, (tx_status & 0xffff0000) >> 16,
+ tx_status & 0x0000ffff);
+ /* count Tx errors, but ignore lost carrier errors when in
+ * full-duplex mode */
+ if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
+ !(tx_status & 0x00000306))) {
+ lp->stats.tx_errors++;
+ }
+ if (tx_status & TX_STS_MANY_COLL_) {
+ lp->stats.collisions+=16;
+ lp->stats.tx_aborted_errors++;
+ } else {
+ lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
+ }
+ /* carrier error only has meaning for half-duplex communication */
+ if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
+ !lp->ctl_rfduplx) {
+ lp->stats.tx_carrier_errors++;
+ }
+ if (tx_status & TX_STS_LATE_COLL_) {
+ lp->stats.collisions++;
+ lp->stats.tx_aborted_errors++;
+ }
+ }
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+/*
+ * Reads a register from the MII Management serial interface
+ */
+
+static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int phydata;
+
+ SMC_GET_MII(phyreg, phyaddr, phydata);
+
+ DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n",
+ __FUNCTION__, phyaddr, phyreg, phydata);
+ return phydata;
+}
+
+
+/*
+ * Writes a register to the MII Management serial interface
+ */
+static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg,
+ int phydata)
+{
+ unsigned long ioaddr = dev->base_addr;
+
+ DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+ __FUNCTION__, phyaddr, phyreg, phydata);
+
+ SMC_SET_MII(phyreg, phyaddr, phydata);
+}
+
+/*
+ * Finds and reports the PHY address (115 and 117 have external
+ * PHY interface 118 has internal only
+ */
+static void smc911x_phy_detect(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ int phyaddr;
+ unsigned int cfg, id1, id2;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ lp->phy_type = 0;
+
+ /*
+ * Scan all 32 PHY addresses if necessary, starting at
+ * PHY#1 to PHY#31, and then PHY#0 last.
+ */
+ switch(lp->version) {
+ case 0x115:
+ case 0x117:
+ cfg = SMC_GET_HW_CFG();
+ if (cfg & HW_CFG_EXT_PHY_DET_) {
+ cfg &= ~HW_CFG_PHY_CLK_SEL_;
+ cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+ SMC_SET_HW_CFG(cfg);
+ udelay(10); /* Wait for clocks to stop */
+
+ cfg |= HW_CFG_EXT_PHY_EN_;
+ SMC_SET_HW_CFG(cfg);
+ udelay(10); /* Wait for clocks to stop */
+
+ cfg &= ~HW_CFG_PHY_CLK_SEL_;
+ cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+ SMC_SET_HW_CFG(cfg);
+ udelay(10); /* Wait for clocks to stop */
+
+ cfg |= HW_CFG_SMI_SEL_;
+ SMC_SET_HW_CFG(cfg);
+
+ for (phyaddr = 1; phyaddr < 32; ++phyaddr) {
+
+ /* Read the PHY identifiers */
+ SMC_GET_PHY_ID1(phyaddr & 31, id1);
+ SMC_GET_PHY_ID2(phyaddr & 31, id2);
+
+ /* Make sure it is a valid identifier */
+ if (id1 != 0x0000 && id1 != 0xffff &&
+ id1 != 0x8000 && id2 != 0x0000 &&
+ id2 != 0xffff && id2 != 0x8000) {
+ /* Save the PHY's address */
+ lp->mii.phy_id = phyaddr & 31;
+ lp->phy_type = id1 << 16 | id2;
+ break;
+ }
+ }
+ }
+ default:
+ /* Internal media only */
+ SMC_GET_PHY_ID1(1, id1);
+ SMC_GET_PHY_ID2(1, id2);
+ /* Save the PHY's address */
+ lp->mii.phy_id = 1;
+ lp->phy_type = id1 << 16 | id2;
+ }
+
+ DBG(SMC_DEBUG_MISC, "%s: phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%d\n",
+ dev->name, id1, id2, lp->mii.phy_id);
+}
+
+/*
+ * Sets the PHY to a configuration as determined by the user.
+ * Called with spin_lock held.
+ */
+static int smc911x_phy_fixed(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int phyaddr = lp->mii.phy_id;
+ int bmcr;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ /* Enter Link Disable state */
+ SMC_GET_PHY_BMCR(phyaddr, bmcr);
+ bmcr |= BMCR_PDOWN;
+ SMC_SET_PHY_BMCR(phyaddr, bmcr);
+
+ /*
+ * Set our fixed capabilities
+ * Disable auto-negotiation
+ */
+ bmcr &= ~BMCR_ANENABLE;
+ if (lp->ctl_rfduplx)
+ bmcr |= BMCR_FULLDPLX;
+
+ if (lp->ctl_rspeed == 100)
+ bmcr |= BMCR_SPEED100;
+
+ /* Write our capabilities to the phy control register */
+ SMC_SET_PHY_BMCR(phyaddr, bmcr);
+
+ /* Re-Configure the Receive/Phy Control register */
+ bmcr &= ~BMCR_PDOWN;
+ SMC_SET_PHY_BMCR(phyaddr, bmcr);
+
+ return 1;
+}
+
+/*
+ * smc911x_phy_reset - reset the phy
+ * @dev: net device
+ * @phy: phy address
+ *
+ * Issue a software reset for the specified PHY and
+ * wait up to 100ms for the reset to complete. We should
+ * not access the PHY for 50ms after issuing the reset.
+ *
+ * The time to wait appears to be dependent on the PHY.
+ *
+ */
+static int smc911x_phy_reset(struct net_device *dev, int phy)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int timeout;
+ unsigned long flags;
+ unsigned int reg;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ reg = SMC_GET_PMT_CTRL();
+ reg &= ~0xfffff030;
+ reg |= PMT_CTRL_PHY_RST_;
+ SMC_SET_PMT_CTRL(reg);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ for (timeout = 2; timeout; timeout--) {
+ msleep(50);
+ spin_lock_irqsave(&lp->lock, flags);
+ reg = SMC_GET_PMT_CTRL();
+ spin_unlock_irqrestore(&lp->lock, flags);
+ if (!(reg & PMT_CTRL_PHY_RST_)) {
+ /* extra delay required because the phy may
+ * not be completed with its reset
+ * when PHY_BCR_RESET_ is cleared. 256us
+ * should suffice, but use 500us to be safe
+ */
+ udelay(500);
+ break;
+ }
+ }
+
+ return reg & PMT_CTRL_PHY_RST_;
+}
+
+/*
+ * smc911x_phy_powerdown - powerdown phy
+ * @dev: net device
+ * @phy: phy address
+ *
+ * Power down the specified PHY
+ */
+static void smc911x_phy_powerdown(struct net_device *dev, int phy)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int bmcr;
+
+ /* Enter Link Disable state */
+ SMC_GET_PHY_BMCR(phy, bmcr);
+ bmcr |= BMCR_PDOWN;
+ SMC_SET_PHY_BMCR(phy, bmcr);
+}
+
+/*
+ * smc911x_phy_check_media - check the media status and adjust BMCR
+ * @dev: net device
+ * @init: set true for initialisation
+ *
+ * Select duplex mode depending on negotiation state. This
+ * also updates our carrier state.
+ */
+static void smc911x_phy_check_media(struct net_device *dev, int init)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int phyaddr = lp->mii.phy_id;
+ unsigned int bmcr, cr;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
+ /* duplex state has changed */
+ SMC_GET_PHY_BMCR(phyaddr, bmcr);
+ SMC_GET_MAC_CR(cr);
+ if (lp->mii.full_duplex) {
+ DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name);
+ bmcr |= BMCR_FULLDPLX;
+ cr |= MAC_CR_RCVOWN_;
+ } else {
+ DBG(SMC_DEBUG_MISC, "%s: Configuring for half-duplex mode\n", dev->name);
+ bmcr &= ~BMCR_FULLDPLX;
+ cr &= ~MAC_CR_RCVOWN_;
+ }
+ SMC_SET_PHY_BMCR(phyaddr, bmcr);
+ SMC_SET_MAC_CR(cr);
+ }
+}
+
+/*
+ * Configures the specified PHY through the MII management interface
+ * using Autonegotiation.
+ * Calls smc911x_phy_fixed() if the user has requested a certain config.
+ * If RPC ANEG bit is set, the media selection is dependent purely on
+ * the selection by the MII (either in the MII BMCR reg or the result
+ * of autonegotiation.) If the RPC ANEG bit is cleared, the selection
+ * is controlled by the RPC SPEED and RPC DPLX bits.
+ */
+static void smc911x_phy_configure(void *data)
+{
+ struct net_device *dev = data;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int phyaddr = lp->mii.phy_id;
+ int my_phy_caps; /* My PHY capabilities */
+ int my_ad_caps; /* My Advertised capabilities */
+ int status;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
+
+ /*
+ * We should not be called if phy_type is zero.
+ */
+ if (lp->phy_type == 0)
+ goto smc911x_phy_configure_exit;
+
+ if (smc911x_phy_reset(dev, phyaddr)) {
+ printk("%s: PHY reset timed out\n", dev->name);
+ goto smc911x_phy_configure_exit;
+ }
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /*
+ * Enable PHY Interrupts (for register 18)
+ * Interrupts listed here are enabled
+ */
+ SMC_SET_PHY_INT_MASK(phyaddr, PHY_INT_MASK_ENERGY_ON_ |
+ PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ |
+ PHY_INT_MASK_LINK_DOWN_);
+
+ /* If the user requested no auto neg, then go set his request */
+ if (lp->mii.force_media) {
+ smc911x_phy_fixed(dev);
+ goto smc911x_phy_configure_exit;
+ }
+
+ /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
+ SMC_GET_PHY_BMSR(phyaddr, my_phy_caps);
+ if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
+ printk(KERN_INFO "Auto negotiation NOT supported\n");
+ smc911x_phy_fixed(dev);
+ goto smc911x_phy_configure_exit;
+ }
+
+ /* CSMA capable w/ both pauses */
+ my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+ if (my_phy_caps & BMSR_100BASE4)
+ my_ad_caps |= ADVERTISE_100BASE4;
+ if (my_phy_caps & BMSR_100FULL)
+ my_ad_caps |= ADVERTISE_100FULL;
+ if (my_phy_caps & BMSR_100HALF)
+ my_ad_caps |= ADVERTISE_100HALF;
+ if (my_phy_caps & BMSR_10FULL)
+ my_ad_caps |= ADVERTISE_10FULL;
+ if (my_phy_caps & BMSR_10HALF)
+ my_ad_caps |= ADVERTISE_10HALF;
+
+ /* Disable capabilities not selected by our user */
+ if (lp->ctl_rspeed != 100)
+ my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
+
+ if (!lp->ctl_rfduplx)
+ my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
+
+ /* Update our Auto-Neg Advertisement Register */
+ SMC_SET_PHY_MII_ADV(phyaddr, my_ad_caps);
+ lp->mii.advertising = my_ad_caps;
+
+ /*
+ * Read the register back. Without this, it appears that when
+ * auto-negotiation is restarted, sometimes it isn't ready and
+ * the link does not come up.
+ */
+ udelay(10);
+ SMC_GET_PHY_MII_ADV(phyaddr, status);
+
+ DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
+ DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
+
+ /* Restart auto-negotiation process in order to advertise my caps */
+ SMC_SET_PHY_BMCR(phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
+
+ smc911x_phy_check_media(dev, 1);
+
+smc911x_phy_configure_exit:
+ spin_unlock_irqrestore(&lp->lock, flags);
+ lp->work_pending = 0;
+}
+
+/*
+ * smc911x_phy_interrupt
+ *
+ * Purpose: Handle interrupts relating to PHY register 18. This is
+ * called from the "hard" interrupt handler under our private spinlock.
+ */
+static void smc911x_phy_interrupt(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int phyaddr = lp->mii.phy_id;
+ int status;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ if (lp->phy_type == 0)
+ return;
+
+ smc911x_phy_check_media(dev, 0);
+ /* read to clear status bits */
+ SMC_GET_PHY_INT_SRC(phyaddr,status);
+ DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n",
+ dev->name, status & 0xffff);
+ DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n",
+ dev->name, SMC_GET_AFC_CFG());
+}
+
+/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
+
+/*
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned int status, mask, timeout;
+ unsigned int rx_overrun=0, cr, pkts;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* Spurious interrupt check */
+ if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
+ (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) {
+ return IRQ_NONE;
+ }
+
+ mask = SMC_GET_INT_EN();
+ SMC_SET_INT_EN(0);
+
+ /* set a timeout value, so I don't stay here forever */
+ timeout = 8;
+
+
+ do {
+ status = SMC_GET_INT();
+
+ DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n",
+ dev->name, status, mask, status & ~mask);
+
+ status &= mask;
+ if (!status)
+ break;
+
+ /* Handle SW interrupt condition */
+ if (status & INT_STS_SW_INT_) {
+ SMC_ACK_INT(INT_STS_SW_INT_);
+ mask &= ~INT_EN_SW_INT_EN_;
+ }
+ /* Handle various error conditions */
+ if (status & INT_STS_RXE_) {
+ SMC_ACK_INT(INT_STS_RXE_);
+ lp->stats.rx_errors++;
+ }
+ if (status & INT_STS_RXDFH_INT_) {
+ SMC_ACK_INT(INT_STS_RXDFH_INT_);
+ lp->stats.rx_dropped+=SMC_GET_RX_DROP();
+ }
+ /* Undocumented interrupt-what is the right thing to do here? */
+ if (status & INT_STS_RXDF_INT_) {
+ SMC_ACK_INT(INT_STS_RXDF_INT_);
+ }
+
+ /* Rx Data FIFO exceeds set level */
+ if (status & INT_STS_RDFL_) {
+ if (IS_REV_A(lp->revision)) {
+ rx_overrun=1;
+ SMC_GET_MAC_CR(cr);
+ cr &= ~MAC_CR_RXEN_;
+ SMC_SET_MAC_CR(cr);
+ DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ }
+ SMC_ACK_INT(INT_STS_RDFL_);
+ }
+ if (status & INT_STS_RDFO_) {
+ if (!IS_REV_A(lp->revision)) {
+ SMC_GET_MAC_CR(cr);
+ cr &= ~MAC_CR_RXEN_;
+ SMC_SET_MAC_CR(cr);
+ rx_overrun=1;
+ DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ }
+ SMC_ACK_INT(INT_STS_RDFO_);
+ }
+ /* Handle receive condition */
+ if ((status & INT_STS_RSFL_) || rx_overrun) {
+ unsigned int fifo;
+ DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name);
+ fifo = SMC_GET_RX_FIFO_INF();
+ pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16;
+ DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n",
+ dev->name, pkts, fifo & 0xFFFF );
+ if (pkts != 0) {
+#ifdef SMC_USE_DMA
+ unsigned int fifo;
+ if (lp->rxdma_active){
+ DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
+ "%s: RX DMA active\n", dev->name);
+ /* The DMA is already running so up the IRQ threshold */
+ fifo = SMC_GET_FIFO_INT() & ~0xFF;
+ fifo |= pkts & 0xFF;
+ DBG(SMC_DEBUG_RX,
+ "%s: Setting RX stat FIFO threshold to %d\n",
+ dev->name, fifo & 0xff);
+ SMC_SET_FIFO_INT(fifo);
+ } else
+#endif
+ smc911x_rcv(dev);
+ }
+ SMC_ACK_INT(INT_STS_RSFL_);
+ }
+ /* Handle transmit FIFO available */
+ if (status & INT_STS_TDFA_) {
+ DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name);
+ SMC_SET_FIFO_TDA(0xFF);
+ lp->tx_throttle = 0;
+#ifdef SMC_USE_DMA
+ if (!lp->txdma_active)
+#endif
+ netif_wake_queue(dev);
+ SMC_ACK_INT(INT_STS_TDFA_);
+ }
+ /* Handle transmit done condition */
+#if 1
+ if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) {
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC,
+ "%s: Tx stat FIFO limit (%d) /GPT irq\n",
+ dev->name, (SMC_GET_FIFO_INT() & 0x00ff0000) >> 16);
+ smc911x_tx(dev);
+ SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
+ SMC_ACK_INT(INT_STS_TSFL_);
+ SMC_ACK_INT(INT_STS_TSFL_ | INT_STS_GPT_INT_);
+ }
+#else
+ if (status & INT_STS_TSFL_) {
+ DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq \n", dev->name, );
+ smc911x_tx(dev);
+ SMC_ACK_INT(INT_STS_TSFL_);
+ }
+
+ if (status & INT_STS_GPT_INT_) {
+ DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n",
+ dev->name,
+ SMC_GET_IRQ_CFG(),
+ SMC_GET_FIFO_INT(),
+ SMC_GET_RX_CFG());
+ DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x "
+ "Data FIFO Used 0x%04x Stat FIFO 0x%08x\n",
+ dev->name,
+ (SMC_GET_RX_FIFO_INF() & 0x00ff0000) >> 16,
+ SMC_GET_RX_FIFO_INF() & 0xffff,
+ SMC_GET_RX_STS_FIFO_PEEK());
+ SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
+ SMC_ACK_INT(INT_STS_GPT_INT_);
+ }
+#endif
+
+ /* Handle PHY interupt condition */
+ if (status & INT_STS_PHY_INT_) {
+ DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);
+ smc911x_phy_interrupt(dev);
+ SMC_ACK_INT(INT_STS_PHY_INT_);
+ }
+ } while (--timeout);
+
+ /* restore mask state */
+ SMC_SET_INT_EN(mask);
+
+ DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n",
+ dev->name, 8-timeout);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef SMC_USE_DMA
+static void
+smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct smc911x_local *lp = netdev_priv(dev);
+ struct sk_buff *skb = lp->current_tx_skb;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name);
+ /* Clear the DMA interrupt sources */
+ SMC_DMA_ACK_IRQ(dev, dma);
+ BUG_ON(skb == NULL);
+ dma_unmap_single(NULL, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE);
+ dev->trans_start = jiffies;
+ dev_kfree_skb_irq(skb);
+ lp->current_tx_skb = NULL;
+ if (lp->pending_tx_skb != NULL)
+ smc911x_hardware_send_pkt(dev);
+ else {
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
+ "%s: No pending Tx packets. DMA disabled\n", dev->name);
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->txdma_active = 0;
+ if (!lp->tx_throttle) {
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+
+ DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
+ "%s: TX DMA irq completed\n", dev->name);
+}
+static void
+smc911x_rx_dma_irq(int dma, void *data, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)data;
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ struct sk_buff *skb = lp->current_rx_skb;
+ unsigned long flags;
+ unsigned int pkts;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+ DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name);
+ /* Clear the DMA interrupt sources */
+ SMC_DMA_ACK_IRQ(dev, dma);
+ dma_unmap_single(NULL, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE);
+ BUG_ON(skb == NULL);
+ lp->current_rx_skb = NULL;
+ PRINT_PKT(skb->data, skb->len);
+ dev->last_rx = jiffies;
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16;
+ if (pkts != 0) {
+ smc911x_rcv(dev);
+ }else {
+ lp->rxdma_active = 0;
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+ DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
+ "%s: RX DMA irq completed. DMA RX FIFO PKTS %d\n",
+ dev->name, pkts);
+}
+#endif /* SMC_USE_DMA */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void smc911x_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ smc911x_interrupt(dev->irq, dev, NULL);
+ enable_irq(dev->irq);
+}
+#endif
+
+/* Our watchdog timed out. Called by the networking layer */
+static void smc911x_timeout(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int status, mask;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ status = SMC_GET_INT();
+ mask = SMC_GET_INT_EN();
+ spin_unlock_irqrestore(&lp->lock, flags);
+ DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x \n",
+ dev->name, status, mask);
+
+ /* Dump the current TX FIFO contents and restart */
+ mask = SMC_GET_TX_CFG();
+ SMC_SET_TX_CFG(mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);
+ /*
+ * Reconfiguring the PHY doesn't seem like a bad idea here, but
+ * smc911x_phy_configure() calls msleep() which calls schedule_timeout()
+ * which calls schedule(). Hence we use a work queue.
+ */
+ if (lp->phy_type != 0) {
+ if (schedule_work(&lp->phy_configure)) {
+ lp->work_pending = 1;
+ }
+ }
+
+ /* We can accept TX packets again */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void smc911x_set_multicast_list(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int multicast_table[2];
+ unsigned int mcr, update_multicast = 0;
+ unsigned long flags;
+ /* table for flipping the order of 5 bits */
+ static const unsigned char invert5[] =
+ {0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0C, 0x1C,
+ 0x02, 0x12, 0x0A, 0x1A, 0x06, 0x16, 0x0E, 0x1E,
+ 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0D, 0x1D,
+ 0x03, 0x13, 0x0B, 0x1B, 0x07, 0x17, 0x0F, 0x1F};
+
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_GET_MAC_CR(mcr);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ if (dev->flags & IFF_PROMISC) {
+
+ DBG(SMC_DEBUG_MISC, "%s: RCR_PRMS\n", dev->name);
+ mcr |= MAC_CR_PRMS_;
+ }
+ /*
+ * Here, I am setting this to accept all multicast packets.
+ * I don't need to zero the multicast table, because the flag is
+ * checked before the table is
+ */
+ else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) {
+ DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name);
+ mcr |= MAC_CR_MCPAS_;
+ }
+
+ /*
+ * This sets the internal hardware table to filter out unwanted
+ * multicast packets before they take up memory.
+ *
+ * The SMC chip uses a hash table where the high 6 bits of the CRC of
+ * address are the offset into the table. If that bit is 1, then the
+ * multicast packet is accepted. Otherwise, it's dropped silently.
+ *
+ * To use the 6 bits as an offset into the table, the high 1 bit is
+ * the number of the 32 bit register, while the low 5 bits are the bit
+ * within that register.
+ */
+ else if (dev->mc_count) {
+ int i;
+ struct dev_mc_list *cur_addr;
+
+ /* Set the Hash perfec mode */
+ mcr |= MAC_CR_HPFILT_;
+
+ /* start with a table of all zeros: reject all */
+ memset(multicast_table, 0, sizeof(multicast_table));
+
+ cur_addr = dev->mc_list;
+ for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
+ int position;
+
+ /* do we have a pointer here? */
+ if (!cur_addr)
+ break;
+ /* make sure this is a multicast address -
+ shouldn't this be a given if we have it here ? */
+ if (!(*cur_addr->dmi_addr & 1))
+ continue;
+
+ /* only use the low order bits */
+ position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f;
+
+ /* do some messy swapping to put the bit in the right spot */
+ multicast_table[invert5[position&0x1F]&0x1] |=
+ (1<<invert5[(position>>1)&0x1F]);
+ }
+
+ /* be sure I get rid of flags I might have set */
+ mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+ /* now, the table can be loaded into the chipset */
+ update_multicast = 1;
+ } else {
+ DBG(SMC_DEBUG_MISC, "%s: ~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n",
+ dev->name);
+ mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+ /*
+ * since I'm disabling all multicast entirely, I need to
+ * clear the multicast list
+ */
+ memset(multicast_table, 0, sizeof(multicast_table));
+ update_multicast = 1;
+ }
+
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_SET_MAC_CR(mcr);
+ if (update_multicast) {
+ DBG(SMC_DEBUG_MISC,
+ "%s: update mcast hash table 0x%08x 0x%08x\n",
+ dev->name, multicast_table[0], multicast_table[1]);
+ SMC_SET_HASHL(multicast_table[0]);
+ SMC_SET_HASHH(multicast_table[1]);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int
+smc911x_open(struct net_device *dev)
+{
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ /*
+ * Check that the address is valid. If its not, refuse
+ * to bring the device up. The user must specify an
+ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+ */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* reset the hardware */
+ smc911x_reset(dev);
+
+ /* Configure the PHY, initialize the link state */
+ smc911x_phy_configure(dev);
+
+ /* Turn on Tx + Rx */
+ smc911x_enable(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+/*
+ * smc911x_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world. Caused by
+ * an 'ifconfig ethX down'
+ */
+static int smc911x_close(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ /* clear everything */
+ smc911x_shutdown(dev);
+
+ if (lp->phy_type != 0) {
+ /* We need to ensure that no calls to
+ * smc911x_phy_configure are pending.
+
+ * flush_scheduled_work() cannot be called because we
+ * are running with the netlink semaphore held (from
+ * devinet_ioctl()) and the pending work queue
+ * contains linkwatch_event() (scheduled by
+ * netif_carrier_off() above). linkwatch_event() also
+ * wants the netlink semaphore.
+ */
+ while (lp->work_pending)
+ schedule();
+ smc911x_phy_powerdown(dev, lp->mii.phy_id);
+ }
+
+ if (lp->pending_tx_skb) {
+ dev_kfree_skb(lp->pending_tx_skb);
+ lp->pending_tx_skb = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *smc911x_query_statistics(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+
+ return &lp->stats;
+}
+
+/*
+ * Ethtool support
+ */
+static int
+smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int ret, status;
+ unsigned long flags;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+ cmd->maxtxpkt = 1;
+ cmd->maxrxpkt = 1;
+
+ if (lp->phy_type != 0) {
+ spin_lock_irqsave(&lp->lock, flags);
+ ret = mii_ethtool_gset(&lp->mii, cmd);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ } else {
+ cmd->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_TP | SUPPORTED_AUI;
+
+ if (lp->ctl_rspeed == 10)
+ cmd->speed = SPEED_10;
+ else if (lp->ctl_rspeed == 100)
+ cmd->speed = SPEED_100;
+
+ cmd->autoneg = AUTONEG_DISABLE;
+ if (lp->mii.phy_id==1)
+ cmd->transceiver = XCVR_INTERNAL;
+ else
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->port = 0;
+ SMC_GET_PHY_SPECIAL(lp->mii.phy_id, status);
+ cmd->duplex =
+ (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int
+smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ int ret;
+ unsigned long flags;
+
+ if (lp->phy_type != 0) {
+ spin_lock_irqsave(&lp->lock, flags);
+ ret = mii_ethtool_sset(&lp->mii, cmd);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ } else {
+ if (cmd->autoneg != AUTONEG_DISABLE ||
+ cmd->speed != SPEED_10 ||
+ (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||
+ (cmd->port != PORT_TP && cmd->port != PORT_AUI))
+ return -EINVAL;
+
+ lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void
+smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strncpy(info->driver, CARDNAME, sizeof(info->driver));
+ strncpy(info->version, version, sizeof(info->version));
+ strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+}
+
+static int smc911x_ethtool_nwayreset(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ int ret = -EINVAL;
+ unsigned long flags;
+
+ if (lp->phy_type != 0) {
+ spin_lock_irqsave(&lp->lock, flags);
+ ret = mii_nway_restart(&lp->mii);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+
+ return ret;
+}
+
+static u32 smc911x_ethtool_getmsglevel(struct net_device *dev)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ return lp->msg_enable;
+}
+
+static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ lp->msg_enable = level;
+}
+
+static int smc911x_ethtool_getregslen(struct net_device *dev)
+{
+ /* System regs + MAC regs + PHY regs */
+ return (((E2P_CMD - ID_REV)/4 + 1) +
+ (WUCSR - MAC_CR)+1 + 32) * sizeof(u32);
+}
+
+static void smc911x_ethtool_getregs(struct net_device *dev,
+ struct ethtool_regs* regs, void *buf)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
+ unsigned long flags;
+ u32 reg,i,j=0;
+ u32 *data = (u32*)buf;
+
+ regs->version = lp->version;
+ for(i=ID_REV;i<=E2P_CMD;i+=4) {
+ data[j++] = SMC_inl(ioaddr,i);
+ }
+ for(i=MAC_CR;i<=WUCSR;i++) {
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_GET_MAC_CSR(i, reg);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ data[j++] = reg;
+ }
+ for(i=0;i<=31;i++) {
+ spin_lock_irqsave(&lp->lock, flags);
+ SMC_GET_MII(i, lp->mii.phy_id, reg);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ data[j++] = reg & 0xFFFF;
+ }
+}
+
+static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int timeout;
+ int e2p_cmd;
+
+ e2p_cmd = SMC_GET_E2P_CMD();
+ for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {
+ if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {
+ PRINTK("%s: %s timeout waiting for EEPROM to respond\n",
+ dev->name, __FUNCTION__);
+ return -EFAULT;
+ }
+ mdelay(1);
+ e2p_cmd = SMC_GET_E2P_CMD();
+ }
+ if (timeout == 0) {
+ PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",
+ dev->name, __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev,
+ int cmd, int addr)
+{
+ unsigned long ioaddr = dev->base_addr;
+ int ret;
+
+ if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+ return ret;
+ SMC_SET_E2P_CMD(E2P_CMD_EPC_BUSY_ |
+ ((cmd) & (0x7<<28)) |
+ ((addr) & 0xFF));
+ return 0;
+}
+
+static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev,
+ u8 *data)
+{
+ unsigned long ioaddr = dev->base_addr;
+ int ret;
+
+ if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+ return ret;
+ *data = SMC_GET_E2P_DATA();
+ return 0;
+}
+
+static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev,
+ u8 data)
+{
+ unsigned long ioaddr = dev->base_addr;
+ int ret;
+
+ if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+ return ret;
+ SMC_SET_E2P_DATA(data);
+ return 0;
+}
+
+static int smc911x_ethtool_geteeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ u8 eebuf[SMC911X_EEPROM_LEN];
+ int i, ret;
+
+ for(i=0;i<SMC911X_EEPROM_LEN;i++) {
+ if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0)
+ return ret;
+ if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
+ return ret;
+ }
+ memcpy(data, eebuf+eeprom->offset, eeprom->len);
+ return 0;
+}
+
+static int smc911x_ethtool_seteeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ int i, ret;
+
+ /* Enable erase */
+ if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0)
+ return ret;
+ for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) {
+ /* erase byte */
+ if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0)
+ return ret;
+ /* write byte */
+ if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
+ return ret;
+ if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
+ return ret;
+ }
+ return 0;
+}
+
+static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
+{
+ return SMC911X_EEPROM_LEN;
+}
+
+static struct ethtool_ops smc911x_ethtool_ops = {
+ .get_settings = smc911x_ethtool_getsettings,
+ .set_settings = smc911x_ethtool_setsettings,
+ .get_drvinfo = smc911x_ethtool_getdrvinfo,
+ .get_msglevel = smc911x_ethtool_getmsglevel,
+ .set_msglevel = smc911x_ethtool_setmsglevel,
+ .nway_reset = smc911x_ethtool_nwayreset,
+ .get_link = ethtool_op_get_link,
+ .get_regs_len = smc911x_ethtool_getregslen,
+ .get_regs = smc911x_ethtool_getregs,
+ .get_eeprom_len = smc911x_ethtool_geteeprom_len,
+ .get_eeprom = smc911x_ethtool_geteeprom,
+ .set_eeprom = smc911x_ethtool_seteeprom,
+};
+
+/*
+ * smc911x_findirq
+ *
+ * This routine has a simple purpose -- make the SMC chip generate an
+ * interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ */
+static int __init smc911x_findirq(unsigned long ioaddr)
+{
+ int timeout = 20;
+ unsigned long cookie;
+
+ DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+
+ cookie = probe_irq_on();
+
+ /*
+ * Force a SW interrupt
+ */
+
+ SMC_SET_INT_EN(INT_EN_SW_INT_EN_);
+
+ /*
+ * Wait until positive that the interrupt has been generated
+ */
+ do {
+ int int_status;
+ udelay(10);
+ int_status = SMC_GET_INT_EN();
+ if (int_status & INT_EN_SW_INT_EN_)
+ break; /* got the interrupt */
+ } while (--timeout);
+
+ /*
+ * there is really nothing that I can do here if timeout fails,
+ * as autoirq_report will return a 0 anyway, which is what I
+ * want in this case. Plus, the clean up is needed in both
+ * cases.
+ */
+
+ /* and disable all interrupts again */
+ SMC_SET_INT_EN(0);
+
+ /* and return what I found */
+ return probe_irq_off(cookie);
+}
+
+/*
+ * Function: smc911x_probe(unsigned long ioaddr)
+ *
+ * Purpose:
+ * Tests to see if a given ioaddr points to an SMC911x chip.
+ * Returns a 0 on success
+ *
+ * Algorithm:
+ * (1) see if the endian word is OK
+ * (1) see if I recognize the chip ID in the appropriate register
+ *
+ * Here I do typical initialization tasks.
+ *
+ * o Initialize the structure if needed
+ * o print out my vanity message if not done so already
+ * o print out what type of hardware is detected
+ * o print out the ethernet address
+ * o find the IRQ
+ * o set up my private data
+ * o configure the dev structure with my subroutines
+ * o actually GRAB the irq.
+ * o GRAB the region
+ */
+static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
+{
+ struct smc911x_local *lp = netdev_priv(dev);
+ int i, retval;
+ unsigned int val, chip_id, revision;
+ const char *version_string;
+
+ DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
+
+ /* First, see if the endian word is recognized */
+ val = SMC_GET_BYTE_TEST();
+ DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val);
+ if (val != 0x87654321) {
+ printk(KERN_ERR "Invalid chip endian 0x08%x\n",val);
+ retval = -ENODEV;
+ goto err_out;
+ }
+
+ /*
+ * check if the revision register is something that I
+ * recognize. These might need to be added to later,
+ * as future revisions could be added.
+ */
+ chip_id = SMC_GET_PN();
+ DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id);
+ for(i=0;chip_ids[i].id != 0; i++) {
+ if (chip_ids[i].id == chip_id) break;
+ }
+ if (!chip_ids[i].id) {
+ printk(KERN_ERR "Unknown chip ID %04x\n", chip_id);
+ retval = -ENODEV;
+ goto err_out;
+ }
+ version_string = chip_ids[i].name;
+
+ revision = SMC_GET_REV();
+ DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision);
+
+ /* At this point I'll assume that the chip is an SMC911x. */
+ DBG(SMC_DEBUG_MISC, "%s: Found a %s\n", CARDNAME, chip_ids[i].name);
+
+ /* Validate the TX FIFO size requested */
+ if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) {
+ printk(KERN_ERR "Invalid TX FIFO size requested %d\n", tx_fifo_kb);
+ retval = -EINVAL;
+ goto err_out;
+ }
+
+ /* fill in some of the fields */
+ dev->base_addr = ioaddr;
+ lp->version = chip_ids[i].id;
+ lp->revision = revision;
+ lp->tx_fifo_kb = tx_fifo_kb;
+ /* Reverse calculate the RX FIFO size from the TX */
+ lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512;
+ lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15;
+
+ /* Set the automatic flow control values */
+ switch(lp->tx_fifo_kb) {
+ /*
+ * AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
+ * AFC_LO is AFC_HI/2
+ * BACK_DUR is about 5uS*(AFC_LO) rounded down
+ */
+ case 2:/* 13440 Rx Data Fifo Size */
+ lp->afc_cfg=0x008C46AF;break;
+ case 3:/* 12480 Rx Data Fifo Size */
+ lp->afc_cfg=0x0082419F;break;
+ case 4:/* 11520 Rx Data Fifo Size */
+ lp->afc_cfg=0x00783C9F;break;
+ case 5:/* 10560 Rx Data Fifo Size */
+ lp->afc_cfg=0x006E374F;break;
+ case 6:/* 9600 Rx Data Fifo Size */
+ lp->afc_cfg=0x0064328F;break;
+ case 7:/* 8640 Rx Data Fifo Size */
+ lp->afc_cfg=0x005A2D7F;break;
+ case 8:/* 7680 Rx Data Fifo Size */
+ lp->afc_cfg=0x0050287F;break;
+ case 9:/* 6720 Rx Data Fifo Size */
+ lp->afc_cfg=0x0046236F;break;
+ case 10:/* 5760 Rx Data Fifo Size */
+ lp->afc_cfg=0x003C1E6F;break;
+ case 11:/* 4800 Rx Data Fifo Size */
+ lp->afc_cfg=0x0032195F;break;
+ /*
+ * AFC_HI is ~1520 bytes less than RX Data Fifo Size
+ * AFC_LO is AFC_HI/2
+ * BACK_DUR is about 5uS*(AFC_LO) rounded down
+ */
+ case 12:/* 3840 Rx Data Fifo Size */
+ lp->afc_cfg=0x0024124F;break;
+ case 13:/* 2880 Rx Data Fifo Size */
+ lp->afc_cfg=0x0015073F;break;
+ case 14:/* 1920 Rx Data Fifo Size */
+ lp->afc_cfg=0x0006032F;break;
+ default:
+ PRINTK("%s: ERROR -- no AFC_CFG setting found",
+ dev->name);
+ break;
+ }
+
+ DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX,
+ "%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME,
+ lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg);
+
+ spin_lock_init(&lp->lock);
+
+ /* Get the MAC address */
+ SMC_GET_MAC_ADDR(dev->dev_addr);
+
+ /* now, reset the chip, and put it into a known state */
+ smc911x_reset(dev);
+
+ /*
+ * If dev->irq is 0, then the device has to be banged on to see
+ * what the IRQ is.
+ *
+ * Specifying an IRQ is done with the assumption that the user knows
+ * what (s)he is doing. No checking is done!!!!
+ */
+ if (dev->irq < 1) {
+ int trials;
+
+ trials = 3;
+ while (trials--) {
+ dev->irq = smc911x_findirq(ioaddr);
+ if (dev->irq)
+ break;
+ /* kick the card and try again */
+ smc911x_reset(dev);
+ }
+ }
+ if (dev->irq == 0) {
+ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+ dev->name);
+ retval = -ENODEV;
+ goto err_out;
+ }
+ dev->irq = irq_canonicalize(dev->irq);
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+
+ dev->open = smc911x_open;
+ dev->stop = smc911x_close;
+ dev->hard_start_xmit = smc911x_hard_start_xmit;
+ dev->tx_timeout = smc911x_timeout;
+ dev->watchdog_timeo = msecs_to_jiffies(watchdog);
+ dev->get_stats = smc911x_query_statistics;
+ dev->set_multicast_list = smc911x_set_multicast_list;
+ dev->ethtool_ops = &smc911x_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = smc911x_poll_controller;
+#endif
+
+ INIT_WORK(&lp->phy_configure, smc911x_phy_configure, dev);
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
+ lp->mii.force_media = 0;
+ lp->mii.full_duplex = 0;
+ lp->mii.dev = dev;
+ lp->mii.mdio_read = smc911x_phy_read;
+ lp->mii.mdio_write = smc911x_phy_write;
+
+ /*
+ * Locate the phy, if any.
+ */
+ smc911x_phy_detect(dev);
+
+ /* Set default parameters */
+ lp->msg_enable = NETIF_MSG_LINK;
+ lp->ctl_rfduplx = 1;
+ lp->ctl_rspeed = 100;
+
+ /* Grab the IRQ */
+ retval = request_irq(dev->irq, &smc911x_interrupt, SA_SHIRQ, dev->name, dev);
+ if (retval)
+ goto err_out;
+
+ set_irq_type(dev->irq, IRQT_FALLING);
+
+#ifdef SMC_USE_DMA
+ lp->rxdma = SMC_DMA_REQUEST(dev, smc911x_rx_dma_irq);
+ lp->txdma = SMC_DMA_REQUEST(dev, smc911x_tx_dma_irq);
+ lp->rxdma_active = 0;
+ lp->txdma_active = 0;
+ dev->dma = lp->rxdma;
+#endif
+
+ retval = register_netdev(dev);
+ if (retval == 0) {
+ /* now, print out the card info, in a short format.. */
+ printk("%s: %s (rev %d) at %#lx IRQ %d",
+ dev->name, version_string, lp->revision,
+ dev->base_addr, dev->irq);
+
+#ifdef SMC_USE_DMA
+ if (lp->rxdma != -1)
+ printk(" RXDMA %d ", lp->rxdma);
+
+ if (lp->txdma != -1)
+ printk("TXDMA %d", lp->txdma);
+#endif
+ printk("\n");
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk("%s: Invalid ethernet MAC address. Please "
+ "set using ifconfig\n", dev->name);
+ } else {
+ /* Print the Ethernet address */
+ printk("%s: Ethernet addr: ", dev->name);
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x\n", dev->dev_addr[5]);
+ }
+
+ if (lp->phy_type == 0) {
+ PRINTK("%s: No PHY found\n", dev->name);
+ } else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) {
+ PRINTK("%s: LAN911x Internal PHY\n", dev->name);
+ } else {
+ PRINTK("%s: External PHY 0x%08x\n", dev->name, lp->phy_type);
+ }
+ }
+
+err_out:
+#ifdef SMC_USE_DMA
+ if (retval) {
+ if (lp->rxdma != -1) {
+ SMC_DMA_FREE(dev, lp->rxdma);
+ }
+ if (lp->txdma != -1) {
+ SMC_DMA_FREE(dev, lp->txdma);
+ }
+ }
+#endif
+ return retval;
+}
+
+/*
+ * smc911x_init(void)
+ *
+ * Output:
+ * 0 --> there is a device
+ * anything else, error
+ */
+static int smc911x_drv_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev;
+ struct resource *res;
+ unsigned int *addr;
+ int ret;
+
+ DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /*
+ * Request the regions.
+ */
+ if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct smc911x_local));
+ if (!ndev) {
+ printk("%s: could not allocate device.\n", CARDNAME);
+ ret = -ENOMEM;
+ goto release_1;
+ }
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ ndev->dma = (unsigned char)-1;
+ ndev->irq = platform_get_irq(pdev, 0);
+
+ addr = ioremap(res->start, SMC911X_IO_EXTENT);
+ if (!addr) {
+ ret = -ENOMEM;
+ goto release_both;
+ }
+
+ platform_set_drvdata(pdev, ndev);
+ ret = smc911x_probe(ndev, (unsigned long)addr);
+ if (ret != 0) {
+ platform_set_drvdata(pdev, NULL);
+ iounmap(addr);
+release_both:
+ free_netdev(ndev);
+release_1:
+ release_mem_region(res->start, SMC911X_IO_EXTENT);
+out:
+ printk("%s: not found (%d).\n", CARDNAME, ret);
+ }
+#ifdef SMC_USE_DMA
+ else {
+ struct smc911x_local *lp = netdev_priv(ndev);
+ lp->physaddr = res->start;
+ lp->dev = &pdev->dev;
+ }
+#endif
+
+ return ret;
+}
+
+static int smc911x_drv_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(ndev);
+
+ free_irq(ndev->irq, ndev);
+
+#ifdef SMC_USE_DMA
+ {
+ struct smc911x_local *lp = netdev_priv(ndev);
+ if (lp->rxdma != -1) {
+ SMC_DMA_FREE(dev, lp->rxdma);
+ }
+ if (lp->txdma != -1) {
+ SMC_DMA_FREE(dev, lp->txdma);
+ }
+ }
+#endif
+ iounmap((void *)ndev->base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, SMC911X_IO_EXTENT);
+
+ free_netdev(ndev);
+ return 0;
+}
+
+static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct net_device *ndev = platform_get_drvdata(dev);
+ unsigned long ioaddr = ndev->base_addr;
+
+ DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+ if (ndev) {
+ if (netif_running(ndev)) {
+ netif_device_detach(ndev);
+ smc911x_shutdown(ndev);
+#if POWER_DOWN
+ /* Set D2 - Energy detect only setting */
+ SMC_SET_PMT_CTRL(2<<12);
+#endif
+ }
+ }
+ return 0;
+}
+
+static int smc911x_drv_resume(struct platform_device *dev)
+{
+ struct net_device *ndev = platform_get_drvdata(dev);
+
+ DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
+ if (ndev) {
+ struct smc911x_local *lp = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ smc911x_reset(ndev);
+ smc911x_enable(ndev);
+ if (lp->phy_type != 0)
+ smc911x_phy_configure(ndev);
+ netif_device_attach(ndev);
+ }
+ }
+ return 0;
+}
+
+static struct platform_driver smc911x_driver = {
+ .probe = smc911x_drv_probe,
+ .remove = smc911x_drv_remove,
+ .suspend = smc911x_drv_suspend,
+ .resume = smc911x_drv_resume,
+ .driver = {
+ .name = CARDNAME,
+ },
+};
+
+static int __init smc911x_init(void)
+{
+ return platform_driver_register(&smc911x_driver);
+}
+
+static void __exit smc911x_cleanup(void)
+{
+ platform_driver_unregister(&smc911x_driver);
+}
+
+module_init(smc911x_init);
+module_exit(smc911x_cleanup);
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
new file mode 100644
index 000000000000..962a710459fc
--- /dev/null
+++ b/drivers/net/smc911x.h
@@ -0,0 +1,835 @@
+/*------------------------------------------------------------------------
+ . smc911x.h - macros for SMSC's LAN911{5,6,7,8} single-chip Ethernet device.
+ .
+ . Copyright (C) 2005 Sensoria Corp.
+ . Derived from the unified SMC91x driver 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 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
+ .
+ . Information contained in this file was obtained from the LAN9118
+ . manual from SMC. To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ . Dustin McIntire <dustin@sensoria.com>
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC911X_H_
+#define _SMC911X_H_
+
+/*
+ * Use the DMA feature on PXA chips
+ */
+#ifdef CONFIG_ARCH_PXA
+ #define SMC_USE_PXA_DMA 1
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+#endif
+
+
+/*
+ * Define the bus width specific IO macros
+ */
+
+#if SMC_USE_16BIT
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) \
+ do{ \
+ writel(v & 0xFFFF, (a) + (r)); \
+ writel(v >> 16, (a) + (r) + 2); \
+ } while (0)
+#define SMC_insl(a, r, p, l) readsw((short*)((a) + (r)), p, l*2)
+#define SMC_outsl(a, r, p, l) writesw((short*)((a) + (r)), p, l*2)
+
+#elif SMC_USE_32BIT
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((int*)((a) + (r)), p, l)
+#define SMC_outsl(a, r, p, l) writesl((int*)((a) + (r)), p, l)
+
+#endif /* SMC_USE_16BIT */
+
+
+
+#if SMC_USE_PXA_DMA
+#define SMC_USE_DMA
+
+/*
+ * Define the request and free functions
+ * These are unfortunately architecture specific as no generic allocation
+ * mechanism exits
+ */
+#define SMC_DMA_REQUEST(dev, handler) \
+ pxa_request_dma(dev->name, DMA_PRIO_LOW, handler, dev)
+
+#define SMC_DMA_FREE(dev, dma) \
+ pxa_free_dma(dma)
+
+#define SMC_DMA_ACK_IRQ(dev, dma) \
+{ \
+ if (DCSR(dma) & DCSR_BUSERR) { \
+ printk("%s: DMA %d bus error!\n", dev->name, dma); \
+ } \
+ DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; \
+}
+
+/*
+ * Use a DMA for RX and TX packets.
+ */
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <asm/arch/pxa-regs.h>
+
+static dma_addr_t rx_dmabuf, tx_dmabuf;
+static int rx_dmalen, tx_dmalen;
+
+#ifdef SMC_insl
+#undef SMC_insl
+#define SMC_insl(a, r, p, l) \
+ smc_pxa_dma_insl(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
+
+static inline void
+smc_pxa_dma_insl(struct device *dev, u_long ioaddr, u_long physaddr,
+ int reg, int dma, u_char *buf, int len)
+{
+ /* 64 bit alignment is required for memory to memory DMA */
+ if ((long)buf & 4) {
+ *((u32 *)buf) = SMC_inl(ioaddr, reg);
+ buf += 4;
+ len--;
+ }
+
+ len *= 4;
+ rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
+ rx_dmalen = len;
+ DCSR(dma) = DCSR_NODESC;
+ DTADR(dma) = rx_dmabuf;
+ DSADR(dma) = physaddr + reg;
+ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+ DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
+ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+
+#ifdef SMC_insw
+#undef SMC_insw
+#define SMC_insw(a, r, p, l) \
+ smc_pxa_dma_insw(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
+
+static inline void
+smc_pxa_dma_insw(struct device *dev, u_long ioaddr, u_long physaddr,
+ int reg, int dma, u_char *buf, int len)
+{
+ /* 64 bit alignment is required for memory to memory DMA */
+ while ((long)buf & 6) {
+ *((u16 *)buf) = SMC_inw(ioaddr, reg);
+ buf += 2;
+ len--;
+ }
+
+ len *= 2;
+ rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
+ rx_dmalen = len;
+ DCSR(dma) = DCSR_NODESC;
+ DTADR(dma) = rx_dmabuf;
+ DSADR(dma) = physaddr + reg;
+ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+ DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
+ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+
+#ifdef SMC_outsl
+#undef SMC_outsl
+#define SMC_outsl(a, r, p, l) \
+ smc_pxa_dma_outsl(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
+
+static inline void
+smc_pxa_dma_outsl(struct device *dev, u_long ioaddr, u_long physaddr,
+ int reg, int dma, u_char *buf, int len)
+{
+ /* 64 bit alignment is required for memory to memory DMA */
+ if ((long)buf & 4) {
+ SMC_outl(*((u32 *)buf), ioaddr, reg);
+ buf += 4;
+ len--;
+ }
+
+ len *= 4;
+ tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
+ tx_dmalen = len;
+ DCSR(dma) = DCSR_NODESC;
+ DSADR(dma) = tx_dmabuf;
+ DTADR(dma) = physaddr + reg;
+ DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
+ DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
+ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+
+#ifdef SMC_outsw
+#undef SMC_outsw
+#define SMC_outsw(a, r, p, l) \
+ smc_pxa_dma_outsw(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
+
+static inline void
+smc_pxa_dma_outsw(struct device *dev, u_long ioaddr, u_long physaddr,
+ int reg, int dma, u_char *buf, int len)
+{
+ /* 64 bit alignment is required for memory to memory DMA */
+ while ((long)buf & 6) {
+ SMC_outw(*((u16 *)buf), ioaddr, reg);
+ buf += 2;
+ len--;
+ }
+
+ len *= 2;
+ tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
+ tx_dmalen = len;
+ DCSR(dma) = DCSR_NODESC;
+ DSADR(dma) = tx_dmabuf;
+ DTADR(dma) = physaddr + reg;
+ DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
+ DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
+ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+
+#endif /* SMC_USE_PXA_DMA */
+
+
+/* Chip Parameters and Register Definitions */
+
+#define SMC911X_TX_FIFO_LOW_THRESHOLD (1536*2)
+
+#define SMC911X_IO_EXTENT 0x100
+
+#define SMC911X_EEPROM_LEN 7
+
+/* Below are the register offsets and bit definitions
+ * of the Lan911x memory space
+ */
+#define RX_DATA_FIFO (0x00)
+
+#define TX_DATA_FIFO (0x20)
+#define TX_CMD_A_INT_ON_COMP_ (0x80000000)
+#define TX_CMD_A_INT_BUF_END_ALGN_ (0x03000000)
+#define TX_CMD_A_INT_4_BYTE_ALGN_ (0x00000000)
+#define TX_CMD_A_INT_16_BYTE_ALGN_ (0x01000000)
+#define TX_CMD_A_INT_32_BYTE_ALGN_ (0x02000000)
+#define TX_CMD_A_INT_DATA_OFFSET_ (0x001F0000)
+#define TX_CMD_A_INT_FIRST_SEG_ (0x00002000)
+#define TX_CMD_A_INT_LAST_SEG_ (0x00001000)
+#define TX_CMD_A_BUF_SIZE_ (0x000007FF)
+#define TX_CMD_B_PKT_TAG_ (0xFFFF0000)
+#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000)
+#define TX_CMD_B_DISABLE_PADDING_ (0x00001000)
+#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF)
+
+#define RX_STATUS_FIFO (0x40)
+#define RX_STS_PKT_LEN_ (0x3FFF0000)
+#define RX_STS_ES_ (0x00008000)
+#define RX_STS_BCST_ (0x00002000)
+#define RX_STS_LEN_ERR_ (0x00001000)
+#define RX_STS_RUNT_ERR_ (0x00000800)
+#define RX_STS_MCAST_ (0x00000400)
+#define RX_STS_TOO_LONG_ (0x00000080)
+#define RX_STS_COLL_ (0x00000040)
+#define RX_STS_ETH_TYPE_ (0x00000020)
+#define RX_STS_WDOG_TMT_ (0x00000010)
+#define RX_STS_MII_ERR_ (0x00000008)
+#define RX_STS_DRIBBLING_ (0x00000004)
+#define RX_STS_CRC_ERR_ (0x00000002)
+#define RX_STATUS_FIFO_PEEK (0x44)
+#define TX_STATUS_FIFO (0x48)
+#define TX_STS_TAG_ (0xFFFF0000)
+#define TX_STS_ES_ (0x00008000)
+#define TX_STS_LOC_ (0x00000800)
+#define TX_STS_NO_CARR_ (0x00000400)
+#define TX_STS_LATE_COLL_ (0x00000200)
+#define TX_STS_MANY_COLL_ (0x00000100)
+#define TX_STS_COLL_CNT_ (0x00000078)
+#define TX_STS_MANY_DEFER_ (0x00000004)
+#define TX_STS_UNDERRUN_ (0x00000002)
+#define TX_STS_DEFERRED_ (0x00000001)
+#define TX_STATUS_FIFO_PEEK (0x4C)
+#define ID_REV (0x50)
+#define ID_REV_CHIP_ID_ (0xFFFF0000) /* RO */
+#define ID_REV_REV_ID_ (0x0000FFFF) /* RO */
+
+#define INT_CFG (0x54)
+#define INT_CFG_INT_DEAS_ (0xFF000000) /* R/W */
+#define INT_CFG_INT_DEAS_CLR_ (0x00004000)
+#define INT_CFG_INT_DEAS_STS_ (0x00002000)
+#define INT_CFG_IRQ_INT_ (0x00001000) /* RO */
+#define INT_CFG_IRQ_EN_ (0x00000100) /* R/W */
+#define INT_CFG_IRQ_POL_ (0x00000010) /* R/W Not Affected by SW Reset */
+#define INT_CFG_IRQ_TYPE_ (0x00000001) /* R/W Not Affected by SW Reset */
+
+#define INT_STS (0x58)
+#define INT_STS_SW_INT_ (0x80000000) /* R/WC */
+#define INT_STS_TXSTOP_INT_ (0x02000000) /* R/WC */
+#define INT_STS_RXSTOP_INT_ (0x01000000) /* R/WC */
+#define INT_STS_RXDFH_INT_ (0x00800000) /* R/WC */
+#define INT_STS_RXDF_INT_ (0x00400000) /* R/WC */
+#define INT_STS_TX_IOC_ (0x00200000) /* R/WC */
+#define INT_STS_RXD_INT_ (0x00100000) /* R/WC */
+#define INT_STS_GPT_INT_ (0x00080000) /* R/WC */
+#define INT_STS_PHY_INT_ (0x00040000) /* RO */
+#define INT_STS_PME_INT_ (0x00020000) /* R/WC */
+#define INT_STS_TXSO_ (0x00010000) /* R/WC */
+#define INT_STS_RWT_ (0x00008000) /* R/WC */
+#define INT_STS_RXE_ (0x00004000) /* R/WC */
+#define INT_STS_TXE_ (0x00002000) /* R/WC */
+//#define INT_STS_ERX_ (0x00001000) /* R/WC */
+#define INT_STS_TDFU_ (0x00000800) /* R/WC */
+#define INT_STS_TDFO_ (0x00000400) /* R/WC */
+#define INT_STS_TDFA_ (0x00000200) /* R/WC */
+#define INT_STS_TSFF_ (0x00000100) /* R/WC */
+#define INT_STS_TSFL_ (0x00000080) /* R/WC */
+//#define INT_STS_RXDF_ (0x00000040) /* R/WC */
+#define INT_STS_RDFO_ (0x00000040) /* R/WC */
+#define INT_STS_RDFL_ (0x00000020) /* R/WC */
+#define INT_STS_RSFF_ (0x00000010) /* R/WC */
+#define INT_STS_RSFL_ (0x00000008) /* R/WC */
+#define INT_STS_GPIO2_INT_ (0x00000004) /* R/WC */
+#define INT_STS_GPIO1_INT_ (0x00000002) /* R/WC */
+#define INT_STS_GPIO0_INT_ (0x00000001) /* R/WC */
+
+#define INT_EN (0x5C)
+#define INT_EN_SW_INT_EN_ (0x80000000) /* R/W */
+#define INT_EN_TXSTOP_INT_EN_ (0x02000000) /* R/W */
+#define INT_EN_RXSTOP_INT_EN_ (0x01000000) /* R/W */
+#define INT_EN_RXDFH_INT_EN_ (0x00800000) /* R/W */
+//#define INT_EN_RXDF_INT_EN_ (0x00400000) /* R/W */
+#define INT_EN_TIOC_INT_EN_ (0x00200000) /* R/W */
+#define INT_EN_RXD_INT_EN_ (0x00100000) /* R/W */
+#define INT_EN_GPT_INT_EN_ (0x00080000) /* R/W */
+#define INT_EN_PHY_INT_EN_ (0x00040000) /* R/W */
+#define INT_EN_PME_INT_EN_ (0x00020000) /* R/W */
+#define INT_EN_TXSO_EN_ (0x00010000) /* R/W */
+#define INT_EN_RWT_EN_ (0x00008000) /* R/W */
+#define INT_EN_RXE_EN_ (0x00004000) /* R/W */
+#define INT_EN_TXE_EN_ (0x00002000) /* R/W */
+//#define INT_EN_ERX_EN_ (0x00001000) /* R/W */
+#define INT_EN_TDFU_EN_ (0x00000800) /* R/W */
+#define INT_EN_TDFO_EN_ (0x00000400) /* R/W */
+#define INT_EN_TDFA_EN_ (0x00000200) /* R/W */
+#define INT_EN_TSFF_EN_ (0x00000100) /* R/W */
+#define INT_EN_TSFL_EN_ (0x00000080) /* R/W */
+//#define INT_EN_RXDF_EN_ (0x00000040) /* R/W */
+#define INT_EN_RDFO_EN_ (0x00000040) /* R/W */
+#define INT_EN_RDFL_EN_ (0x00000020) /* R/W */
+#define INT_EN_RSFF_EN_ (0x00000010) /* R/W */
+#define INT_EN_RSFL_EN_ (0x00000008) /* R/W */
+#define INT_EN_GPIO2_INT_ (0x00000004) /* R/W */
+#define INT_EN_GPIO1_INT_ (0x00000002) /* R/W */
+#define INT_EN_GPIO0_INT_ (0x00000001) /* R/W */
+
+#define BYTE_TEST (0x64)
+#define FIFO_INT (0x68)
+#define FIFO_INT_TX_AVAIL_LEVEL_ (0xFF000000) /* R/W */
+#define FIFO_INT_TX_STS_LEVEL_ (0x00FF0000) /* R/W */
+#define FIFO_INT_RX_AVAIL_LEVEL_ (0x0000FF00) /* R/W */
+#define FIFO_INT_RX_STS_LEVEL_ (0x000000FF) /* R/W */
+
+#define RX_CFG (0x6C)
+#define RX_CFG_RX_END_ALGN_ (0xC0000000) /* R/W */
+#define RX_CFG_RX_END_ALGN4_ (0x00000000) /* R/W */
+#define RX_CFG_RX_END_ALGN16_ (0x40000000) /* R/W */
+#define RX_CFG_RX_END_ALGN32_ (0x80000000) /* R/W */
+#define RX_CFG_RX_DMA_CNT_ (0x0FFF0000) /* R/W */
+#define RX_CFG_RX_DUMP_ (0x00008000) /* R/W */
+#define RX_CFG_RXDOFF_ (0x00001F00) /* R/W */
+//#define RX_CFG_RXBAD_ (0x00000001) /* R/W */
+
+#define TX_CFG (0x70)
+//#define TX_CFG_TX_DMA_LVL_ (0xE0000000) /* R/W */
+//#define TX_CFG_TX_DMA_CNT_ (0x0FFF0000) /* R/W Self Clearing */
+#define TX_CFG_TXS_DUMP_ (0x00008000) /* Self Clearing */
+#define TX_CFG_TXD_DUMP_ (0x00004000) /* Self Clearing */
+#define TX_CFG_TXSAO_ (0x00000004) /* R/W */
+#define TX_CFG_TX_ON_ (0x00000002) /* R/W */
+#define TX_CFG_STOP_TX_ (0x00000001) /* Self Clearing */
+
+#define HW_CFG (0x74)
+#define HW_CFG_TTM_ (0x00200000) /* R/W */
+#define HW_CFG_SF_ (0x00100000) /* R/W */
+#define HW_CFG_TX_FIF_SZ_ (0x000F0000) /* R/W */
+#define HW_CFG_TR_ (0x00003000) /* R/W */
+#define HW_CFG_PHY_CLK_SEL_ (0x00000060) /* R/W */
+#define HW_CFG_PHY_CLK_SEL_INT_PHY_ (0x00000000) /* R/W */
+#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ (0x00000020) /* R/W */
+#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ (0x00000040) /* R/W */
+#define HW_CFG_SMI_SEL_ (0x00000010) /* R/W */
+#define HW_CFG_EXT_PHY_DET_ (0x00000008) /* RO */
+#define HW_CFG_EXT_PHY_EN_ (0x00000004) /* R/W */
+#define HW_CFG_32_16_BIT_MODE_ (0x00000004) /* RO */
+#define HW_CFG_SRST_TO_ (0x00000002) /* RO */
+#define HW_CFG_SRST_ (0x00000001) /* Self Clearing */
+
+#define RX_DP_CTRL (0x78)
+#define RX_DP_CTRL_RX_FFWD_ (0x80000000) /* R/W */
+#define RX_DP_CTRL_FFWD_BUSY_ (0x80000000) /* RO */
+
+#define RX_FIFO_INF (0x7C)
+#define RX_FIFO_INF_RXSUSED_ (0x00FF0000) /* RO */
+#define RX_FIFO_INF_RXDUSED_ (0x0000FFFF) /* RO */
+
+#define TX_FIFO_INF (0x80)
+#define TX_FIFO_INF_TSUSED_ (0x00FF0000) /* RO */
+#define TX_FIFO_INF_TDFREE_ (0x0000FFFF) /* RO */
+
+#define PMT_CTRL (0x84)
+#define PMT_CTRL_PM_MODE_ (0x00003000) /* Self Clearing */
+#define PMT_CTRL_PHY_RST_ (0x00000400) /* Self Clearing */
+#define PMT_CTRL_WOL_EN_ (0x00000200) /* R/W */
+#define PMT_CTRL_ED_EN_ (0x00000100) /* R/W */
+#define PMT_CTRL_PME_TYPE_ (0x00000040) /* R/W Not Affected by SW Reset */
+#define PMT_CTRL_WUPS_ (0x00000030) /* R/WC */
+#define PMT_CTRL_WUPS_NOWAKE_ (0x00000000) /* R/WC */
+#define PMT_CTRL_WUPS_ED_ (0x00000010) /* R/WC */
+#define PMT_CTRL_WUPS_WOL_ (0x00000020) /* R/WC */
+#define PMT_CTRL_WUPS_MULTI_ (0x00000030) /* R/WC */
+#define PMT_CTRL_PME_IND_ (0x00000008) /* R/W */
+#define PMT_CTRL_PME_POL_ (0x00000004) /* R/W */
+#define PMT_CTRL_PME_EN_ (0x00000002) /* R/W Not Affected by SW Reset */
+#define PMT_CTRL_READY_ (0x00000001) /* RO */
+
+#define GPIO_CFG (0x88)
+#define GPIO_CFG_LED3_EN_ (0x40000000) /* R/W */
+#define GPIO_CFG_LED2_EN_ (0x20000000) /* R/W */
+#define GPIO_CFG_LED1_EN_ (0x10000000) /* R/W */
+#define GPIO_CFG_GPIO2_INT_POL_ (0x04000000) /* R/W */
+#define GPIO_CFG_GPIO1_INT_POL_ (0x02000000) /* R/W */
+#define GPIO_CFG_GPIO0_INT_POL_ (0x01000000) /* R/W */
+#define GPIO_CFG_EEPR_EN_ (0x00700000) /* R/W */
+#define GPIO_CFG_GPIOBUF2_ (0x00040000) /* R/W */
+#define GPIO_CFG_GPIOBUF1_ (0x00020000) /* R/W */
+#define GPIO_CFG_GPIOBUF0_ (0x00010000) /* R/W */
+#define GPIO_CFG_GPIODIR2_ (0x00000400) /* R/W */
+#define GPIO_CFG_GPIODIR1_ (0x00000200) /* R/W */
+#define GPIO_CFG_GPIODIR0_ (0x00000100) /* R/W */
+#define GPIO_CFG_GPIOD4_ (0x00000010) /* R/W */
+#define GPIO_CFG_GPIOD3_ (0x00000008) /* R/W */
+#define GPIO_CFG_GPIOD2_ (0x00000004) /* R/W */
+#define GPIO_CFG_GPIOD1_ (0x00000002) /* R/W */
+#define GPIO_CFG_GPIOD0_ (0x00000001) /* R/W */
+
+#define GPT_CFG (0x8C)
+#define GPT_CFG_TIMER_EN_ (0x20000000) /* R/W */
+#define GPT_CFG_GPT_LOAD_ (0x0000FFFF) /* R/W */
+
+#define GPT_CNT (0x90)
+#define GPT_CNT_GPT_CNT_ (0x0000FFFF) /* RO */
+
+#define ENDIAN (0x98)
+#define FREE_RUN (0x9C)
+#define RX_DROP (0xA0)
+#define MAC_CSR_CMD (0xA4)
+#define MAC_CSR_CMD_CSR_BUSY_ (0x80000000) /* Self Clearing */
+#define MAC_CSR_CMD_R_NOT_W_ (0x40000000) /* R/W */
+#define MAC_CSR_CMD_CSR_ADDR_ (0x000000FF) /* R/W */
+
+#define MAC_CSR_DATA (0xA8)
+#define AFC_CFG (0xAC)
+#define AFC_CFG_AFC_HI_ (0x00FF0000) /* R/W */
+#define AFC_CFG_AFC_LO_ (0x0000FF00) /* R/W */
+#define AFC_CFG_BACK_DUR_ (0x000000F0) /* R/W */
+#define AFC_CFG_FCMULT_ (0x00000008) /* R/W */
+#define AFC_CFG_FCBRD_ (0x00000004) /* R/W */
+#define AFC_CFG_FCADD_ (0x00000002) /* R/W */
+#define AFC_CFG_FCANY_ (0x00000001) /* R/W */
+
+#define E2P_CMD (0xB0)
+#define E2P_CMD_EPC_BUSY_ (0x80000000) /* Self Clearing */
+#define E2P_CMD_EPC_CMD_ (0x70000000) /* R/W */
+#define E2P_CMD_EPC_CMD_READ_ (0x00000000) /* R/W */
+#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) /* R/W */
+#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) /* R/W */
+#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) /* R/W */
+#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) /* R/W */
+#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) /* R/W */
+#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) /* R/W */
+#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) /* R/W */
+#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) /* RO */
+#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) /* RO */
+#define E2P_CMD_EPC_ADDR_ (0x000000FF) /* R/W */
+
+#define E2P_DATA (0xB4)
+#define E2P_DATA_EEPROM_DATA_ (0x000000FF) /* R/W */
+/* end of LAN register offsets and bit definitions */
+
+/*
+ ****************************************************************************
+ ****************************************************************************
+ * MAC Control and Status Register (Indirect Address)
+ * Offset (through the MAC_CSR CMD and DATA port)
+ ****************************************************************************
+ ****************************************************************************
+ *
+ */
+#define MAC_CR (0x01) /* R/W */
+
+/* MAC_CR - MAC Control Register */
+#define MAC_CR_RXALL_ (0x80000000)
+// TODO: delete this bit? It is not described in the data sheet.
+#define MAC_CR_HBDIS_ (0x10000000)
+#define MAC_CR_RCVOWN_ (0x00800000)
+#define MAC_CR_LOOPBK_ (0x00200000)
+#define MAC_CR_FDPX_ (0x00100000)
+#define MAC_CR_MCPAS_ (0x00080000)
+#define MAC_CR_PRMS_ (0x00040000)
+#define MAC_CR_INVFILT_ (0x00020000)
+#define MAC_CR_PASSBAD_ (0x00010000)
+#define MAC_CR_HFILT_ (0x00008000)
+#define MAC_CR_HPFILT_ (0x00002000)
+#define MAC_CR_LCOLL_ (0x00001000)
+#define MAC_CR_BCAST_ (0x00000800)
+#define MAC_CR_DISRTY_ (0x00000400)
+#define MAC_CR_PADSTR_ (0x00000100)
+#define MAC_CR_BOLMT_MASK_ (0x000000C0)
+#define MAC_CR_DFCHK_ (0x00000020)
+#define MAC_CR_TXEN_ (0x00000008)
+#define MAC_CR_RXEN_ (0x00000004)
+
+#define ADDRH (0x02) /* R/W mask 0x0000FFFFUL */
+#define ADDRL (0x03) /* R/W mask 0xFFFFFFFFUL */
+#define HASHH (0x04) /* R/W */
+#define HASHL (0x05) /* R/W */
+
+#define MII_ACC (0x06) /* R/W */
+#define MII_ACC_PHY_ADDR_ (0x0000F800)
+#define MII_ACC_MIIRINDA_ (0x000007C0)
+#define MII_ACC_MII_WRITE_ (0x00000002)
+#define MII_ACC_MII_BUSY_ (0x00000001)
+
+#define MII_DATA (0x07) /* R/W mask 0x0000FFFFUL */
+
+#define FLOW (0x08) /* R/W */
+#define FLOW_FCPT_ (0xFFFF0000)
+#define FLOW_FCPASS_ (0x00000004)
+#define FLOW_FCEN_ (0x00000002)
+#define FLOW_FCBSY_ (0x00000001)
+
+#define VLAN1 (0x09) /* R/W mask 0x0000FFFFUL */
+#define VLAN1_VTI1_ (0x0000ffff)
+
+#define VLAN2 (0x0A) /* R/W mask 0x0000FFFFUL */
+#define VLAN2_VTI2_ (0x0000ffff)
+
+#define WUFF (0x0B) /* WO */
+
+#define WUCSR (0x0C) /* R/W */
+#define WUCSR_GUE_ (0x00000200)
+#define WUCSR_WUFR_ (0x00000040)
+#define WUCSR_MPR_ (0x00000020)
+#define WUCSR_WAKE_EN_ (0x00000004)
+#define WUCSR_MPEN_ (0x00000002)
+
+/*
+ ****************************************************************************
+ * Chip Specific MII Defines
+ ****************************************************************************
+ *
+ * Phy register offsets and bit definitions
+ *
+ */
+
+#define PHY_MODE_CTRL_STS ((u32)17) /* Mode Control/Status Register */
+//#define MODE_CTRL_STS_FASTRIP_ ((u16)0x4000)
+#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000)
+//#define MODE_CTRL_STS_LOWSQEN_ ((u16)0x0800)
+//#define MODE_CTRL_STS_MDPREBP_ ((u16)0x0400)
+//#define MODE_CTRL_STS_FARLOOPBACK_ ((u16)0x0200)
+//#define MODE_CTRL_STS_FASTEST_ ((u16)0x0100)
+//#define MODE_CTRL_STS_REFCLKEN_ ((u16)0x0010)
+//#define MODE_CTRL_STS_PHYADBP_ ((u16)0x0008)
+//#define MODE_CTRL_STS_FORCE_G_LINK_ ((u16)0x0004)
+#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002)
+
+#define PHY_INT_SRC ((u32)29)
+#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080)
+#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040)
+#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020)
+#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010)
+#define PHY_INT_SRC_ANEG_LP_ACK_ ((u16)0x0008)
+#define PHY_INT_SRC_PAR_DET_FAULT_ ((u16)0x0004)
+#define PHY_INT_SRC_ANEG_PGRX_ ((u16)0x0002)
+
+#define PHY_INT_MASK ((u32)30)
+#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080)
+#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040)
+#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020)
+#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010)
+#define PHY_INT_MASK_ANEG_LP_ACK_ ((u16)0x0008)
+#define PHY_INT_MASK_PAR_DET_FAULT_ ((u16)0x0004)
+#define PHY_INT_MASK_ANEG_PGRX_ ((u16)0x0002)
+
+#define PHY_SPECIAL ((u32)31)
+#define PHY_SPECIAL_ANEG_DONE_ ((u16)0x1000)
+#define PHY_SPECIAL_RES_ ((u16)0x0040)
+#define PHY_SPECIAL_RES_MASK_ ((u16)0x0FE1)
+#define PHY_SPECIAL_SPD_ ((u16)0x001C)
+#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004)
+#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014)
+#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008)
+#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018)
+
+#define LAN911X_INTERNAL_PHY_ID (0x0007C000)
+
+/* Chip ID values */
+#define CHIP_9115 0x115
+#define CHIP_9116 0x116
+#define CHIP_9117 0x117
+#define CHIP_9118 0x118
+
+struct chip_id {
+ u16 id;
+ char *name;
+};
+
+static const struct chip_id chip_ids[] = {
+ { CHIP_9115, "LAN9115" },
+ { CHIP_9116, "LAN9116" },
+ { CHIP_9117, "LAN9117" },
+ { CHIP_9118, "LAN9118" },
+ { 0, NULL },
+};
+
+#define IS_REV_A(x) ((x & 0xFFFF)==0)
+
+/*
+ * Macros to abstract register access according to the data bus
+ * capabilities. Please use those and not the in/out primitives.
+ */
+/* FIFO read/write macros */
+#define SMC_PUSH_DATA(p, l) SMC_outsl( ioaddr, TX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_PULL_DATA(p, l) SMC_insl ( ioaddr, RX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_SET_TX_FIFO(x) SMC_outl( x, ioaddr, TX_DATA_FIFO )
+#define SMC_GET_RX_FIFO() SMC_inl( ioaddr, RX_DATA_FIFO )
+
+
+/* I/O mapped register read/write macros */
+#define SMC_GET_TX_STS_FIFO() SMC_inl( ioaddr, TX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO() SMC_inl( ioaddr, RX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO_PEEK() SMC_inl( ioaddr, RX_STATUS_FIFO_PEEK )
+#define SMC_GET_PN() (SMC_inl( ioaddr, ID_REV ) >> 16)
+#define SMC_GET_REV() (SMC_inl( ioaddr, ID_REV ) & 0xFFFF)
+#define SMC_GET_IRQ_CFG() SMC_inl( ioaddr, INT_CFG )
+#define SMC_SET_IRQ_CFG(x) SMC_outl( x, ioaddr, INT_CFG )
+#define SMC_GET_INT() SMC_inl( ioaddr, INT_STS )
+#define SMC_ACK_INT(x) SMC_outl( x, ioaddr, INT_STS )
+#define SMC_GET_INT_EN() SMC_inl( ioaddr, INT_EN )
+#define SMC_SET_INT_EN(x) SMC_outl( x, ioaddr, INT_EN )
+#define SMC_GET_BYTE_TEST() SMC_inl( ioaddr, BYTE_TEST )
+#define SMC_SET_BYTE_TEST(x) SMC_outl( x, ioaddr, BYTE_TEST )
+#define SMC_GET_FIFO_INT() SMC_inl( ioaddr, FIFO_INT )
+#define SMC_SET_FIFO_INT(x) SMC_outl( x, ioaddr, FIFO_INT )
+#define SMC_SET_FIFO_TDA(x) \
+ do { \
+ unsigned long __flags; \
+ int __mask; \
+ local_irq_save(__flags); \
+ __mask = SMC_GET_FIFO_INT() & ~(0xFF<<24); \
+ SMC_SET_FIFO_INT( __mask | (x)<<24 ); \
+ local_irq_restore(__flags); \
+ } while (0)
+#define SMC_SET_FIFO_TSL(x) \
+ do { \
+ unsigned long __flags; \
+ int __mask; \
+ local_irq_save(__flags); \
+ __mask = SMC_GET_FIFO_INT() & ~(0xFF<<16); \
+ SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<16)); \
+ local_irq_restore(__flags); \
+ } while (0)
+#define SMC_SET_FIFO_RSA(x) \
+ do { \
+ unsigned long __flags; \
+ int __mask; \
+ local_irq_save(__flags); \
+ __mask = SMC_GET_FIFO_INT() & ~(0xFF<<8); \
+ SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<8)); \
+ local_irq_restore(__flags); \
+ } while (0)
+#define SMC_SET_FIFO_RSL(x) \
+ do { \
+ unsigned long __flags; \
+ int __mask; \
+ local_irq_save(__flags); \
+ __mask = SMC_GET_FIFO_INT() & ~0xFF; \
+ SMC_SET_FIFO_INT( __mask | ((x) & 0xFF)); \
+ local_irq_restore(__flags); \
+ } while (0)
+#define SMC_GET_RX_CFG() SMC_inl( ioaddr, RX_CFG )
+#define SMC_SET_RX_CFG(x) SMC_outl( x, ioaddr, RX_CFG )
+#define SMC_GET_TX_CFG() SMC_inl( ioaddr, TX_CFG )
+#define SMC_SET_TX_CFG(x) SMC_outl( x, ioaddr, TX_CFG )
+#define SMC_GET_HW_CFG() SMC_inl( ioaddr, HW_CFG )
+#define SMC_SET_HW_CFG(x) SMC_outl( x, ioaddr, HW_CFG )
+#define SMC_GET_RX_DP_CTRL() SMC_inl( ioaddr, RX_DP_CTRL )
+#define SMC_SET_RX_DP_CTRL(x) SMC_outl( x, ioaddr, RX_DP_CTRL )
+#define SMC_GET_PMT_CTRL() SMC_inl( ioaddr, PMT_CTRL )
+#define SMC_SET_PMT_CTRL(x) SMC_outl( x, ioaddr, PMT_CTRL )
+#define SMC_GET_GPIO_CFG() SMC_inl( ioaddr, GPIO_CFG )
+#define SMC_SET_GPIO_CFG(x) SMC_outl( x, ioaddr, GPIO_CFG )
+#define SMC_GET_RX_FIFO_INF() SMC_inl( ioaddr, RX_FIFO_INF )
+#define SMC_SET_RX_FIFO_INF(x) SMC_outl( x, ioaddr, RX_FIFO_INF )
+#define SMC_GET_TX_FIFO_INF() SMC_inl( ioaddr, TX_FIFO_INF )
+#define SMC_SET_TX_FIFO_INF(x) SMC_outl( x, ioaddr, TX_FIFO_INF )
+#define SMC_GET_GPT_CFG() SMC_inl( ioaddr, GPT_CFG )
+#define SMC_SET_GPT_CFG(x) SMC_outl( x, ioaddr, GPT_CFG )
+#define SMC_GET_RX_DROP() SMC_inl( ioaddr, RX_DROP )
+#define SMC_SET_RX_DROP(x) SMC_outl( x, ioaddr, RX_DROP )
+#define SMC_GET_MAC_CMD() SMC_inl( ioaddr, MAC_CSR_CMD )
+#define SMC_SET_MAC_CMD(x) SMC_outl( x, ioaddr, MAC_CSR_CMD )
+#define SMC_GET_MAC_DATA() SMC_inl( ioaddr, MAC_CSR_DATA )
+#define SMC_SET_MAC_DATA(x) SMC_outl( x, ioaddr, MAC_CSR_DATA )
+#define SMC_GET_AFC_CFG() SMC_inl( ioaddr, AFC_CFG )
+#define SMC_SET_AFC_CFG(x) SMC_outl( x, ioaddr, AFC_CFG )
+#define SMC_GET_E2P_CMD() SMC_inl( ioaddr, E2P_CMD )
+#define SMC_SET_E2P_CMD(x) SMC_outl( x, ioaddr, E2P_CMD )
+#define SMC_GET_E2P_DATA() SMC_inl( ioaddr, E2P_DATA )
+#define SMC_SET_E2P_DATA(x) SMC_outl( x, ioaddr, E2P_DATA )
+
+/* MAC register read/write macros */
+#define SMC_GET_MAC_CSR(a,v) \
+ do { \
+ while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | \
+ MAC_CSR_CMD_R_NOT_W_ | (a) ); \
+ while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ v = SMC_GET_MAC_DATA(); \
+ } while (0)
+#define SMC_SET_MAC_CSR(a,v) \
+ do { \
+ while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_DATA(v); \
+ SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | (a) ); \
+ while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ } while (0)
+#define SMC_GET_MAC_CR(x) SMC_GET_MAC_CSR( MAC_CR, x )
+#define SMC_SET_MAC_CR(x) SMC_SET_MAC_CSR( MAC_CR, x )
+#define SMC_GET_ADDRH(x) SMC_GET_MAC_CSR( ADDRH, x )
+#define SMC_SET_ADDRH(x) SMC_SET_MAC_CSR( ADDRH, x )
+#define SMC_GET_ADDRL(x) SMC_GET_MAC_CSR( ADDRL, x )
+#define SMC_SET_ADDRL(x) SMC_SET_MAC_CSR( ADDRL, x )
+#define SMC_GET_HASHH(x) SMC_GET_MAC_CSR( HASHH, x )
+#define SMC_SET_HASHH(x) SMC_SET_MAC_CSR( HASHH, x )
+#define SMC_GET_HASHL(x) SMC_GET_MAC_CSR( HASHL, x )
+#define SMC_SET_HASHL(x) SMC_SET_MAC_CSR( HASHL, x )
+#define SMC_GET_MII_ACC(x) SMC_GET_MAC_CSR( MII_ACC, x )
+#define SMC_SET_MII_ACC(x) SMC_SET_MAC_CSR( MII_ACC, x )
+#define SMC_GET_MII_DATA(x) SMC_GET_MAC_CSR( MII_DATA, x )
+#define SMC_SET_MII_DATA(x) SMC_SET_MAC_CSR( MII_DATA, x )
+#define SMC_GET_FLOW(x) SMC_GET_MAC_CSR( FLOW, x )
+#define SMC_SET_FLOW(x) SMC_SET_MAC_CSR( FLOW, x )
+#define SMC_GET_VLAN1(x) SMC_GET_MAC_CSR( VLAN1, x )
+#define SMC_SET_VLAN1(x) SMC_SET_MAC_CSR( VLAN1, x )
+#define SMC_GET_VLAN2(x) SMC_GET_MAC_CSR( VLAN2, x )
+#define SMC_SET_VLAN2(x) SMC_SET_MAC_CSR( VLAN2, x )
+#define SMC_SET_WUFF(x) SMC_SET_MAC_CSR( WUFF, x )
+#define SMC_GET_WUCSR(x) SMC_GET_MAC_CSR( WUCSR, x )
+#define SMC_SET_WUCSR(x) SMC_SET_MAC_CSR( WUCSR, x )
+
+/* PHY register read/write macros */
+#define SMC_GET_MII(a,phy,v) \
+ do { \
+ u32 __v; \
+ do { \
+ SMC_GET_MII_ACC(__v); \
+ } while ( __v & MII_ACC_MII_BUSY_ ); \
+ SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ MII_ACC_MII_BUSY_); \
+ do { \
+ SMC_GET_MII_ACC(__v); \
+ } while ( __v & MII_ACC_MII_BUSY_ ); \
+ SMC_GET_MII_DATA(v); \
+ } while (0)
+#define SMC_SET_MII(a,phy,v) \
+ do { \
+ u32 __v; \
+ do { \
+ SMC_GET_MII_ACC(__v); \
+ } while ( __v & MII_ACC_MII_BUSY_ ); \
+ SMC_SET_MII_DATA(v); \
+ SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ MII_ACC_MII_BUSY_ | \
+ MII_ACC_MII_WRITE_ ); \
+ do { \
+ SMC_GET_MII_ACC(__v); \
+ } while ( __v & MII_ACC_MII_BUSY_ ); \
+ } while (0)
+#define SMC_GET_PHY_BMCR(phy,x) SMC_GET_MII( MII_BMCR, phy, x )
+#define SMC_SET_PHY_BMCR(phy,x) SMC_SET_MII( MII_BMCR, phy, x )
+#define SMC_GET_PHY_BMSR(phy,x) SMC_GET_MII( MII_BMSR, phy, x )
+#define SMC_GET_PHY_ID1(phy,x) SMC_GET_MII( MII_PHYSID1, phy, x )
+#define SMC_GET_PHY_ID2(phy,x) SMC_GET_MII( MII_PHYSID2, phy, x )
+#define SMC_GET_PHY_MII_ADV(phy,x) SMC_GET_MII( MII_ADVERTISE, phy, x )
+#define SMC_SET_PHY_MII_ADV(phy,x) SMC_SET_MII( MII_ADVERTISE, phy, x )
+#define SMC_GET_PHY_MII_LPA(phy,x) SMC_GET_MII( MII_LPA, phy, x )
+#define SMC_SET_PHY_MII_LPA(phy,x) SMC_SET_MII( MII_LPA, phy, x )
+#define SMC_GET_PHY_CTRL_STS(phy,x) SMC_GET_MII( PHY_MODE_CTRL_STS, phy, x )
+#define SMC_SET_PHY_CTRL_STS(phy,x) SMC_SET_MII( PHY_MODE_CTRL_STS, phy, x )
+#define SMC_GET_PHY_INT_SRC(phy,x) SMC_GET_MII( PHY_INT_SRC, phy, x )
+#define SMC_SET_PHY_INT_SRC(phy,x) SMC_SET_MII( PHY_INT_SRC, phy, x )
+#define SMC_GET_PHY_INT_MASK(phy,x) SMC_GET_MII( PHY_INT_MASK, phy, x )
+#define SMC_SET_PHY_INT_MASK(phy,x) SMC_SET_MII( PHY_INT_MASK, phy, x )
+#define SMC_GET_PHY_SPECIAL(phy,x) SMC_GET_MII( PHY_SPECIAL, phy, x )
+
+
+
+/* Misc read/write macros */
+
+#ifndef SMC_GET_MAC_ADDR
+#define SMC_GET_MAC_ADDR(addr) \
+ do { \
+ unsigned int __v; \
+ \
+ SMC_GET_MAC_CSR(ADDRL, __v); \
+ addr[0] = __v; addr[1] = __v >> 8; \
+ addr[2] = __v >> 16; addr[3] = __v >> 24; \
+ SMC_GET_MAC_CSR(ADDRH, __v); \
+ addr[4] = __v; addr[5] = __v >> 8; \
+ } while (0)
+#endif
+
+#define SMC_SET_MAC_ADDR(addr) \
+ do { \
+ SMC_SET_MAC_CSR(ADDRL, \
+ addr[0] | \
+ (addr[1] << 8) | \
+ (addr[2] << 16) | \
+ (addr[3] << 24)); \
+ SMC_SET_MAC_CSR(ADDRH, addr[4]|(addr[5] << 8));\
+ } while (0)
+
+
+#define SMC_WRITE_EEPROM_CMD(cmd, addr) \
+ do { \
+ while (SMC_GET_E2P_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD(MAC_CSR_CMD_R_NOT_W_ | a ); \
+ while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ } while (0)
+
+#endif /* _SMC911X_H_ */
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index f86697da04d6..6cf16f322ad5 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -732,12 +732,9 @@ static int ifport;
struct net_device * __init smc_init(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct smc_local));
- static struct devlist *smcdev = smc_devlist;
+ struct devlist *smcdev = smc_devlist;
int err = 0;
-#ifndef NO_AUTOPROBE
- smcdev = smc_devlist;
-#endif
if (!dev)
return ERR_PTR(-ENODEV);
@@ -1607,7 +1604,7 @@ MODULE_PARM_DESC(io, "SMC 99194 I/O base address");
MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");
MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");
-int init_module(void)
+int __init init_module(void)
{
if (io == 0)
printk(KERN_WARNING
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index e1be1af51201..bf776125ca38 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -129,6 +129,24 @@
#define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l))
#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l))
+#elif defined(CONFIG_MACH_LOGICPD_PXA270)
+
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_IO_SHIFT 0
+#define SMC_NOWAIT 1
+#define SMC_USE_PXA_DMA 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
+
#elif defined(CONFIG_ARCH_INNOKOM) || \
defined(CONFIG_MACH_MAINSTONE) || \
defined(CONFIG_ARCH_PXA_IDP) || \
@@ -242,15 +260,17 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define RPC_LSA_DEFAULT RPC_LED_TX_RX
#define RPC_LSB_DEFAULT RPC_LED_100_10
-#elif defined(CONFIG_MACH_LPD7A400) || defined(CONFIG_MACH_LPD7A404)
+#elif defined(CONFIG_MACH_LPD79520) \
+ || defined(CONFIG_MACH_LPD7A400) \
+ || defined(CONFIG_MACH_LPD7A404)
-/* The LPD7A40X_IOBARRIER is necessary to overcome a mismatch between
- * the way that the CPU handles chip selects and the way that the SMC
- * chip expects the chip select to operate. Refer to
+/* The LPD7X_IOBARRIER is necessary to overcome a mismatch between the
+ * way that the CPU handles chip selects and the way that the SMC chip
+ * expects the chip select to operate. Refer to
* Documentation/arm/Sharp-LH/IOBarrier for details. The read from
- * IOBARRIER is a byte as a least-common denominator of possible
- * regions to use as the barrier. It would be wasteful to read 32
- * bits from a byte oriented region.
+ * IOBARRIER is a byte, in order that we read the least-common
+ * denominator. It would be wasteful to read 32 bits from an 8-bit
+ * accessible region.
*
* There is no explicit protection against interrupts intervening
* between the writew and the IOBARRIER. In SMC ISR there is a
@@ -269,25 +289,35 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_CAN_USE_16BIT 1
#define SMC_CAN_USE_32BIT 0
#define SMC_NOWAIT 0
-#define LPD7A40X_IOBARRIER readb (IOBARRIER_VIRT)
+#define LPD7X_IOBARRIER readb (IOBARRIER_VIRT)
-#define SMC_inw(a,r) readw ((void*) ((a) + (r)))
-#define SMC_insw(a,r,p,l) readsw ((void*) ((a) + (r)), p, l)
-#define SMC_outw(v,a,r) ({ writew ((v), (a) + (r)); LPD7A40X_IOBARRIER; })
+#define SMC_inw(a,r)\
+ ({ unsigned short v = readw ((void*) ((a) + (r))); LPD7X_IOBARRIER; v; })
+#define SMC_outw(v,a,r) ({ writew ((v), (a) + (r)); LPD7X_IOBARRIER; })
-#define SMC_outsw LPD7A40X_SMC_outsw
+#define SMC_insw LPD7_SMC_insw
+static inline void LPD7_SMC_insw (unsigned char* a, int r,
+ unsigned char* p, int l)
+{
+ unsigned short* ps = (unsigned short*) p;
+ while (l-- > 0) {
+ *ps++ = readw (a + r);
+ LPD7X_IOBARRIER;
+ }
+}
-static inline void LPD7A40X_SMC_outsw(unsigned long a, int r,
- unsigned char* p, int l)
+#define SMC_outsw LPD7_SMC_outsw
+static inline void LPD7_SMC_outsw (unsigned char* a, int r,
+ unsigned char* p, int l)
{
unsigned short* ps = (unsigned short*) p;
while (l-- > 0) {
writew (*ps++, a + r);
- LPD7A40X_IOBARRIER;
+ LPD7X_IOBARRIER;
}
}
-#define SMC_INTERRUPT_PREAMBLE LPD7A40X_IOBARRIER
+#define SMC_INTERRUPT_PREAMBLE LPD7X_IOBARRIER
#define RPC_LSA_DEFAULT RPC_LED_TX_RX
#define RPC_LSB_DEFAULT RPC_LED_100_10
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 43f5e86fc559..394339d5e87c 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1652,6 +1652,8 @@ spider_net_enable_card(struct spider_net_card *card)
{ SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
{ SPIDER_NET_GMRWOLCTRL, 0 },
+ { SPIDER_NET_GTESTMD, 0x10000000 },
+ { SPIDER_NET_GTTQMSK, 0x00400040 },
{ SPIDER_NET_GTESTMD, 0 },
{ SPIDER_NET_GMACINTEN, 0 },
@@ -1792,15 +1794,7 @@ spider_net_setup_phy(struct spider_net_card *card)
if (phy->def->ops->setup_forced)
phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
- /* the following two writes could be moved to sungem_phy.c */
- /* enable fiber mode */
- spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020);
- /* LEDs active in both modes, autosense prio = fiber */
- spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f);
-
- /* switch off fibre autoneg */
- spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01);
- spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004);
+ phy->def->ops->enable_fiber(phy);
phy->def->ops->read_link(phy);
pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 5922b529a048..3b8d951cf73c 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -120,6 +120,8 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_GMRUAFILnR 0x00000500
#define SPIDER_NET_GMRUA0FIL15R 0x00000578
+#define SPIDER_NET_GTTQMSK 0x00000934
+
/* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
* 0x00000b.. for DMA controller B, etc. */
#define SPIDER_NET_GDADCHA 0x00000a00
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 046371ee5bbe..9282b4b0c022 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -329,6 +329,30 @@ static int bcm5421_init(struct mii_phy* phy)
return 0;
}
+static int bcm5421_enable_fiber(struct mii_phy* phy)
+{
+ /* enable fiber mode */
+ phy_write(phy, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ phy_write(phy, MII_NCONFIG, 0x945f);
+
+ /* switch off fibre autoneg */
+ phy_write(phy, MII_NCONFIG, 0xfc01);
+ phy_write(phy, 0x0b, 0x0004);
+
+ return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy)
+{
+ phy_write(phy, MII_NCONFIG, 0xfc0c);
+ phy_write(phy, MII_BMCR, 0x4140);
+ phy_write(phy, MII_NCONFIG, 0xfc0b);
+ phy_write(phy, MII_BMCR, 0x0140);
+
+ return 0;
+}
+
static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -762,6 +786,7 @@ static struct mii_phy_ops bcm5421_phy_ops = {
.setup_forced = bcm54xx_setup_forced,
.poll_link = genmii_poll_link,
.read_link = bcm54xx_read_link,
+ .enable_fiber = bcm5421_enable_fiber,
};
static struct mii_phy_def bcm5421_phy_def = {
@@ -792,6 +817,25 @@ static struct mii_phy_def bcm5421k2_phy_def = {
.ops = &bcm5421k2_phy_ops
};
+static struct mii_phy_ops bcm5461_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+ .enable_fiber = bcm5461_enable_fiber,
+};
+
+static struct mii_phy_def bcm5461_phy_def = {
+ .phy_id = 0x002060c0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5461",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5461_phy_ops
+};
+
/* Broadcom BCM 5462 built-in Vesta */
static struct mii_phy_ops bcm5462V_phy_ops = {
.init = bcm5421_init,
@@ -857,6 +901,7 @@ static struct mii_phy_def* mii_phy_table[] = {
&bcm5411_phy_def,
&bcm5421_phy_def,
&bcm5421k2_phy_def,
+ &bcm5461_phy_def,
&bcm5462V_phy_def,
&marvell_phy_def,
&genmii_phy_def,
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 430544496c52..69e125197fcf 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -12,6 +12,7 @@ struct mii_phy_ops
int (*setup_forced)(struct mii_phy *phy, int speed, int fd);
int (*poll_link)(struct mii_phy *phy);
int (*read_link)(struct mii_phy *phy);
+ int (*enable_fiber)(struct mii_phy *phy);
};
/* Structure used to statically define an mii/gii based PHY */
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 73e271e59c6a..b2ddd4522a87 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,8 +69,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.56"
-#define DRV_MODULE_RELDATE "Apr 1, 2006"
+#define DRV_MODULE_VERSION "3.60"
+#define DRV_MODULE_RELDATE "June 17, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -229,6 +229,8 @@ static struct pci_device_id tg3_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M,
@@ -974,6 +976,8 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
return err;
}
+static void tg3_link_report(struct tg3 *);
+
/* This will reset the tigon3 PHY if there is no valid
* link unless the FORCE argument is non-zero.
*/
@@ -987,6 +991,11 @@ static int tg3_phy_reset(struct tg3 *tp)
if (err != 0)
return -EBUSY;
+ if (netif_running(tp->dev) && netif_carrier_ok(tp->dev)) {
+ netif_carrier_off(tp->dev);
+ tg3_link_report(tp);
+ }
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
@@ -1023,6 +1032,12 @@ out:
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
+ else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+ tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
+ tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+ }
/* Set Extended packet length bit (bit 14) on all chips that */
/* support jumbo frames */
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
@@ -2952,6 +2967,27 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
return err;
}
+/* This is called whenever we suspect that the system chipset is re-
+ * ordering the sequence of MMIO to the tx send mailbox. The symptom
+ * is bogus tx completions. We try to recover by setting the
+ * TG3_FLAG_MBOX_WRITE_REORDER flag and resetting the chip later
+ * in the workqueue.
+ */
+static void tg3_tx_recover(struct tg3 *tp)
+{
+ BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) ||
+ tp->write32_tx_mbox == tg3_write_indirect_mbox);
+
+ printk(KERN_WARNING PFX "%s: The system may be re-ordering memory-"
+ "mapped I/O cycles to the network device, attempting to "
+ "recover. Please report the problem to the driver maintainer "
+ "and include system chipset information.\n", tp->dev->name);
+
+ spin_lock(&tp->lock);
+ tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING;
+ spin_unlock(&tp->lock);
+}
+
/* Tigon3 never reports partial packet sends. So we do not
* need special logic to handle SKBs that have not had all
* of their frags sent yet, like SunGEM does.
@@ -2964,9 +3000,13 @@ static void tg3_tx(struct tg3 *tp)
while (sw_idx != hw_idx) {
struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
struct sk_buff *skb = ri->skb;
- int i;
+ int i, tx_bug = 0;
+
+ if (unlikely(skb == NULL)) {
+ tg3_tx_recover(tp);
+ return;
+ }
- BUG_ON(skb == NULL);
pci_unmap_single(tp->pdev,
pci_unmap_addr(ri, mapping),
skb_headlen(skb),
@@ -2977,10 +3017,9 @@ static void tg3_tx(struct tg3 *tp)
sw_idx = NEXT_TX(sw_idx);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_ON(sw_idx == hw_idx);
-
ri = &tp->tx_buffers[sw_idx];
- BUG_ON(ri->skb != NULL);
+ if (unlikely(ri->skb != NULL || sw_idx == hw_idx))
+ tx_bug = 1;
pci_unmap_page(tp->pdev,
pci_unmap_addr(ri, mapping),
@@ -2991,6 +3030,11 @@ static void tg3_tx(struct tg3 *tp)
}
dev_kfree_skb(skb);
+
+ if (unlikely(tx_bug)) {
+ tg3_tx_recover(tp);
+ return;
+ }
}
tp->tx_cons = sw_idx;
@@ -3318,6 +3362,11 @@ static int tg3_poll(struct net_device *netdev, int *budget)
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
tg3_tx(tp);
+ if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
+ netif_rx_complete(netdev);
+ schedule_work(&tp->reset_task);
+ return 0;
+ }
}
/* run RX thread, within the bounds set by NAPI.
@@ -3378,12 +3427,10 @@ static inline void tg3_full_lock(struct tg3 *tp, int irq_sync)
if (irq_sync)
tg3_irq_quiesce(tp);
spin_lock_bh(&tp->lock);
- spin_lock(&tp->tx_lock);
}
static inline void tg3_full_unlock(struct tg3 *tp)
{
- spin_unlock(&tp->tx_lock);
spin_unlock_bh(&tp->lock);
}
@@ -3531,7 +3578,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
return IRQ_RETVAL(0);
}
-static int tg3_init_hw(struct tg3 *);
+static int tg3_init_hw(struct tg3 *, int);
static int tg3_halt(struct tg3 *, int, int);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3566,8 +3613,15 @@ static void tg3_reset_task(void *_data)
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
+ if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) {
+ tp->write32_tx_mbox = tg3_write32_tx_mbox;
+ tp->write32_rx_mbox = tg3_write_flush_reg32;
+ tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
+ tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING;
+ }
+
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tg3_netif_start(tp);
@@ -3705,14 +3759,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
- /* No BH disabling for tx_lock here. We are running in BH disabled
- * context and TX reclaim runs via tp->poll inside of a software
+ /* We are running in BH disabled context with netif_tx_lock
+ * and TX reclaim runs via tp->poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
- if (!spin_trylock(&tp->tx_lock))
- return NETDEV_TX_LOCKED;
-
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
@@ -3721,7 +3772,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
"queue awake!\n", dev->name);
}
- spin_unlock(&tp->tx_lock);
return NETDEV_TX_BUSY;
}
@@ -3804,15 +3854,16 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
tp->tx_prod = entry;
- if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) {
+ if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) {
+ spin_lock(&tp->tx_lock);
netif_stop_queue(dev);
if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
netif_wake_queue(tp->dev);
+ spin_unlock(&tp->tx_lock);
}
out_unlock:
mmiowb();
- spin_unlock(&tp->tx_lock);
dev->trans_start = jiffies;
@@ -3831,14 +3882,11 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
- /* No BH disabling for tx_lock here. We are running in BH disabled
- * context and TX reclaim runs via tp->poll inside of a software
+ /* We are running in BH disabled context with netif_tx_lock
+ * and TX reclaim runs via tp->poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
- if (!spin_trylock(&tp->tx_lock))
- return NETDEV_TX_LOCKED;
-
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
@@ -3847,7 +3895,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
"queue awake!\n", dev->name);
}
- spin_unlock(&tp->tx_lock);
return NETDEV_TX_BUSY;
}
@@ -3985,15 +4032,16 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
tp->tx_prod = entry;
- if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) {
+ if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) {
+ spin_lock(&tp->tx_lock);
netif_stop_queue(dev);
if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
netif_wake_queue(tp->dev);
+ spin_unlock(&tp->tx_lock);
}
out_unlock:
mmiowb();
- spin_unlock(&tp->tx_lock);
dev->trans_start = jiffies;
@@ -4042,7 +4090,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_set_mtu(dev, tp, new_mtu);
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 0);
tg3_netif_start(tp);
@@ -4472,9 +4520,8 @@ static void tg3_disable_nvram_access(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
- if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
- tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
- NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+ tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
+ NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
switch (kind) {
@@ -4555,13 +4602,12 @@ static int tg3_chip_reset(struct tg3 *tp)
void (*write_op)(struct tg3 *, u32, u32);
int i;
- if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
- tg3_nvram_lock(tp);
- /* No matching tg3_nvram_unlock() after this because
- * chip reset below will undo the nvram lock.
- */
- tp->nvram_lock_cnt = 0;
- }
+ tg3_nvram_lock(tp);
+
+ /* No matching tg3_nvram_unlock() after this because
+ * chip reset below will undo the nvram lock.
+ */
+ tp->nvram_lock_cnt = 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
@@ -4714,20 +4760,25 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32_f(MAC_MODE, 0);
udelay(40);
- if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
- /* Wait for firmware initialization to complete. */
- for (i = 0; i < 100000; i++) {
- tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
- if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
- break;
- udelay(10);
- }
- if (i >= 100000) {
- printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
- "firmware will not restart magic=%08x\n",
- tp->dev->name, val);
- return -ENODEV;
- }
+ /* Wait for firmware initialization to complete. */
+ for (i = 0; i < 100000; i++) {
+ tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+ if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+ break;
+ udelay(10);
+ }
+
+ /* Chip might not be fitted with firmare. Some Sun onboard
+ * parts are configured like that. So don't signal the timeout
+ * of the above loop as an error, but do report the lack of
+ * running firmware once.
+ */
+ if (i >= 100000 &&
+ !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
+ tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
+
+ printk(KERN_INFO PFX "%s: No firmware running.\n",
+ tp->dev->name);
}
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
@@ -5719,9 +5770,23 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
if (!netif_running(dev))
return 0;
- spin_lock_bh(&tp->lock);
- __tg3_set_mac_addr(tp);
- spin_unlock_bh(&tp->lock);
+ if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ /* Reset chip so that ASF can re-init any MAC addresses it
+ * needs.
+ */
+ tg3_netif_stop(tp);
+ tg3_full_lock(tp, 1);
+
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ tg3_init_hw(tp, 0);
+
+ tg3_netif_start(tp);
+ tg3_full_unlock(tp);
+ } else {
+ spin_lock_bh(&tp->lock);
+ __tg3_set_mac_addr(tp);
+ spin_unlock_bh(&tp->lock);
+ }
return 0;
}
@@ -5771,7 +5836,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
}
/* tp->lock is held. */
-static int tg3_reset_hw(struct tg3 *tp)
+static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
{
u32 val, rdmac_mode;
int i, err, limit;
@@ -5786,7 +5851,7 @@ static int tg3_reset_hw(struct tg3 *tp)
tg3_abort_hw(tp, 1);
}
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) && reset_phy)
tg3_phy_reset(tp);
err = tg3_chip_reset(tp);
@@ -6327,7 +6392,7 @@ static int tg3_reset_hw(struct tg3 *tp)
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
}
- err = tg3_setup_phy(tp, 1);
+ err = tg3_setup_phy(tp, reset_phy);
if (err)
return err;
@@ -6400,7 +6465,7 @@ static int tg3_reset_hw(struct tg3 *tp)
/* Called at device open time to get the chip ready for
* packet processing. Invoked with tp->lock held.
*/
-static int tg3_init_hw(struct tg3 *tp)
+static int tg3_init_hw(struct tg3 *tp, int reset_phy)
{
int err;
@@ -6413,7 +6478,7 @@ static int tg3_init_hw(struct tg3 *tp)
tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
- err = tg3_reset_hw(tp);
+ err = tg3_reset_hw(tp, reset_phy);
out:
return err;
@@ -6461,6 +6526,10 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
TG3_STAT_ADD32(&sp->rx_frame_too_long_errors, MAC_RX_STATS_FRAME_TOO_LONG);
TG3_STAT_ADD32(&sp->rx_jabbers, MAC_RX_STATS_JABBERS);
TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE);
+
+ TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT);
+ TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT);
+ TG3_STAT_ADD32(&sp->rx_errors, RCVLPC_IN_ERRORS_CNT);
}
static void tg3_timer(unsigned long __opaque)
@@ -6683,7 +6752,7 @@ static int tg3_test_msi(struct tg3 *tp)
tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_init_hw(tp);
+ err = tg3_init_hw(tp, 1);
tg3_full_unlock(tp);
@@ -6748,7 +6817,7 @@ static int tg3_open(struct net_device *dev)
tg3_full_lock(tp, 0);
- err = tg3_init_hw(tp);
+ err = tg3_init_hw(tp, 1);
if (err) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
@@ -7626,21 +7695,23 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported |= (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full);
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+ if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
cmd->supported |= (SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_MII);
- else
+ cmd->port = PORT_TP;
+ } else {
cmd->supported |= SUPPORTED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ }
cmd->advertising = tp->link_config.advertising;
if (netif_running(dev)) {
cmd->speed = tp->link_config.active_speed;
cmd->duplex = tp->link_config.active_duplex;
}
- cmd->port = 0;
cmd->phy_address = PHY_ADDR;
cmd->transceiver = 0;
cmd->autoneg = tp->link_config.autoneg;
@@ -7839,7 +7910,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tg3_netif_start(tp);
}
@@ -7884,7 +7955,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tg3_netif_start(tp);
}
@@ -8427,6 +8498,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
tx_len = 1514;
skb = dev_alloc_skb(tx_len);
+ if (!skb)
+ return -ENOMEM;
+
tx_data = skb_put(skb, tx_len);
memcpy(tx_data, tp->dev->dev_addr, 6);
memset(tx_data + 6, 0x0, 8);
@@ -8522,7 +8596,7 @@ static int tg3_test_loopback(struct tg3 *tp)
if (!netif_running(tp->dev))
return TG3_LOOPBACK_FAILED;
- tg3_reset_hw(tp);
+ tg3_reset_hw(tp, 1);
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
err |= TG3_MAC_LOOPBACK_FAILED;
@@ -8596,7 +8670,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tg3_netif_start(tp);
}
@@ -9039,9 +9113,6 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
{
int j;
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X)
- return;
-
tw32_f(GRC_EEPROM_ADDR,
(EEPROM_ADDR_FSM_RESET |
(EEPROM_DEFAULT_CLOCK_PERIOD <<
@@ -9174,11 +9245,6 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
{
int ret;
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
- printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n");
- return -EINVAL;
- }
-
if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
return tg3_nvram_read_using_eeprom(tp, offset, val);
@@ -9377,7 +9443,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
if ((page_off == 0) || (i == 0))
nvram_cmd |= NVRAM_CMD_FIRST;
- else if (page_off == (tp->nvram_pagesize - 4))
+ if (page_off == (tp->nvram_pagesize - 4))
nvram_cmd |= NVRAM_CMD_LAST;
if (i == (len - 4))
@@ -9411,11 +9477,6 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
{
int ret;
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
- printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n");
- return -EINVAL;
- }
-
if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
~GRC_LCLCTRL_GPIO_OUTPUT1);
@@ -9542,15 +9603,19 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
tp->misc_host_ctrl);
+ /* The memory arbiter has to be enabled in order for SRAM accesses
+ * to succeed. Normally on powerup the tg3 chip firmware will make
+ * sure it is enabled, but other entities such as system netboot
+ * code might disable it.
+ */
+ val = tr32(MEMARB_MODE);
+ tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
+
tp->phy_id = PHY_ID_INVALID;
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
- /* Do not even try poking around in here on Sun parts. */
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
- /* All SUN chips are built-in LOMs. */
- tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
- return;
- }
+ /* Assume an onboard device by default. */
+ tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
@@ -9650,6 +9715,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+ else
+ tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
@@ -9798,16 +9865,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
int i;
u32 magic;
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
- /* Sun decided not to put the necessary bits in the
- * NVRAM of their onboard tg3 parts :(
- */
- strcpy(tp->board_part_number, "Sun 570X");
- return;
- }
-
if (tg3_nvram_read_swab(tp, 0x0, &magic))
- return;
+ goto out_not_found;
if (magic == TG3_EEPROM_MAGIC) {
for (i = 0; i < 256; i += 4) {
@@ -9838,6 +9897,9 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
break;
msleep(1);
}
+ if (!(tmp16 & 0x8000))
+ goto out_not_found;
+
pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
&tmp);
tmp = cpu_to_le32(tmp);
@@ -9929,37 +9991,6 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
}
}
-#ifdef CONFIG_SPARC64
-static int __devinit tg3_is_sun_570X(struct tg3 *tp)
-{
- struct pci_dev *pdev = tp->pdev;
- struct pcidev_cookie *pcp = pdev->sysdata;
-
- if (pcp != NULL) {
- int node = pcp->prom_node;
- u32 venid;
- int err;
-
- err = prom_getproperty(node, "subsystem-vendor-id",
- (char *) &venid, sizeof(venid));
- if (err == 0 || err == -1)
- return 0;
- if (venid == PCI_VENDOR_ID_SUN)
- return 1;
-
- /* TG3 chips onboard the SunBlade-2500 don't have the
- * subsystem-vendor-id set to PCI_VENDOR_ID_SUN but they
- * are distinguishable from non-Sun variants by being
- * named "network" by the firmware. Non-Sun cards will
- * show up as being named "ethernet".
- */
- if (!strcmp(pcp->prom_name, "network"))
- return 1;
- }
- return 0;
-}
-#endif
-
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
static struct pci_device_id write_reorder_chipsets[] = {
@@ -9976,11 +10007,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
u16 pci_cmd;
int err;
-#ifdef CONFIG_SPARC64
- if (tg3_is_sun_570X(tp))
- tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
-#endif
-
/* Force memory write invalidate off. If we leave it on,
* then on 5700_BX chips we have to enable a workaround.
* The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
@@ -10276,8 +10302,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->write32 == tg3_write_indirect_reg32 ||
((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) ||
- (tp->tg3_flags2 & TG3_FLG2_SUN_570X))
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
/* Get eeprom hw config before calling tg3_set_power_state().
@@ -10353,10 +10378,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
- if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787))
- tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
+ else
+ tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+ }
tp->coalesce_mode = 0;
if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
@@ -10555,8 +10583,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
#endif
mac_offset = 0x7c;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
- !(tp->tg3_flags & TG3_FLG2_SUN_570X)) ||
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
mac_offset = 0xcc;
@@ -10583,8 +10610,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
}
if (!addr_ok) {
/* Next, try NVRAM. */
- if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) &&
- !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+ if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
!tg3_nvram_read(tp, mac_offset + 4, &lo)) {
dev->dev_addr[0] = ((hi >> 16) & 0xff);
dev->dev_addr[1] = ((hi >> 24) & 0xff);
@@ -11252,7 +11278,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- dev->features |= NETIF_F_LLTX;
#if TG3_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register = tg3_vlan_rx_register;
@@ -11569,7 +11594,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
@@ -11603,7 +11628,7 @@ static int tg3_resume(struct pci_dev *pdev)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp);
+ tg3_init_hw(tp, 1);
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 8c8b987d1250..8209da5dd15f 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2074,12 +2074,22 @@ struct tg3 {
/* SMP locking strategy:
*
- * lock: Held during all operations except TX packet
- * processing.
+ * lock: Held during reset, PHY access, timer, and when
+ * updating tg3_flags and tg3_flags2.
*
- * tx_lock: Held during tg3_start_xmit and tg3_tx
+ * tx_lock: Held during tg3_start_xmit and tg3_tx only
+ * when calling netif_[start|stop]_queue.
+ * tg3_start_xmit is protected by netif_tx_lock.
*
* Both of these locks are to be held with BH safety.
+ *
+ * Because the IRQ handler, tg3_poll, and tg3_start_xmit
+ * are running lockless, it is necessary to completely
+ * quiesce the chip with tg3_netif_stop and tg3_full_lock
+ * before reconfiguring the device.
+ *
+ * indirect_lock: Held when accessing registers indirectly
+ * with IRQ disabling.
*/
spinlock_t lock;
spinlock_t indirect_lock;
@@ -2155,11 +2165,7 @@ struct tg3 {
#define TG3_FLAG_ENABLE_ASF 0x00000020
#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
-#if defined(CONFIG_X86)
#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100
-#else
-#define TG3_FLAG_MBOX_WRITE_REORDER 0 /* disables code too */
-#endif
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
#define TG3_FLAG_WOL_SPEED_100MB 0x00000400
#define TG3_FLAG_WOL_ENABLE 0x00000800
@@ -2172,6 +2178,7 @@ struct tg3 {
#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
#define TG3_FLAG_PCI_32BIT 0x00080000
#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000
+#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000
#define TG3_FLAG_SERDES_WOL_CAP 0x00400000
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
@@ -2184,7 +2191,7 @@ struct tg3 {
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
-#define TG3_FLG2_SUN_570X 0x00000002
+/* 0x00000002 available */
#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
#define TG3_FLG2_IS_5788 0x00000008
#define TG3_FLG2_MAX_RXPEND_64 0x00000010
@@ -2215,6 +2222,8 @@ struct tg3 {
#define TG3_FLG2_HW_TSO_2 0x08000000
#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2)
#define TG3_FLG2_1SHOT_MSI 0x10000000
+#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
+#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index e3dd144d326b..5f743b972949 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -227,12 +227,12 @@ enum {
SROMC0InfoLeaf = 27,
MediaBlockMask = 0x3f,
MediaCustomCSRs = (1 << 6),
-
+
/* PCIPM bits */
PM_Sleep = (1 << 31),
PM_Snooze = (1 << 30),
PM_Mask = PM_Sleep | PM_Snooze,
-
+
/* SIAStatus bits */
NWayState = (1 << 14) | (1 << 13) | (1 << 12),
NWayRestart = (1 << 12),
@@ -858,7 +858,7 @@ static void de_stop_rxtx (struct de_private *de)
return;
cpu_relax();
}
-
+
printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name);
}
@@ -931,7 +931,7 @@ static void de_set_media (struct de_private *de)
macmode |= FullDuplex;
else
macmode &= ~FullDuplex;
-
+
if (netif_msg_link(de)) {
printk(KERN_INFO "%s: set link %s\n"
KERN_INFO "%s: mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
@@ -966,9 +966,9 @@ static void de21040_media_timer (unsigned long data)
u32 status = dr32(SIAStatus);
unsigned int carrier;
unsigned long flags;
-
+
carrier = (status & NetCxnErr) ? 0 : 1;
-
+
if (carrier) {
if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus))
goto no_link_yet;
@@ -985,7 +985,7 @@ static void de21040_media_timer (unsigned long data)
return;
}
- de_link_down(de);
+ de_link_down(de);
if (de->media_lock)
return;
@@ -1039,7 +1039,7 @@ static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
return 0;
break;
}
-
+
return 1;
}
@@ -1050,9 +1050,9 @@ static void de21041_media_timer (unsigned long data)
u32 status = dr32(SIAStatus);
unsigned int carrier;
unsigned long flags;
-
+
carrier = (status & NetCxnErr) ? 0 : 1;
-
+
if (carrier) {
if ((de->media_type == DE_MEDIA_TP_AUTO ||
de->media_type == DE_MEDIA_TP ||
@@ -1072,7 +1072,7 @@ static void de21041_media_timer (unsigned long data)
return;
}
- de_link_down(de);
+ de_link_down(de);
/* if media type locked, don't switch media */
if (de->media_lock)
@@ -1124,7 +1124,7 @@ static void de21041_media_timer (unsigned long data)
u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
de_next_media(de, next_states, ARRAY_SIZE(next_states));
}
-
+
set_media:
spin_lock_irqsave(&de->lock, flags);
de_stop_rxtx(de);
@@ -1148,7 +1148,7 @@ static void de_media_interrupt (struct de_private *de, u32 status)
mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
return;
}
-
+
BUG_ON(!(status & LinkFail));
if (netif_carrier_ok(de->dev)) {
@@ -1227,7 +1227,7 @@ static int de_init_hw (struct de_private *de)
int rc;
de_adapter_wake(de);
-
+
macmode = dr32(MacMode) & ~MacModeClear;
rc = de_reset_mac(de);
@@ -1413,7 +1413,7 @@ static int de_close (struct net_device *dev)
netif_stop_queue(dev);
netif_carrier_off(dev);
spin_unlock_irqrestore(&de->lock, flags);
-
+
free_irq(dev->irq, dev);
de_free_rings(de);
@@ -1441,7 +1441,7 @@ static void de_tx_timeout (struct net_device *dev)
spin_unlock_irq(&de->lock);
enable_irq(dev->irq);
-
+
/* Update the error counts. */
__de_get_stats(de);
@@ -1451,7 +1451,7 @@ static void de_tx_timeout (struct net_device *dev)
de_init_rings(de);
de_init_hw(de);
-
+
netif_wake_queue(dev);
}
@@ -1459,7 +1459,7 @@ static void __de_get_regs(struct de_private *de, u8 *buf)
{
int i;
u32 *rbuf = (u32 *)buf;
-
+
/* read all CSRs */
for (i = 0; i < DE_NUM_REGS; i++)
rbuf[i] = dr32(i * 8);
@@ -1474,7 +1474,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_INTERNAL;
ecmd->phy_address = 0;
ecmd->advertising = de->media_advertise;
-
+
switch (de->media_type) {
case DE_MEDIA_AUI:
ecmd->port = PORT_AUI;
@@ -1489,7 +1489,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
ecmd->speed = SPEED_10;
break;
}
-
+
if (dr32(MacMode) & FullDuplex)
ecmd->duplex = DUPLEX_FULL;
else
@@ -1529,7 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
if (ecmd->autoneg == AUTONEG_ENABLE &&
(!(ecmd->advertising & ADVERTISED_Autoneg)))
return -EINVAL;
-
+
switch (ecmd->port) {
case PORT_AUI:
new_media = DE_MEDIA_AUI;
@@ -1554,22 +1554,22 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
return -EINVAL;
break;
}
-
+
media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1;
-
+
if ((new_media == de->media_type) &&
(media_lock == de->media_lock) &&
(ecmd->advertising == de->media_advertise))
return 0; /* nothing to change */
-
+
de_link_down(de);
de_stop_rxtx(de);
-
+
de->media_type = new_media;
de->media_lock = media_lock;
de->media_advertise = ecmd->advertising;
de_set_media(de);
-
+
return 0;
}
@@ -1817,7 +1817,7 @@ static void __init de21041_get_srom_info (struct de_private *de)
case 0x0204: de->media_type = DE_MEDIA_TP_FD; break;
default: de->media_type = DE_MEDIA_TP_AUTO; break;
}
-
+
if (netif_msg_probe(de))
printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
de->board_idx, ofs,
@@ -1886,7 +1886,7 @@ static void __init de21041_get_srom_info (struct de_private *de)
de->media[idx].csr13,
de->media[idx].csr14,
de->media[idx].csr15);
-
+
} else if (netif_msg_probe(de))
printk("\n");
@@ -2118,7 +2118,7 @@ static int de_suspend (struct pci_dev *pdev, pm_message_t state)
spin_unlock_irq(&de->lock);
enable_irq(dev->irq);
-
+
/* Update the error counts. */
__de_get_stats(de);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index f56094102042..da8bd0d62a3f 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -41,11 +41,11 @@
Digital Semiconductor SROM Specification. The driver currently
recognises the following chips:
- DC21040 (no SROM)
- DC21041[A]
- DC21140[A]
- DC21142
- DC21143
+ DC21040 (no SROM)
+ DC21041[A]
+ DC21140[A]
+ DC21142
+ DC21143
So far the driver is known to work with the following cards:
@@ -55,7 +55,7 @@
SMC8432
SMC9332 (w/new SROM)
ZNYX31[45]
- ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
+ ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
The driver has been tested on a relatively busy network using the DE425,
DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
@@ -106,7 +106,7 @@
loading by:
insmod de4x5 io=0xghh where g = bus number
- hh = device number
+ hh = device number
NB: autoprobing for modules is now supported by default. You may just
use:
@@ -120,11 +120,11 @@
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the de4x5 configuration turned off and reboot.
5) insmod de4x5 [io=0xghh]
- 6) run the net startup bits for your new eth?? interface(s) manually
- (usually /etc/rc.inet[12] at boot time).
+ 6) run the net startup bits for your new eth?? interface(s) manually
+ (usually /etc/rc.inet[12] at boot time).
7) enjoy!
- To unload a module, turn off the associated interface(s)
+ To unload a module, turn off the associated interface(s)
'ifconfig eth?? down' then 'rmmod de4x5'.
Automedia detection is included so that in principal you can disconnect
@@ -135,7 +135,7 @@
By default, the driver will now autodetect any DECchip based card.
Should you have a need to restrict the driver to DIGITAL only cards, you
can compile with a DEC_ONLY define, or if loading as a module, use the
- 'dec_only=1' parameter.
+ 'dec_only=1' parameter.
I've changed the timing routines to use the kernel timer and scheduling
functions so that the hangs and other assorted problems that occurred
@@ -204,7 +204,7 @@
following parameters are allowed:
fdx for full duplex
- autosense to set the media/speed; with the following
+ autosense to set the media/speed; with the following
sub-parameters:
TP, TP_NW, BNC, AUI, BNC_AUI, 100Mb, 10Mb, AUTO
@@ -235,14 +235,14 @@
this automatically or include #define DE4X5_FORCE_EISA on or before
line 1040 in the driver.
- TO DO:
+ TO DO:
------
Revision History
----------------
Version Date Description
-
+
0.1 17-Nov-94 Initial writing. ALPHA code release.
0.2 13-Jan-95 Added PCI support for DE435's.
0.21 19-Jan-95 Added auto media detection.
@@ -251,7 +251,7 @@
Add request/release_region code.
Add loadable modules support for PCI.
Clean up loadable modules support.
- 0.23 28-Feb-95 Added DC21041 and DC21140 support.
+ 0.23 28-Feb-95 Added DC21041 and DC21140 support.
Fix missed frame counter value and initialisation.
Fixed EISA probe.
0.24 11-Apr-95 Change delay routine to use <linux/udelay>.
@@ -280,7 +280,7 @@
Add kernel timer code (h/w is too flaky).
Add MII based PHY autosense.
Add new multicasting code.
- Add new autosense algorithms for media/mode
+ Add new autosense algorithms for media/mode
selection using kernel scheduling/timing.
Re-formatted.
Made changes suggested by <jeff@router.patch.net>:
@@ -307,10 +307,10 @@
Add Accton to the list of broken cards.
Fix TX under-run bug for non DC21140 chips.
Fix boot command probe bug in alloc_device() as
- reported by <koen.gadeyne@barco.com> and
+ reported by <koen.gadeyne@barco.com> and
<orava@nether.tky.hut.fi>.
Add cache locks to prevent a race condition as
- reported by <csd@microplex.com> and
+ reported by <csd@microplex.com> and
<baba@beckman.uiuc.edu>.
Upgraded alloc_device() code.
0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion
@@ -322,7 +322,7 @@
with a loopback packet.
0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported
by <bhat@mundook.cs.mu.OZ.AU>
- 0.45 8-Dec-96 Include endian functions for PPC use, from work
+ 0.45 8-Dec-96 Include endian functions for PPC use, from work
by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
0.451 28-Dec-96 Added fix to allow autoprobe for modules after
suggestion from <mjacob@feral.com>.
@@ -346,14 +346,14 @@
<paubert@iram.es>.
0.52 26-Apr-97 Some changes may not credit the right people -
a disk crash meant I lost some mail.
- Change RX interrupt routine to drop rather than
- defer packets to avoid hang reported by
+ Change RX interrupt routine to drop rather than
+ defer packets to avoid hang reported by
<g.thomas@opengroup.org>.
Fix srom_exec() to return for COMPACT and type 1
infoblocks.
Added DC21142 and DC21143 functions.
Added byte counters from <phil@tazenda.demon.co.uk>
- Added SA_INTERRUPT temporary fix from
+ Added SA_INTERRUPT temporary fix from
<mjacob@feral.com>.
0.53 12-Nov-97 Fix the *_probe() to include 'eth??' name during
module load: bug reported by
@@ -363,10 +363,10 @@
Make above search independent of BIOS device scan
direction.
Completed DC2114[23] autosense functions.
- 0.531 21-Dec-97 Fix DE500-XA 100Mb/s bug reported by
+ 0.531 21-Dec-97 Fix DE500-XA 100Mb/s bug reported by
<robin@intercore.com
Fix type1_infoblock() bug introduced in 0.53, from
- problem reports by
+ problem reports by
<parmee@postecss.ncrfran.france.ncr.com> and
<jo@ice.dillingen.baynet.de>.
Added argument list to set up each board from either
@@ -374,7 +374,7 @@
Added generic MII PHY functionality to deal with
newer PHY chips.
Fix the mess in 2.1.67.
- 0.532 5-Jan-98 Fix bug in mii_get_phy() reported by
+ 0.532 5-Jan-98 Fix bug in mii_get_phy() reported by
<redhat@cococo.net>.
Fix bug in pci_probe() for 64 bit systems reported
by <belliott@accessone.com>.
@@ -398,7 +398,7 @@
version. I hope nothing is broken...
Add TX done interrupt modification from suggestion
by <Austin.Donnelly@cl.cam.ac.uk>.
- Fix is_anc_capable() bug reported by
+ Fix is_anc_capable() bug reported by
<Austin.Donnelly@cl.cam.ac.uk>.
Fix type[13]_infoblock() bug: during MII search, PHY
lp->rst not run because lp->ibn not initialised -
@@ -413,7 +413,7 @@
Add an_exception() for old ZYNX346 and fix compile
warning on PPC & SPARC, from <ecd@skynet.be>.
Fix lastPCI to correctly work with compiled in
- kernels and modules from bug report by
+ kernels and modules from bug report by
<Zlatko.Calusic@CARNet.hr> et al.
0.542 15-Sep-98 Fix dc2114x_autoconf() to stop multiple messages
when media is unconnected.
@@ -425,7 +425,7 @@
0.544 8-May-99 Fix for buggy SROM in Motorola embedded boards using
a 21143 by <mmporter@home.com>.
Change PCI/EISA bus probing order.
- 0.545 28-Nov-99 Further Moto SROM bug fix from
+ 0.545 28-Nov-99 Further Moto SROM bug fix from
<mporter@eng.mcd.mot.com>
Remove double checking for DEBUG_RX in de4x5_dbg_rx()
from report by <geert@linux-m68k.org>
@@ -434,8 +434,8 @@
variable 'pb', on a non de4x5 PCI device, in this
case a PCI bridge (DEC chip 21152). The value of
'pb' is now only initialized if a de4x5 chip is
- present.
- <france@handhelds.org>
+ present.
+ <france@handhelds.org>
0.547 08-Nov-01 Use library crc32 functions by <Matt_Domsch@dell.com>
0.548 30-Aug-03 Big 2.6 cleanup. Ported to PCI/EISA probing and
generic DMA APIs. Fixed DE425 support on Alpha.
@@ -584,7 +584,7 @@ static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
/*
** Allow per adapter set up. For modules this is simply a command line
-** parameter, e.g.:
+** parameter, e.g.:
** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
**
** For a compiled in driver, place e.g.
@@ -655,7 +655,7 @@ static c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
** Memory Alignment. Each descriptor is 4 longwords long. To force a
** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
** DESC_ALIGN. ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
+** and hence the RX descriptor ring's first entry.
*/
#define DE4X5_ALIGN4 ((u_long)4 - 1) /* 1 longword align */
#define DE4X5_ALIGN8 ((u_long)8 - 1) /* 2 longword align */
@@ -1081,8 +1081,8 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
mdelay(2); /* Wait for 2ms */\
}
-
-static int __devinit
+
+static int __devinit
de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
{
char name[DE4X5_NAME_LENGTH + 1];
@@ -1102,12 +1102,12 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
mdelay(10);
RESET_DE4X5;
-
+
if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
return -ENXIO; /* Hardware could not reset */
}
-
- /*
+
+ /*
** Now find out what kind of DC21040/DC21041/DC21140 board we have.
*/
lp->useSROM = FALSE;
@@ -1116,21 +1116,21 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
} else {
EISA_signature(name, gendev);
}
-
+
if (*name == '\0') { /* Not found a board signature */
return -ENXIO;
}
-
+
dev->base_addr = iobase;
printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase);
-
+
printk(", h/w address ");
status = get_hw_addr(dev);
for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
printk("%2.2x:", dev->dev_addr[i]);
}
printk("%2.2x,\n", dev->dev_addr[i]);
-
+
if (status != 0) {
printk(" which has an Ethernet PROM CRC error.\n");
return -ENXIO;
@@ -1171,10 +1171,10 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
}
lp->tx_ring = lp->rx_ring + NUM_RX_DESC;
-
+
/*
** Set up the RX descriptor ring (Intels)
- ** Allocate contiguous receive buffers, long word aligned (Alphas)
+ ** Allocate contiguous receive buffers, long word aligned (Alphas)
*/
#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
for (i=0; i<NUM_RX_DESC; i++) {
@@ -1210,7 +1210,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
lp->rxRingSize = NUM_RX_DESC;
lp->txRingSize = NUM_TX_DESC;
-
+
/* Write the end of list marker to the descriptor lists */
lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
@@ -1219,7 +1219,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
outl(lp->dma_rings, DE4X5_RRBA);
outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
DE4X5_TRBA);
-
+
/* Initialise the IRQ mask and Enable/Disable */
lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
lp->irq_en = IMR_NIM | IMR_AIM;
@@ -1252,7 +1252,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
mii_get_phy(dev);
}
-
+
#ifndef __sparc_v9__
printk(" and requires IRQ%d (provided by %s).\n", dev->irq,
#else
@@ -1260,11 +1260,11 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
#endif
((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
}
-
+
if (de4x5_debug & DEBUG_VERSION) {
printk(version);
}
-
+
/* The DE4X5-specific entries in the device structure. */
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gendev);
@@ -1274,23 +1274,23 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
dev->get_stats = &de4x5_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &de4x5_ioctl;
-
+
dev->mem_start = 0;
-
+
/* Fill in the generic fields of the device structure. */
if ((status = register_netdev (dev))) {
dma_free_coherent (gendev, lp->dma_size,
lp->rx_ring, lp->dma_rings);
return status;
}
-
+
/* Let the adapter sleep to save power */
yawn(dev, SLEEP);
-
+
return status;
}
-
+
static int
de4x5_open(struct net_device *dev)
{
@@ -1312,15 +1312,15 @@ de4x5_open(struct net_device *dev)
*/
yawn(dev, WAKEUP);
- /*
- ** Re-initialize the DE4X5...
+ /*
+ ** Re-initialize the DE4X5...
*/
status = de4x5_init(dev);
spin_lock_init(&lp->lock);
lp->state = OPEN;
de4x5_dbg_open(dev);
-
- if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
+
+ if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
lp->adapter_name, dev)) {
printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
@@ -1340,11 +1340,11 @@ de4x5_open(struct net_device *dev)
lp->interrupt = UNMASK_INTERRUPTS;
dev->trans_start = jiffies;
-
+
START_DE4X5;
-
+
de4x5_setup_intr(dev);
-
+
if (de4x5_debug & DEBUG_OPEN) {
printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR));
@@ -1355,7 +1355,7 @@ de4x5_open(struct net_device *dev)
printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
}
-
+
return status;
}
@@ -1369,15 +1369,15 @@ de4x5_open(struct net_device *dev)
*/
static int
de4x5_init(struct net_device *dev)
-{
+{
/* Lock out other processes whilst setting up the hardware */
netif_stop_queue(dev);
-
+
de4x5_sw_reset(dev);
-
+
/* Autoconfigure the connected port */
autoconf_media(dev);
-
+
return 0;
}
@@ -1388,7 +1388,7 @@ de4x5_sw_reset(struct net_device *dev)
u_long iobase = dev->base_addr;
int i, j, status = 0;
s32 bmr, omr;
-
+
/* Select the MII or SRL port now and RESET the MAC */
if (!lp->useSROM) {
if (lp->phy[lp->active].id != 0) {
@@ -1399,7 +1399,7 @@ de4x5_sw_reset(struct net_device *dev)
de4x5_switch_mac_port(dev);
}
- /*
+ /*
** Set the programmable burst length to 8 longwords for all the DC21140
** Fasternet chips and 4 longwords for all others: DMA errors result
** without these values. Cache align 16 long.
@@ -1416,23 +1416,23 @@ de4x5_sw_reset(struct net_device *dev)
outl(lp->dma_rings, DE4X5_RRBA);
outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
DE4X5_TRBA);
-
+
lp->rx_new = lp->rx_old = 0;
lp->tx_new = lp->tx_old = 0;
-
+
for (i = 0; i < lp->rxRingSize; i++) {
lp->rx_ring[i].status = cpu_to_le32(R_OWN);
}
-
+
for (i = 0; i < lp->txRingSize; i++) {
lp->tx_ring[i].status = cpu_to_le32(0);
}
-
+
barrier();
/* Build the setup frame depending on filtering mode */
SetMulticastFilter(dev);
-
+
load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, (struct sk_buff *)1);
outl(omr|OMR_ST, DE4X5_OMR);
@@ -1445,18 +1445,18 @@ de4x5_sw_reset(struct net_device *dev)
outl(omr, DE4X5_OMR); /* Stop everything! */
if (j == 0) {
- printk("%s: Setup frame timed out, status %08x\n", dev->name,
+ printk("%s: Setup frame timed out, status %08x\n", dev->name,
inl(DE4X5_STS));
status = -EIO;
}
-
+
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
lp->tx_old = lp->tx_new;
return status;
}
-/*
+/*
** Writes a socket buffer address to the next available transmit descriptor.
*/
static int
@@ -1469,9 +1469,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
if (lp->tx_enable == NO) { /* Cannot send for now */
- return -1;
+ return -1;
}
-
+
/*
** Clean out the TX ring asynchronously to interrupts - sometimes the
** interrupts are lost by delayed descriptor status updates relative to
@@ -1482,7 +1482,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
/* Test if cache is already locked - requeue skb if so */
- if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt)
+ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt)
return -1;
/* Transmit descriptor ring full or stale skb */
@@ -1509,10 +1509,10 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
lp->stats.tx_bytes += skb->len;
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
-
+
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
dev->trans_start = jiffies;
-
+
if (TX_BUFFS_AVAIL) {
netif_start_queue(dev); /* Another pkt may be queued */
}
@@ -1521,15 +1521,15 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
}
if (skb) de4x5_putb_cache(dev, skb);
}
-
+
lp->cache.lock = 0;
return status;
}
/*
-** The DE4X5 interrupt handler.
-**
+** The DE4X5 interrupt handler.
+**
** I/O Read/Writes through intermediate PCI bridges are never 'posted',
** so that the asserted interrupt always has some real data to work with -
** if these I/O accesses are ever changed to memory accesses, ensure the
@@ -1546,7 +1546,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
s32 imr, omr, sts, limit;
u_long iobase;
unsigned int handled = 0;
-
+
if (dev == NULL) {
printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
return IRQ_NONE;
@@ -1554,35 +1554,35 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp = netdev_priv(dev);
spin_lock(&lp->lock);
iobase = dev->base_addr;
-
+
DISABLE_IRQs; /* Ensure non re-entrancy */
if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt))
printk("%s: Re-entering the interrupt handler.\n", dev->name);
synchronize_irq(dev->irq);
-
+
for (limit=0; limit<8; limit++) {
sts = inl(DE4X5_STS); /* Read IRQ status */
outl(sts, DE4X5_STS); /* Reset the board interrupts */
-
+
if (!(sts & lp->irq_mask)) break;/* All done */
handled = 1;
-
+
if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
de4x5_rx(dev);
-
+
if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
- de4x5_tx(dev);
-
+ de4x5_tx(dev);
+
if (sts & STS_LNF) { /* TP Link has failed */
lp->irq_mask &= ~IMR_LFM;
}
-
+
if (sts & STS_UNF) { /* Transmit underrun */
de4x5_txur(dev);
}
-
+
if (sts & STS_SE) { /* Bus Error */
STOP_DE4X5;
printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1603,7 +1603,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->interrupt = UNMASK_INTERRUPTS;
ENABLE_IRQs;
spin_unlock(&lp->lock);
-
+
return IRQ_RETVAL(handled);
}
@@ -1614,11 +1614,11 @@ de4x5_rx(struct net_device *dev)
u_long iobase = dev->base_addr;
int entry;
s32 status;
-
+
for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
entry=lp->rx_new) {
status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
-
+
if (lp->rx_ovf) {
if (inl(DE4X5_MFC) & MFC_FOCM) {
de4x5_rx_ovfc(dev);
@@ -1629,7 +1629,7 @@ de4x5_rx(struct net_device *dev)
if (status & RD_FS) { /* Remember the start of frame */
lp->rx_old = entry;
}
-
+
if (status & RD_LS) { /* Valid frame status */
if (lp->tx_enable) lp->linkOK++;
if (status & RD_ES) { /* There was an error. */
@@ -1646,9 +1646,9 @@ de4x5_rx(struct net_device *dev)
struct sk_buff *skb;
short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
>> 16) - 4;
-
+
if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
- printk("%s: Insufficient memory; nuking packet.\n",
+ printk("%s: Insufficient memory; nuking packet.\n",
dev->name);
lp->stats.rx_dropped++;
} else {
@@ -1658,14 +1658,14 @@ de4x5_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
de4x5_local_stats(dev, skb->data, pkt_len);
netif_rx(skb);
-
+
/* Update stats */
dev->last_rx = jiffies;
lp->stats.rx_packets++;
lp->stats.rx_bytes += pkt_len;
}
}
-
+
/* Change buffer ownership for this frame, back to the adapter */
for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
@@ -1674,13 +1674,13 @@ de4x5_rx(struct net_device *dev)
lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
barrier();
}
-
+
/*
** Update entry information
*/
lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
}
-
+
return 0;
}
@@ -1705,20 +1705,20 @@ de4x5_tx(struct net_device *dev)
u_long iobase = dev->base_addr;
int entry;
s32 status;
-
+
for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
if (status < 0) { /* Buffer not sent yet */
break;
} else if (status != 0x7fffffff) { /* Not setup frame */
if (status & TD_ES) { /* An error happened */
- lp->stats.tx_errors++;
+ lp->stats.tx_errors++;
if (status & TD_NC) lp->stats.tx_carrier_errors++;
if (status & TD_LC) lp->stats.tx_window_errors++;
if (status & TD_UF) lp->stats.tx_fifo_errors++;
if (status & TD_EC) lp->pktStats.excessive_collisions++;
if (status & TD_DE) lp->stats.tx_aborted_errors++;
-
+
if (TX_PKT_PENDING) {
outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
}
@@ -1727,14 +1727,14 @@ de4x5_tx(struct net_device *dev)
if (lp->tx_enable) lp->linkOK++;
}
/* Update the collision counter */
- lp->stats.collisions += ((status & TD_EC) ? 16 :
+ lp->stats.collisions += ((status & TD_EC) ? 16 :
((status & TD_CC) >> 3));
/* Free the buffer. */
if (lp->tx_skb[entry] != NULL)
de4x5_free_tx_buff(lp, entry);
}
-
+
/* Update all the pointers */
lp->tx_old = (++lp->tx_old) % lp->txRingSize;
}
@@ -1746,7 +1746,7 @@ de4x5_tx(struct net_device *dev)
else
netif_start_queue(dev);
}
-
+
return 0;
}
@@ -1755,9 +1755,9 @@ de4x5_ast(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
int next_tick = DE4X5_AUTOSENSE_MS;
-
+
disable_ast(dev);
-
+
if (lp->useSROM) {
next_tick = srom_autoconf(dev);
} else if (lp->chipset == DC21140) {
@@ -1769,7 +1769,7 @@ de4x5_ast(struct net_device *dev)
}
lp->linkOK = 0;
enable_ast(dev, next_tick);
-
+
return 0;
}
@@ -1792,11 +1792,11 @@ de4x5_txur(struct net_device *dev)
}
outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
}
-
+
return 0;
}
-static int
+static int
de4x5_rx_ovfc(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -1813,7 +1813,7 @@ de4x5_rx_ovfc(struct net_device *dev)
}
outl(omr, DE4X5_OMR);
-
+
return 0;
}
@@ -1823,22 +1823,22 @@ de4x5_close(struct net_device *dev)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
s32 imr, omr;
-
+
disable_ast(dev);
netif_stop_queue(dev);
-
+
if (de4x5_debug & DEBUG_CLOSE) {
printk("%s: Shutting down ethercard, status was %8.8x.\n",
dev->name, inl(DE4X5_STS));
}
-
- /*
+
+ /*
** We stop the DE4X5 here... mask interrupts and stop TX & RX
*/
DISABLE_IRQs;
STOP_DE4X5;
-
+
/* Free the associated irq */
free_irq(dev->irq, dev);
lp->state = CLOSED;
@@ -1846,10 +1846,10 @@ de4x5_close(struct net_device *dev)
/* Free any socket buffers */
de4x5_free_rx_buffs(dev);
de4x5_free_tx_buffs(dev);
-
+
/* Put the adapter to sleep to save power */
yawn(dev, SLEEP);
-
+
return 0;
}
@@ -1858,9 +1858,9 @@ de4x5_get_stats(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
-
+
lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
-
+
return &lp->stats;
}
@@ -1886,7 +1886,7 @@ de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len)
(*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
lp->pktStats.unicast++;
}
-
+
lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
if (lp->pktStats.bins[0] == 0) { /* Reset counters */
memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
@@ -1937,11 +1937,11 @@ set_multicast_list(struct net_device *dev)
omr = inl(DE4X5_OMR);
omr |= OMR_PR;
outl(omr, DE4X5_OMR);
- } else {
+ } else {
SetMulticastFilter(dev);
- load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, (struct sk_buff *)1);
-
+
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->trans_start = jiffies;
@@ -1969,20 +1969,20 @@ SetMulticastFilter(struct net_device *dev)
omr = inl(DE4X5_OMR);
omr &= ~(OMR_PR | OMR_PM);
pa = build_setup_frame(dev, ALL); /* Build the basic frame */
-
+
if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
omr |= OMR_PM; /* Pass all multicasts */
} else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */
for (i=0;i<dev->mc_count;i++) { /* for each address in the list */
addrs=dmi->dmi_addr;
dmi=dmi->next;
- if ((*addrs & 0x01) == 1) { /* multicast address? */
+ if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
-
+
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
-
+
byte <<= 1; /* calc offset into setup frame */
if (byte & 0x02) {
byte -= 1;
@@ -1994,14 +1994,14 @@ SetMulticastFilter(struct net_device *dev)
for (j=0; j<dev->mc_count; j++) {
addrs=dmi->dmi_addr;
dmi=dmi->next;
- for (i=0; i<ETH_ALEN; i++) {
+ for (i=0; i<ETH_ALEN; i++) {
*(pa + (i&1)) = *addrs++;
if (i & 0x01) pa += 4;
}
}
}
outl(omr, DE4X5_OMR);
-
+
return;
}
@@ -2031,18 +2031,18 @@ static int __init de4x5_eisa_probe (struct device *gendev)
status = -EBUSY;
goto release_reg_1;
}
-
+
if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) {
status = -ENOMEM;
goto release_reg_2;
}
lp = netdev_priv(dev);
-
+
cfid = (u32) inl(PCI_CFID);
lp->cfrv = (u_short) inl(PCI_CFRV);
device = (cfid >> 8) & 0x00ffff00;
vendor = (u_short) cfid;
-
+
/* Read the EISA Configuration Registers */
regval = inb(EISA_REG0) & (ER0_INTL | ER0_INTT);
#ifdef CONFIG_ALPHA
@@ -2050,7 +2050,7 @@ static int __init de4x5_eisa_probe (struct device *gendev)
* care about the EISA configuration, and thus doesn't
* configure the PLX bridge properly. Oh well... Simply mimic
* the EISA config file to sort it out. */
-
+
/* EISA REG1: Assert DecChip 21040 HW Reset */
outb (ER1_IAM | 1, EISA_REG1);
mdelay (1);
@@ -2061,12 +2061,12 @@ static int __init de4x5_eisa_probe (struct device *gendev)
/* EISA REG3: R/W Burst Transfer Enable */
outb (ER3_BWE | ER3_BRE, EISA_REG3);
-
+
/* 32_bit slave/master, Preempt Time=23 bclks, Unlatched Interrupt */
outb (ER0_BSW | ER0_BMW | ER0_EPT | regval, EISA_REG0);
#endif
irq = de4x5_irq[(regval >> 1) & 0x03];
-
+
if (is_DC2114x) {
device = ((lp->cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
}
@@ -2077,7 +2077,7 @@ static int __init de4x5_eisa_probe (struct device *gendev)
outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
outl(0x00006000, PCI_CFLT);
outl(iobase, PCI_CBIO);
-
+
DevicePresent(dev, EISA_APROM);
dev->irq = irq;
@@ -2102,7 +2102,7 @@ static int __devexit de4x5_eisa_remove (struct device *device)
dev = device->driver_data;
iobase = dev->base_addr;
-
+
unregister_netdev (dev);
free_netdev (dev);
release_region (iobase + DE4X5_EISA_IO_PORTS, DE4X5_EISA_TOTAL_SIZE);
@@ -2131,11 +2131,11 @@ MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
/*
** This function searches the current bus (which is >0) for a DECchip with an
-** SROM, so that in multiport cards that have one SROM shared between multiple
+** SROM, so that in multiport cards that have one SROM shared between multiple
** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
** For single port cards this is a time waster...
*/
-static void __devinit
+static void __devinit
srom_search(struct net_device *dev, struct pci_dev *pdev)
{
u_char pb;
@@ -2163,7 +2163,7 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
/* Set the device number information */
lp->device = PCI_SLOT(this_dev->devfn);
lp->bus_num = pb;
-
+
/* Set the chipset information */
if (is_DC2114x) {
device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
@@ -2176,7 +2176,7 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
/* Fetch the IRQ to be used */
irq = this_dev->irq;
if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
-
+
/* Check if I/O accesses are enabled */
pci_read_config_word(this_dev, PCI_COMMAND, &status);
if (!(status & PCI_COMMAND_IO)) continue;
@@ -2254,7 +2254,7 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
lp = netdev_priv(dev);
lp->bus = PCI;
lp->bus_num = 0;
-
+
/* Search for an SROM on this bus */
if (lp->bus_num != pb) {
lp->bus_num = pb;
@@ -2267,7 +2267,7 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
/* Set the device number information */
lp->device = dev_num;
lp->bus_num = pb;
-
+
/* Set the chipset information */
if (is_DC2114x) {
device = ((lp->cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
@@ -2283,7 +2283,7 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
error = -ENODEV;
goto free_dev;
}
-
+
/* Check if I/O accesses and Bus Mastering are enabled */
pci_read_config_word(pdev, PCI_COMMAND, &status);
#ifdef __powerpc__
@@ -2322,7 +2322,7 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
}
dev->irq = irq;
-
+
if ((error = de4x5_hw_init(dev, iobase, &pdev->dev))) {
goto release;
}
@@ -2377,7 +2377,7 @@ static struct pci_driver de4x5_pci_driver = {
** Auto configure the media here rather than setting the port at compile
** time. This routine is called by de4x5_init() and when a loss of media is
** detected (excessive collisions, loss of carrier, no carrier or link fail
-** [TP] or no recent receive activity) to check whether the user has been
+** [TP] or no recent receive activity) to check whether the user has been
** sneaky and changed the port on us.
*/
static int
@@ -2405,7 +2405,7 @@ autoconf_media(struct net_device *dev)
}
enable_ast(dev, next_tick);
-
+
return (lp->media);
}
@@ -2428,7 +2428,7 @@ dc21040_autoconf(struct net_device *dev)
u_long iobase = dev->base_addr;
int next_tick = DE4X5_AUTOSENSE_MS;
s32 imr;
-
+
switch (lp->media) {
case INIT:
DISABLE_IRQs;
@@ -2447,36 +2447,36 @@ dc21040_autoconf(struct net_device *dev)
lp->local_state = 0;
next_tick = dc21040_autoconf(dev);
break;
-
+
case TP:
- next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
+ next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
TP_SUSPECT, test_tp);
break;
-
+
case TP_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
break;
-
+
case BNC:
case AUI:
case BNC_AUI:
- next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
+ next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
BNC_AUI_SUSPECT, ping_media);
break;
-
+
case BNC_AUI_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
break;
-
+
case EXT_SIA:
- next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
+ next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
NC, EXT_SIA_SUSPECT, ping_media);
break;
-
+
case EXT_SIA_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
break;
-
+
case NC:
/* default to TP for all */
reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
@@ -2488,13 +2488,13 @@ dc21040_autoconf(struct net_device *dev)
lp->tx_enable = NO;
break;
}
-
+
return next_tick;
}
static int
dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeout,
- int next_state, int suspect_state,
+ int next_state, int suspect_state,
int (*fn)(struct net_device *, int))
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -2507,7 +2507,7 @@ dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeo
lp->local_state++;
next_tick = 500;
break;
-
+
case 1:
if (!lp->tx_enable) {
linkBad = fn(dev, timeout);
@@ -2527,7 +2527,7 @@ dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeo
}
break;
}
-
+
return next_tick;
}
@@ -2582,7 +2582,7 @@ dc21041_autoconf(struct net_device *dev)
u_long iobase = dev->base_addr;
s32 sts, irqs, irq_mask, imr, omr;
int next_tick = DE4X5_AUTOSENSE_MS;
-
+
switch (lp->media) {
case INIT:
DISABLE_IRQs;
@@ -2603,7 +2603,7 @@ dc21041_autoconf(struct net_device *dev)
lp->local_state = 0;
next_tick = dc21041_autoconf(dev);
break;
-
+
case TP_NW:
if (lp->timeout < 0) {
omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
@@ -2623,7 +2623,7 @@ dc21041_autoconf(struct net_device *dev)
next_tick = dc21041_autoconf(dev);
}
break;
-
+
case ANS:
if (!lp->tx_enable) {
irqs = STS_LNP;
@@ -2645,11 +2645,11 @@ dc21041_autoconf(struct net_device *dev)
next_tick = 3000;
}
break;
-
+
case ANS_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
break;
-
+
case TP:
if (!lp->tx_enable) {
if (lp->timeout < 0) {
@@ -2679,11 +2679,11 @@ dc21041_autoconf(struct net_device *dev)
next_tick = 3000;
}
break;
-
+
case TP_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
break;
-
+
case AUI:
if (!lp->tx_enable) {
if (lp->timeout < 0) {
@@ -2709,11 +2709,11 @@ dc21041_autoconf(struct net_device *dev)
next_tick = 3000;
}
break;
-
+
case AUI_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
break;
-
+
case BNC:
switch (lp->local_state) {
case 0:
@@ -2731,7 +2731,7 @@ dc21041_autoconf(struct net_device *dev)
next_tick = dc21041_autoconf(dev);
}
break;
-
+
case 1:
if (!lp->tx_enable) {
if ((sts = ping_media(dev, 3000)) < 0) {
@@ -2751,11 +2751,11 @@ dc21041_autoconf(struct net_device *dev)
break;
}
break;
-
+
case BNC_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
break;
-
+
case NC:
omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
outl(omr | OMR_FDX, DE4X5_OMR);
@@ -2768,7 +2768,7 @@ dc21041_autoconf(struct net_device *dev)
lp->tx_enable = NO;
break;
}
-
+
return next_tick;
}
@@ -2784,9 +2784,9 @@ dc21140m_autoconf(struct net_device *dev)
int ana, anlpa, cap, cr, slnk, sr;
int next_tick = DE4X5_AUTOSENSE_MS;
u_long imr, omr, iobase = dev->base_addr;
-
+
switch(lp->media) {
- case INIT:
+ case INIT:
if (lp->timeout < 0) {
DISABLE_IRQs;
lp->tx_enable = FALSE;
@@ -2813,7 +2813,7 @@ dc21140m_autoconf(struct net_device *dev)
lp->media = _100Mb;
} else if (lp->autosense == _10Mb) {
lp->media = _10Mb;
- } else if ((lp->autosense == AUTO) &&
+ } else if ((lp->autosense == AUTO) &&
((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
@@ -2831,7 +2831,7 @@ dc21140m_autoconf(struct net_device *dev)
next_tick = dc21140m_autoconf(dev);
}
break;
-
+
case ANS:
switch (lp->local_state) {
case 0:
@@ -2851,7 +2851,7 @@ dc21140m_autoconf(struct net_device *dev)
next_tick = dc21140m_autoconf(dev);
}
break;
-
+
case 1:
if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
next_tick = sr & ~TIMER_CB;
@@ -2862,7 +2862,7 @@ dc21140m_autoconf(struct net_device *dev)
lp->tmp = MII_SR_ASSC;
anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
- if (!(anlpa & MII_ANLPA_RF) &&
+ if (!(anlpa & MII_ANLPA_RF) &&
(cap = anlpa & MII_ANLPA_TAF & ana)) {
if (cap & MII_ANA_100M) {
lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
@@ -2879,10 +2879,10 @@ dc21140m_autoconf(struct net_device *dev)
break;
}
break;
-
+
case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
if (lp->timeout < 0) {
- lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
+ lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
(~gep_rd(dev) & GEP_LNP));
SET_100Mb_PDET;
}
@@ -2899,7 +2899,7 @@ dc21140m_autoconf(struct net_device *dev)
next_tick = dc21140m_autoconf(dev);
}
break;
-
+
case _100Mb: /* Set 100Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
@@ -2933,7 +2933,7 @@ dc21140m_autoconf(struct net_device *dev)
}
}
break;
-
+
case NC:
if (lp->media != lp->c_media) {
de4x5_dbg_media(dev);
@@ -2943,7 +2943,7 @@ dc21140m_autoconf(struct net_device *dev)
lp->tx_enable = FALSE;
break;
}
-
+
return next_tick;
}
@@ -3002,7 +3002,7 @@ dc2114x_autoconf(struct net_device *dev)
lp->media = AUI;
} else {
lp->media = SPD_DET;
- if ((lp->infoblock_media == ANS) &&
+ if ((lp->infoblock_media == ANS) &&
((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
@@ -3014,7 +3014,7 @@ dc2114x_autoconf(struct net_device *dev)
next_tick = dc2114x_autoconf(dev);
}
break;
-
+
case ANS:
switch (lp->local_state) {
case 0:
@@ -3034,7 +3034,7 @@ dc2114x_autoconf(struct net_device *dev)
next_tick = dc2114x_autoconf(dev);
}
break;
-
+
case 1:
if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
next_tick = sr & ~TIMER_CB;
@@ -3045,7 +3045,7 @@ dc2114x_autoconf(struct net_device *dev)
lp->tmp = MII_SR_ASSC;
anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
- if (!(anlpa & MII_ANLPA_RF) &&
+ if (!(anlpa & MII_ANLPA_RF) &&
(cap = anlpa & MII_ANLPA_TAF & ana)) {
if (cap & MII_ANA_100M) {
lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
@@ -3087,11 +3087,11 @@ dc2114x_autoconf(struct net_device *dev)
next_tick = 3000;
}
break;
-
+
case AUI_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
break;
-
+
case BNC:
switch (lp->local_state) {
case 0:
@@ -3109,7 +3109,7 @@ dc2114x_autoconf(struct net_device *dev)
next_tick = dc2114x_autoconf(dev);
}
break;
-
+
case 1:
if (!lp->tx_enable) {
if ((sts = ping_media(dev, 3000)) < 0) {
@@ -3130,11 +3130,11 @@ dc2114x_autoconf(struct net_device *dev)
break;
}
break;
-
+
case BNC_SUSPECT:
next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
break;
-
+
case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
if (srom_map_media(dev) < 0) {
lp->tcount++;
@@ -3161,7 +3161,7 @@ dc2114x_autoconf(struct net_device *dev)
next_tick = dc2114x_autoconf(dev);
} else if (((lp->media == _100Mb) && is_100_up(dev)) ||
(((lp->media == _10Mb) || (lp->media == TP) ||
- (lp->media == BNC) || (lp->media == AUI)) &&
+ (lp->media == BNC) || (lp->media == AUI)) &&
is_10_up(dev))) {
next_tick = dc2114x_autoconf(dev);
} else {
@@ -3169,7 +3169,7 @@ dc2114x_autoconf(struct net_device *dev)
lp->media = INIT;
}
break;
-
+
case _10Mb:
next_tick = 3000;
if (!lp->tx_enable) {
@@ -3208,7 +3208,7 @@ printk("Huh?: media:%02x\n", lp->media);
lp->media = INIT;
break;
}
-
+
return next_tick;
}
@@ -3231,7 +3231,7 @@ srom_map_media(struct net_device *dev)
struct de4x5_private *lp = netdev_priv(dev);
lp->fdx = 0;
- if (lp->infoblock_media == lp->media)
+ if (lp->infoblock_media == lp->media)
return 0;
switch(lp->infoblock_media) {
@@ -3270,7 +3270,7 @@ srom_map_media(struct net_device *dev)
case SROM_100BASEFF:
if (!lp->params.fdx) return -1;
lp->fdx = TRUE;
- case SROM_100BASEF:
+ case SROM_100BASEF:
if (lp->params.fdx && !lp->fdx) return -1;
lp->media = _100Mb;
break;
@@ -3280,8 +3280,8 @@ srom_map_media(struct net_device *dev)
lp->fdx = lp->params.fdx;
break;
- default:
- printk("%s: Bad media code [%d] detected in SROM!\n", dev->name,
+ default:
+ printk("%s: Bad media code [%d] detected in SROM!\n", dev->name,
lp->infoblock_media);
return -1;
break;
@@ -3359,7 +3359,7 @@ test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14,
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
s32 sts, csr12;
-
+
if (lp->timeout < 0) {
lp->timeout = msec/100;
if (!lp->useSROM) { /* Already done if by SROM, else dc2104[01] */
@@ -3372,22 +3372,22 @@ test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14,
/* clear all pending interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
-
+
/* clear csr12 NRA and SRA bits */
if ((lp->chipset == DC21041) || lp->useSROM) {
csr12 = inl(DE4X5_SISR);
outl(csr12, DE4X5_SISR);
}
}
-
+
sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+
if (!(sts & irqs) && --lp->timeout) {
sts = 100 | TIMER_CB;
} else {
lp->timeout = -1;
}
-
+
return sts;
}
@@ -3397,11 +3397,11 @@ test_tp(struct net_device *dev, s32 msec)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
int sisr;
-
+
if (lp->timeout < 0) {
lp->timeout = msec/100;
}
-
+
sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
if (sisr && --lp->timeout) {
@@ -3409,7 +3409,7 @@ test_tp(struct net_device *dev, s32 msec)
} else {
lp->timeout = -1;
}
-
+
return sisr;
}
@@ -3436,7 +3436,7 @@ test_for_100Mb(struct net_device *dev, int msec)
lp->timeout = msec/SAMPLE_INTERVAL;
}
}
-
+
if (lp->phy[lp->active].id || lp->useSROM) {
gep = is_100_up(dev) | is_spd_100(dev);
} else {
@@ -3447,7 +3447,7 @@ test_for_100Mb(struct net_device *dev, int msec)
} else {
lp->timeout = -1;
}
-
+
return gep;
}
@@ -3459,13 +3459,13 @@ wait_for_link(struct net_device *dev)
if (lp->timeout < 0) {
lp->timeout = 1;
}
-
+
if (lp->timeout--) {
return TIMER_CB;
} else {
lp->timeout = -1;
}
-
+
return 0;
}
@@ -3479,21 +3479,21 @@ test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
struct de4x5_private *lp = netdev_priv(dev);
int test;
u_long iobase = dev->base_addr;
-
+
if (lp->timeout < 0) {
lp->timeout = msec/100;
}
-
+
if (pol) pol = ~0;
reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
test = (reg ^ pol) & mask;
-
+
if (test && --lp->timeout) {
reg = 100 | TIMER_CB;
} else {
lp->timeout = -1;
}
-
+
return reg;
}
@@ -3503,7 +3503,7 @@ is_spd_100(struct net_device *dev)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
int spd;
-
+
if (lp->useMII) {
spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
spd = ~(spd ^ lp->phy[lp->active].spd.value);
@@ -3517,7 +3517,7 @@ is_spd_100(struct net_device *dev)
spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
(lp->linkOK & ~lp->asBitValid);
}
-
+
return spd;
}
@@ -3526,7 +3526,7 @@ is_100_up(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
-
+
if (lp->useMII) {
/* Double read for sticky bits & temporary drops */
mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
@@ -3547,7 +3547,7 @@ is_10_up(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
-
+
if (lp->useMII) {
/* Double read for sticky bits & temporary drops */
mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
@@ -3570,7 +3570,7 @@ is_anc_capable(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
-
+
if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
@@ -3590,24 +3590,24 @@ ping_media(struct net_device *dev, int msec)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
int sisr;
-
+
if (lp->timeout < 0) {
lp->timeout = msec/100;
-
+
lp->tmp = lp->tx_new; /* Remember the ring position */
load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), (struct sk_buff *)1);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD);
}
-
+
sisr = inl(DE4X5_SISR);
- if ((!(sisr & SISR_NCR)) &&
- ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
+ if ((!(sisr & SISR_NCR)) &&
+ ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
(--lp->timeout)) {
sisr = 100 | TIMER_CB;
} else {
- if ((!(sisr & SISR_NCR)) &&
+ if ((!(sisr & SISR_NCR)) &&
!(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
lp->timeout) {
sisr = 0;
@@ -3616,7 +3616,7 @@ ping_media(struct net_device *dev, int msec)
}
lp->timeout = -1;
}
-
+
return sisr;
}
@@ -3668,7 +3668,7 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len)
} else { /* Linear buffer */
memcpy(skb_put(p,len),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,len);
}
-
+
return p;
#endif
}
@@ -3751,23 +3751,23 @@ de4x5_rst_desc_ring(struct net_device *dev)
outl(lp->dma_rings, DE4X5_RRBA);
outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
DE4X5_TRBA);
-
+
lp->rx_new = lp->rx_old = 0;
lp->tx_new = lp->tx_old = 0;
-
+
for (i = 0; i < lp->rxRingSize; i++) {
lp->rx_ring[i].status = cpu_to_le32(R_OWN);
}
-
+
for (i = 0; i < lp->txRingSize; i++) {
lp->tx_ring[i].status = cpu_to_le32(0);
}
-
+
barrier();
lp->cache.save_cnt--;
START_DE4X5;
}
-
+
return;
}
@@ -3792,7 +3792,7 @@ de4x5_cache_state(struct net_device *dev, int flag)
gep_wr(lp->cache.gepc, dev);
gep_wr(lp->cache.gep, dev);
} else {
- reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
+ reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
lp->cache.csr15);
}
break;
@@ -3854,25 +3854,25 @@ test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
s32 sts, ans;
-
+
if (lp->timeout < 0) {
lp->timeout = msec/100;
outl(irq_mask, DE4X5_IMR);
-
+
/* clear all pending interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
}
-
+
ans = inl(DE4X5_SISR) & SISR_ANS;
sts = inl(DE4X5_STS) & ~TIMER_CB;
-
+
if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
sts = 100 | TIMER_CB;
} else {
lp->timeout = -1;
}
-
+
return sts;
}
@@ -3882,7 +3882,7 @@ de4x5_setup_intr(struct net_device *dev)
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
s32 imr, sts;
-
+
if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */
imr = 0;
UNMASK_IRQs;
@@ -3890,7 +3890,7 @@ de4x5_setup_intr(struct net_device *dev)
outl(sts, DE4X5_STS);
ENABLE_IRQs;
}
-
+
return;
}
@@ -3936,17 +3936,17 @@ create_packet(struct net_device *dev, char *frame, int len)
{
int i;
char *buf = frame;
-
+
for (i=0; i<ETH_ALEN; i++) { /* Use this source address */
*buf++ = dev->dev_addr[i];
}
for (i=0; i<ETH_ALEN; i++) { /* Use this destination address */
*buf++ = dev->dev_addr[i];
}
-
+
*buf++ = 0; /* Packet length (2 bytes) */
*buf++ = 1;
-
+
return;
}
@@ -3978,7 +3978,7 @@ static int
PCI_signature(char *name, struct de4x5_private *lp)
{
int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
-
+
if (lp->chipset == DC21040) {
strcpy(name, "DE434/5");
return status;
@@ -4007,7 +4007,7 @@ PCI_signature(char *name, struct de4x5_private *lp)
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
lp->useSROM = TRUE;
}
-
+
return status;
}
@@ -4024,7 +4024,7 @@ DevicePresent(struct net_device *dev, u_long aprom_addr)
{
int i, j=0;
struct de4x5_private *lp = netdev_priv(dev);
-
+
if (lp->chipset == DC21040) {
if (lp->bus == EISA) {
enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */
@@ -4049,7 +4049,7 @@ DevicePresent(struct net_device *dev, u_long aprom_addr)
}
de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
}
-
+
return;
}
@@ -4071,11 +4071,11 @@ enet_addr_rst(u_long aprom_addr)
short sigLength=0;
s8 data;
int i, j;
-
+
dev.llsig.a = ETH_PROM_SIG;
dev.llsig.b = ETH_PROM_SIG;
sigLength = sizeof(u32) << 1;
-
+
for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
data = inb(aprom_addr);
if (dev.Sig[j] == data) { /* track signature */
@@ -4088,7 +4088,7 @@ enet_addr_rst(u_long aprom_addr)
}
}
}
-
+
return;
}
@@ -4111,7 +4111,7 @@ get_hw_addr(struct net_device *dev)
for (i=0,k=0,j=0;j<3;j++) {
k <<= 1;
if (k > 0xffff) k-=0xffff;
-
+
if (lp->bus == PCI) {
if (lp->chipset == DC21040) {
while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -4133,11 +4133,11 @@ get_hw_addr(struct net_device *dev)
k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
dev->dev_addr[i++] = (u_char) tmp;
}
-
+
if (k > 0xffff) k-=0xffff;
}
if (k == 0xffff) k=0;
-
+
if (lp->bus == PCI) {
if (lp->chipset == DC21040) {
while ((tmp = inl(DE4X5_APROM)) < 0);
@@ -4156,7 +4156,7 @@ get_hw_addr(struct net_device *dev)
srom_repair(dev, broken);
#ifdef CONFIG_PPC_MULTIPLATFORM
- /*
+ /*
** If the address starts with 00 a0, we have to bit-reverse
** each byte of the address.
*/
@@ -4245,7 +4245,7 @@ test_bad_enet(struct net_device *dev, int status)
for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
if ((tmp == 0) || (tmp == 0x5fa)) {
- if ((lp->chipset == last.chipset) &&
+ if ((lp->chipset == last.chipset) &&
(lp->bus_num == last.bus) && (lp->bus_num > 0)) {
for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
for (i=ETH_ALEN-1; i>2; --i) {
@@ -4275,7 +4275,7 @@ test_bad_enet(struct net_device *dev, int status)
static int
an_exception(struct de4x5_private *lp)
{
- if ((*(u_short *)lp->srom.sub_vendor_id == 0x00c0) &&
+ if ((*(u_short *)lp->srom.sub_vendor_id == 0x00c0) &&
(*(u_short *)lp->srom.sub_system_id == 0x95e0)) {
return -1;
}
@@ -4290,11 +4290,11 @@ static short
srom_rd(u_long addr, u_char offset)
{
sendto_srom(SROM_RD | SROM_SR, addr);
-
+
srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
-
+
return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
}
@@ -4304,7 +4304,7 @@ srom_latch(u_int command, u_long addr)
sendto_srom(command, addr);
sendto_srom(command | DT_CLK, addr);
sendto_srom(command, addr);
-
+
return;
}
@@ -4314,7 +4314,7 @@ srom_command(u_int command, u_long addr)
srom_latch(command, addr);
srom_latch(command, addr);
srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
+
return;
}
@@ -4322,15 +4322,15 @@ static void
srom_address(u_int command, u_long addr, u_char offset)
{
int i, a;
-
+
a = offset << 2;
for (i=0; i<6; i++, a <<= 1) {
srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr);
}
udelay(1);
-
+
i = (getfrom_srom(addr) >> 3) & 0x01;
-
+
return;
}
@@ -4340,17 +4340,17 @@ srom_data(u_int command, u_long addr)
int i;
short word = 0;
s32 tmp;
-
+
for (i=0; i<16; i++) {
sendto_srom(command | DT_CLK, addr);
tmp = getfrom_srom(addr);
sendto_srom(command, addr);
-
+
word = (word << 1) | ((tmp >> 3) & 0x01);
}
-
+
sendto_srom(command & 0x0000ff00, addr);
-
+
return word;
}
@@ -4359,13 +4359,13 @@ static void
srom_busy(u_int command, u_long addr)
{
sendto_srom((command & 0x0000ff00) | DT_CS, addr);
-
+
while (!((getfrom_srom(addr) >> 3) & 0x01)) {
mdelay(1);
}
-
+
sendto_srom(command & 0x0000ff00, addr);
-
+
return;
}
*/
@@ -4375,7 +4375,7 @@ sendto_srom(u_int command, u_long addr)
{
outl(command, addr);
udelay(1);
-
+
return;
}
@@ -4383,10 +4383,10 @@ static int
getfrom_srom(u_long addr)
{
s32 tmp;
-
+
tmp = inl(addr);
udelay(1);
-
+
return tmp;
}
@@ -4403,7 +4403,7 @@ srom_infoleaf_info(struct net_device *dev)
}
if (i == INFOLEAF_SIZE) {
lp->useSROM = FALSE;
- printk("%s: Cannot find correct chipset for SROM decoding!\n",
+ printk("%s: Cannot find correct chipset for SROM decoding!\n",
dev->name);
return -ENXIO;
}
@@ -4420,7 +4420,7 @@ srom_infoleaf_info(struct net_device *dev)
}
if (i == 0) {
lp->useSROM = FALSE;
- printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
+ printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
dev->name, lp->device);
return -ENXIO;
}
@@ -4494,9 +4494,9 @@ srom_exec(struct net_device *dev, u_char *p)
if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
if (lp->chipset != DC21140) RESET_SIA;
-
+
while (count--) {
- gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
+ gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
*p++ : TWIDDLE(w++)), dev);
mdelay(2); /* 2ms per action */
}
@@ -4514,13 +4514,13 @@ srom_exec(struct net_device *dev, u_char *p)
** unless I implement the DC21041 SROM functions. There's no need
** since the existing code will be satisfactory for all boards.
*/
-static int
+static int
dc21041_infoleaf(struct net_device *dev)
{
return DE4X5_AUTOSENSE_MS;
}
-static int
+static int
dc21140_infoleaf(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4558,7 +4558,7 @@ dc21140_infoleaf(struct net_device *dev)
return next_tick & ~TIMER_CB;
}
-static int
+static int
dc21142_infoleaf(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4593,7 +4593,7 @@ dc21142_infoleaf(struct net_device *dev)
return next_tick & ~TIMER_CB;
}
-static int
+static int
dc21143_infoleaf(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4631,7 +4631,7 @@ dc21143_infoleaf(struct net_device *dev)
** The compact infoblock is only designed for DC21140[A] chips, so
** we'll reuse the dc21140m_autoconf function. Non MII media only.
*/
-static int
+static int
compact_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4671,7 +4671,7 @@ compact_infoblock(struct net_device *dev, u_char count, u_char *p)
/*
** This block describes non MII media for the DC21140[A] only.
*/
-static int
+static int
type0_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4711,7 +4711,7 @@ type0_infoblock(struct net_device *dev, u_char count, u_char *p)
/* These functions are under construction! */
-static int
+static int
type1_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4750,7 +4750,7 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p)
return dc21140m_autoconf(dev);
}
-static int
+static int
type2_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4791,7 +4791,7 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p)
return dc2114x_autoconf(dev);
}
-static int
+static int
type3_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4833,7 +4833,7 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p)
return dc2114x_autoconf(dev);
}
-static int
+static int
type4_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4878,7 +4878,7 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p)
** This block type provides information for resetting external devices
** (chips) through the General Purpose Register.
*/
-static int
+static int
type5_infoblock(struct net_device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = netdev_priv(dev);
@@ -4916,7 +4916,7 @@ mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
mii_address(phyaddr, ioaddr); /* PHY address to be accessed */
mii_address(phyreg, ioaddr); /* PHY Register to read */
mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */
-
+
return mii_rdata(ioaddr); /* Read data */
}
@@ -4931,7 +4931,7 @@ mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */
data = mii_swap(data, 16); /* Swap data bit ordering */
mii_wdata(data, 16, ioaddr); /* Write data */
-
+
return;
}
@@ -4940,12 +4940,12 @@ mii_rdata(u_long ioaddr)
{
int i;
s32 tmp = 0;
-
+
for (i=0; i<16; i++) {
tmp <<= 1;
tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
}
-
+
return tmp;
}
@@ -4953,12 +4953,12 @@ static void
mii_wdata(int data, int len, u_long ioaddr)
{
int i;
-
+
for (i=0; i<len; i++) {
sendto_mii(MII_MWR | MII_WR, data, ioaddr);
data >>= 1;
}
-
+
return;
}
@@ -4966,13 +4966,13 @@ static void
mii_address(u_char addr, u_long ioaddr)
{
int i;
-
+
addr = mii_swap(addr, 5);
for (i=0; i<5; i++) {
sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
addr >>= 1;
}
-
+
return;
}
@@ -4980,12 +4980,12 @@ static void
mii_ta(u_long rw, u_long ioaddr)
{
if (rw == MII_STWR) {
- sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
- sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
+ sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
+ sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
} else {
getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */
}
-
+
return;
}
@@ -4993,13 +4993,13 @@ static int
mii_swap(int data, int len)
{
int i, tmp = 0;
-
+
for (i=0; i<len; i++) {
tmp <<= 1;
tmp |= (data & 1);
data >>= 1;
}
-
+
return tmp;
}
@@ -5007,13 +5007,13 @@ static void
sendto_mii(u32 command, int data, u_long ioaddr)
{
u32 j;
-
+
j = (data & 1) << 17;
outl(command | j, ioaddr);
udelay(1);
outl(command | MII_MDC | j, ioaddr);
udelay(1);
-
+
return;
}
@@ -5024,7 +5024,7 @@ getfrom_mii(u32 command, u_long ioaddr)
udelay(1);
outl(command | MII_MDC, ioaddr);
udelay(1);
-
+
return ((inl(ioaddr) >> 19) & 1);
}
@@ -5085,7 +5085,7 @@ mii_get_phy(struct net_device *dev)
u_long iobase = dev->base_addr;
int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
int id;
-
+
lp->active = 0;
lp->useMII = TRUE;
@@ -5094,7 +5094,7 @@ mii_get_phy(struct net_device *dev)
lp->phy[lp->active].addr = i;
if (i==0) n++; /* Count cycles */
while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
- id = mii_get_oui(i, DE4X5_MII);
+ id = mii_get_oui(i, DE4X5_MII);
if ((id == 0) || (id == 65535)) continue; /* Valid ID? */
for (j=0; j<limit; j++) { /* Search PHY table */
if (id != phy_info[j].id) continue; /* ID match? */
@@ -5133,7 +5133,7 @@ mii_get_phy(struct net_device *dev)
for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
-
+
de4x5_dbg_mii(dev, k);
}
}
@@ -5148,12 +5148,12 @@ build_setup_frame(struct net_device *dev, int mode)
struct de4x5_private *lp = netdev_priv(dev);
int i;
char *pa = lp->setup_frame;
-
+
/* Initialise the setup frame */
if (mode == ALL) {
memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
}
-
+
if (lp->setup_f == HASH_PERF) {
for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
*(pa + i) = dev->dev_addr[i]; /* Host address */
@@ -5170,7 +5170,7 @@ build_setup_frame(struct net_device *dev, int mode)
if (i & 0x01) pa += 4;
}
}
-
+
return pa; /* Points to the next entry */
}
@@ -5178,7 +5178,7 @@ static void
enable_ast(struct net_device *dev, u32 time_out)
{
timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-
+
return;
}
@@ -5186,9 +5186,9 @@ static void
disable_ast(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
-
+
del_timer(&lp->timer);
-
+
return;
}
@@ -5207,10 +5207,10 @@ de4x5_switch_mac_port(struct net_device *dev)
omr |= lp->infoblock_csr6;
if (omr & OMR_PS) omr |= OMR_HBD;
outl(omr, DE4X5_OMR);
-
+
/* Soft Reset */
RESET_DE4X5;
-
+
/* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
if (lp->chipset == DC21140) {
gep_wr(lp->cache.gepc, dev);
@@ -5263,21 +5263,21 @@ timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long mse
{
struct de4x5_private *lp = netdev_priv(dev);
int dt;
-
+
/* First, cancel any pending timer events */
del_timer(&lp->timer);
-
+
/* Convert msec to ticks */
dt = (msec * HZ) / 1000;
if (dt==0) dt=1;
-
+
/* Set up timer */
init_timer(&lp->timer);
lp->timer.expires = jiffies + dt;
lp->timer.function = fn;
lp->timer.data = data;
add_timer(&lp->timer);
-
+
return;
}
@@ -5375,7 +5375,7 @@ de4x5_dbg_open(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
int i;
-
+
if (de4x5_debug & DEBUG_OPEN) {
printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
printk("\tphysical address: ");
@@ -5413,11 +5413,11 @@ de4x5_dbg_open(struct net_device *dev)
}
}
printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
- printk("Ring size: \nRX: %d\nTX: %d\n",
- (short)lp->rxRingSize,
- (short)lp->txRingSize);
+ printk("Ring size: \nRX: %d\nTX: %d\n",
+ (short)lp->rxRingSize,
+ (short)lp->txRingSize);
}
-
+
return;
}
@@ -5426,7 +5426,7 @@ de4x5_dbg_mii(struct net_device *dev, int k)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
-
+
if (de4x5_debug & DEBUG_MII) {
printk("\nMII device address: %d\n", lp->phy[k].addr);
printk("MII CR: %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
@@ -5445,7 +5445,7 @@ de4x5_dbg_mii(struct net_device *dev, int k)
printk("MII 20: %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
}
}
-
+
return;
}
@@ -5453,17 +5453,17 @@ static void
de4x5_dbg_media(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
-
+
if (lp->media != lp->c_media) {
if (de4x5_debug & DEBUG_MEDIA) {
printk("%s: media is %s%s\n", dev->name,
(lp->media == NC ? "unconnected, link down or incompatible connection" :
(lp->media == TP ? "TP" :
(lp->media == ANS ? "TP/Nway" :
- (lp->media == BNC ? "BNC" :
- (lp->media == AUI ? "AUI" :
- (lp->media == BNC_AUI ? "BNC/AUI" :
- (lp->media == EXT_SIA ? "EXT SIA" :
+ (lp->media == BNC ? "BNC" :
+ (lp->media == AUI ? "AUI" :
+ (lp->media == BNC_AUI ? "BNC/AUI" :
+ (lp->media == EXT_SIA ? "EXT SIA" :
(lp->media == _100Mb ? "100Mb/s" :
(lp->media == _10Mb ? "10Mb/s" :
"???"
@@ -5471,7 +5471,7 @@ de4x5_dbg_media(struct net_device *dev)
}
lp->c_media = lp->media;
}
-
+
return;
}
@@ -5554,7 +5554,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
u32 lval[36];
} tmp;
u_long flags = 0;
-
+
switch(ioc->cmd) {
case DE4X5_GET_HWADDR: /* Get the hardware address */
ioc->len = ETH_ALEN;
@@ -5575,7 +5575,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
- load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, (struct sk_buff *)1);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
@@ -5617,8 +5617,8 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
spin_lock_irqsave(&lp->lock, flags);
memcpy(&statbuf, &lp->pktStats, ioc->len);
spin_unlock_irqrestore(&lp->lock, flags);
- if (copy_to_user(ioc->data, &statbuf, ioc->len))
- return -EFAULT;
+ if (copy_to_user(ioc->data, &statbuf, ioc->len))
+ return -EFAULT;
break;
}
case DE4X5_CLR_STATS: /* Zero out the driver statistics */
@@ -5652,9 +5652,9 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
ioc->len = j;
if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
break;
-
+
#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
-/*
+/*
case DE4X5_DUMP:
j = 0;
tmp.addr[j++] = dev->irq;
@@ -5664,7 +5664,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
tmp.addr[j++] = lp->rxRingSize;
tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
-
+
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
@@ -5677,7 +5677,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
}
tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
@@ -5690,14 +5690,14 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
}
tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-
+
for (i=0;i<lp->rxRingSize;i++){
tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
}
for (i=0;i<lp->txRingSize;i++){
tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
}
-
+
tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4;
tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4;
@@ -5706,18 +5706,18 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
tmp.lval[j>>2] = inl(DE4X5_STS); j+=4;
tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4;
- tmp.lval[j>>2] = lp->chipset; j+=4;
+ tmp.lval[j>>2] = lp->chipset; j+=4;
if (lp->chipset == DC21140) {
tmp.lval[j>>2] = gep_rd(dev); j+=4;
} else {
tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
}
- tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
+ tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
- tmp.lval[j>>2] = lp->active; j+=4;
+ tmp.lval[j>>2] = lp->active; j+=4;
tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
@@ -5734,10 +5734,10 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
}
}
-
+
tmp.addr[j++] = lp->txRingSize;
tmp.addr[j++] = netif_queue_stopped(dev);
-
+
ioc->len = j;
if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
break;
@@ -5746,7 +5746,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
default:
return -EOPNOTSUPP;
}
-
+
return status;
}
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index ad37a4074302..57226e5eb8a6 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -38,11 +38,11 @@
/*
** EISA Register Address Map
*/
-#define EISA_ID iobase+0x0c80 /* EISA ID Registers */
-#define EISA_ID0 iobase+0x0c80 /* EISA ID Register 0 */
-#define EISA_ID1 iobase+0x0c81 /* EISA ID Register 1 */
-#define EISA_ID2 iobase+0x0c82 /* EISA ID Register 2 */
-#define EISA_ID3 iobase+0x0c83 /* EISA ID Register 3 */
+#define EISA_ID iobase+0x0c80 /* EISA ID Registers */
+#define EISA_ID0 iobase+0x0c80 /* EISA ID Register 0 */
+#define EISA_ID1 iobase+0x0c81 /* EISA ID Register 1 */
+#define EISA_ID2 iobase+0x0c82 /* EISA ID Register 2 */
+#define EISA_ID3 iobase+0x0c83 /* EISA ID Register 3 */
#define EISA_CR iobase+0x0c84 /* EISA Control Register */
#define EISA_REG0 iobase+0x0c88 /* EISA Configuration Register 0 */
#define EISA_REG1 iobase+0x0c89 /* EISA Configuration Register 1 */
@@ -1008,8 +1008,8 @@ struct de4x5_ioctl {
unsigned char __user *data; /* Pointer to the data buffer */
};
-/*
-** Recognised commands for the driver
+/*
+** Recognised commands for the driver
*/
#define DE4X5_GET_HWADDR 0x01 /* Get the hardware address */
#define DE4X5_SET_HWADDR 0x02 /* Set the hardware address */
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 74e9075d9c48..ba5b112093f4 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -50,7 +50,7 @@
forget to unmap PCI mapped skbs.
Alan Cox <alan@redhat.com>
- Added new PCI identifiers provided by Clear Zhang at ALi
+ Added new PCI identifiers provided by Clear Zhang at ALi
for their 1563 ethernet device.
TODO
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index fbd9ab60b052..5ffbd5b300c0 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -96,11 +96,11 @@ static const char *block_name[] __devinitdata = {
* tulip_build_fake_mediatable - Build a fake mediatable entry.
* @tp: Ptr to the tulip private data.
*
- * Some cards like the 3x5 HSC cards (J3514A) do not have a standard
+ * Some cards like the 3x5 HSC cards (J3514A) do not have a standard
* srom and can not be handled under the fixup routine. These cards
- * still need a valid mediatable entry for correct csr12 setup and
+ * still need a valid mediatable entry for correct csr12 setup and
* mii handling.
- *
+ *
* Since this is currently a parisc-linux specific function, the
* #ifdef __hppa__ should completely optimize this function away for
* non-parisc hardware.
@@ -140,7 +140,7 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
tp->flags |= HAS_PHY_IRQ;
tp->csr12_shadow = -1;
}
-#endif
+#endif
}
void __devinit tulip_parse_eeprom(struct net_device *dev)
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index bb3558164a5b..da4f7593c50f 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -139,22 +139,22 @@ int tulip_poll(struct net_device *dev, int *budget)
}
/* Acknowledge current RX interrupt sources. */
iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5);
-
-
+
+
/* If we own the next entry, it is a new packet. Send it up. */
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
-
-
+
+
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
break;
-
+
if (tulip_debug > 5)
printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
dev->name, entry, status);
if (--rx_work_limit < 0)
goto not_done;
-
+
if ((status & 0x38008300) != 0x0300) {
if ((status & 0x38000300) != 0x0300) {
/* Ingore earlier buffers. */
@@ -180,7 +180,7 @@ int tulip_poll(struct net_device *dev, int *budget)
/* Omit the four octet CRC from the length. */
short pkt_len = ((status >> 16) & 0x7ff) - 4;
struct sk_buff *skb;
-
+
#ifndef final_version
if (pkt_len > 1518) {
printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
@@ -213,7 +213,7 @@ int tulip_poll(struct net_device *dev, int *budget)
} else { /* Pass up the skb already on the Rx ring. */
char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
pkt_len);
-
+
#ifndef final_version
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
@@ -225,17 +225,17 @@ int tulip_poll(struct net_device *dev, int *budget)
skb->head, temp);
}
#endif
-
+
pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping,
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-
+
tp->rx_buffers[entry].skb = NULL;
tp->rx_buffers[entry].mapping = 0;
}
skb->protocol = eth_type_trans(skb, dev);
-
+
netif_receive_skb(skb);
-
+
dev->last_rx = jiffies;
tp->stats.rx_packets++;
tp->stats.rx_bytes += pkt_len;
@@ -245,12 +245,12 @@ int tulip_poll(struct net_device *dev, int *budget)
entry = (++tp->cur_rx) % RX_RING_SIZE;
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
tulip_refill_rx(dev);
-
+
}
-
+
/* New ack strategy... irq does not ack Rx any longer
hopefully this helps */
-
+
/* Really bad things can happen here... If new packet arrives
* and an irq arrives (tx or just due to occasionally unset
* mask), it will be acked by irq handler, but new thread
@@ -259,28 +259,28 @@ int tulip_poll(struct net_device *dev, int *budget)
* tomorrow (night 011029). If it will not fail, we won
* finally: amount of IO did not increase at all. */
} while ((ioread32(tp->base_addr + CSR5) & RxIntr));
-
+
done:
-
+
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
-
+
/* We use this simplistic scheme for IM. It's proven by
real life installations. We can have IM enabled
- continuesly but this would cause unnecessary latency.
- Unfortunely we can't use all the NET_RX_* feedback here.
- This would turn on IM for devices that is not contributing
- to backlog congestion with unnecessary latency.
-
+ continuesly but this would cause unnecessary latency.
+ Unfortunely we can't use all the NET_RX_* feedback here.
+ This would turn on IM for devices that is not contributing
+ to backlog congestion with unnecessary latency.
+
We monitor the the device RX-ring and have:
-
+
HW Interrupt Mitigation either ON or OFF.
-
- ON: More then 1 pkt received (per intr.) OR we are dropping
+
+ ON: More then 1 pkt received (per intr.) OR we are dropping
OFF: Only 1 pkt received
-
+
Note. We only use min and max (0, 15) settings from mit_table */
-
-
+
+
if( tp->flags & HAS_INTR_MITIGATION) {
if( received > 1 ) {
if( ! tp->mit_on ) {
@@ -297,20 +297,20 @@ done:
}
#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
-
+
dev->quota -= received;
*budget -= received;
-
+
tulip_refill_rx(dev);
-
+
/* If RX ring is not full we are out of memory. */
if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
-
+
/* Remove us from polling list and enable RX intr. */
-
+
netif_rx_complete(dev);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
-
+
/* The last op happens after poll completion. Which means the following:
* 1. it can race with disabling irqs in irq handler
* 2. it can race with dise/enabling irqs in other poll threads
@@ -321,9 +321,9 @@ done:
* due to races in masking and due to too late acking of already
* processed irqs. But it must not result in losing events.
*/
-
+
return 0;
-
+
not_done:
if (!received) {
@@ -331,29 +331,29 @@ done:
}
dev->quota -= received;
*budget -= received;
-
+
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
tulip_refill_rx(dev);
-
+
if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
-
+
return 1;
-
-
+
+
oom: /* Executed with RX ints disabled */
-
-
+
+
/* Start timer, stop polling, but do not enable rx interrupts. */
mod_timer(&tp->oom_timer, jiffies+1);
-
+
/* Think: timer_pending() was an explicit signature of bug.
* Timer can be pending now but fired and completed
* before we did netif_rx_complete(). See? We would lose it. */
-
+
/* remove ourselves from the polling list */
netif_rx_complete(dev);
-
+
return 0;
}
@@ -521,9 +521,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Let's see whether the interrupt really is for us */
csr5 = ioread32(ioaddr + CSR5);
- if (tp->flags & HAS_PHY_IRQ)
+ if (tp->flags & HAS_PHY_IRQ)
handled = phy_interrupt (dev);
-
+
if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
return IRQ_RETVAL(handled);
@@ -538,17 +538,17 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Mask RX intrs and add the device to poll list. */
iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
netif_rx_schedule(dev);
-
+
if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
break;
}
-
+
/* Acknowledge the interrupt sources we handle here ASAP
the poll function does Rx and RxNoBuf acking */
-
+
iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5);
-#else
+#else
/* Acknowledge all of the current interrupt sources ASAP. */
iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5);
@@ -559,11 +559,11 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
#endif /* CONFIG_TULIP_NAPI */
-
+
if (tulip_debug > 4)
printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
dev->name, csr5, ioread32(ioaddr + CSR5));
-
+
if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
unsigned int dirty_tx;
@@ -737,17 +737,17 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
#ifdef CONFIG_TULIP_NAPI
if (rxd)
csr5 &= ~RxPollInt;
- } while ((csr5 & (TxNoBuf |
- TxDied |
- TxIntr |
+ } while ((csr5 & (TxNoBuf |
+ TxDied |
+ TxIntr |
TimerInt |
/* Abnormal intr. */
- RxDied |
- TxFIFOUnderflow |
- TxJabber |
- TPLnkFail |
+ RxDied |
+ TxFIFOUnderflow |
+ TxJabber |
+ TPLnkFail |
SytemError )) != 0);
-#else
+#else
} while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
tulip_refill_rx(dev);
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index f53396fe79c9..e9bc2a958c14 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -140,7 +140,7 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
spin_unlock_irqrestore(&tp->mii_lock, flags);
return;
}
-
+
/* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 05d2d96f7be2..d25020da6798 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -259,7 +259,7 @@ enum t21143_csr6_bits {
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 32
-#define RX_RING_SIZE 128
+#define RX_RING_SIZE 128
#define MEDIA_MASK 31
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index c67c91251d04..cabdf894e21e 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1224,7 +1224,7 @@ out:
* Chips that have the MRM/reserved bit quirk and the burst quirk. That
* is the DM910X and the on chip ULi devices
*/
-
+
static int tulip_uli_dm_quirk(struct pci_dev *pdev)
{
if (pdev->vendor == 0x1282 && pdev->device == 0x9102)
@@ -1297,7 +1297,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
*/
/* 1. Intel Saturn. Switch to 8 long words burst, 8 long word cache
- aligned. Aries might need this too. The Saturn errata are not
+ aligned. Aries might need this too. The Saturn errata are not
pretty reading but thankfully it's an old 486 chipset.
2. The dreaded SiS496 486 chipset. Same workaround as Intel
@@ -1483,14 +1483,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
sa_offset = 2; /* Grrr, damn Matrox boards. */
multiport_cnt = 4;
}
-#ifdef CONFIG_DDB5476
- if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 6)) {
- /* DDB5476 MAC address in first EEPROM locations. */
- sa_offset = 0;
- /* No media table either */
- tp->flags &= ~HAS_MEDIA_TABLE;
- }
-#endif
#ifdef CONFIG_DDB5477
if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) {
/* DDB5477 MAC address in first EEPROM locations. */
@@ -1500,7 +1492,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
}
#endif
#ifdef CONFIG_MIPS_COBALT
- if ((pdev->bus->number == 0) &&
+ if ((pdev->bus->number == 0) &&
((PCI_SLOT(pdev->devfn) == 7) ||
(PCI_SLOT(pdev->devfn) == 12))) {
/* Cobalt MAC address in first EEPROM locations. */
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 238e9c72cb3a..8b3a28f53c3d 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -9,7 +9,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
*/
#define DRV_NAME "uli526x"
@@ -185,7 +185,7 @@ struct uli526x_board_info {
/* NIC SROM data */
unsigned char srom[128];
- u8 init;
+ u8 init;
};
enum uli526x_offsets {
@@ -258,7 +258,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
struct uli526x_board_info *db; /* board information structure */
struct net_device *dev;
int i, err;
-
+
ULI526X_DBUG(0, "uli526x_init_one()", 0);
if (!printed_version++)
@@ -316,7 +316,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_nomem;
}
-
+
db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
db->first_tx_desc_dma = db->desc_pool_dma_ptr;
db->buf_pool_start = db->buf_pool_ptr;
@@ -324,14 +324,14 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
db->chip_id = ent->driver_data;
db->ioaddr = pci_resource_start(pdev, 0);
-
+
db->pdev = pdev;
db->init = 1;
-
+
dev->base_addr = db->ioaddr;
dev->irq = pdev->irq;
pci_set_drvdata(pdev, dev);
-
+
/* Register some necessary functions */
dev->open = &uli526x_open;
dev->hard_start_xmit = &uli526x_start_xmit;
@@ -341,7 +341,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
dev->ethtool_ops = &netdev_ethtool_ops;
spin_lock_init(&db->lock);
-
+
/* read 64 word srom data */
for (i = 0; i < 64; i++)
((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
@@ -374,7 +374,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
goto err_out_res;
printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
-
+
for (i = 0; i < 6; i++)
printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
printk(", irq %d.\n", dev->irq);
@@ -389,7 +389,7 @@ err_out_nomem:
if(db->desc_pool_ptr)
pci_free_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
db->desc_pool_ptr, db->desc_pool_dma_ptr);
-
+
if(db->buf_pool_ptr != NULL)
pci_free_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
db->buf_pool_ptr, db->buf_pool_dma_ptr);
@@ -433,7 +433,7 @@ static int uli526x_open(struct net_device *dev)
{
int ret;
struct uli526x_board_info *db = netdev_priv(dev);
-
+
ULI526X_DBUG(0, "uli526x_open", 0);
ret = request_irq(dev->irq, &uli526x_interrupt, SA_SHIRQ, dev->name, dev);
@@ -454,7 +454,7 @@ static int uli526x_open(struct net_device *dev)
/* CR6 operation mode decision */
db->cr6_data |= ULI526X_TXTH_256;
db->cr0_data = CR0_DEFAULT;
-
+
/* Initialize ULI526X board */
uli526x_init(dev);
@@ -604,7 +604,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore CR7 to enable interrupt */
spin_unlock_irqrestore(&db->lock, flags);
outl(db->cr7_data, dev->base_addr + DCR7);
-
+
/* free this SKB */
dev_kfree_skb(skb);
@@ -782,7 +782,7 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
struct sk_buff *skb;
int rxlen;
u32 rdes0;
-
+
rxptr = db->rx_ready_ptr;
while(db->rx_avail_cnt) {
@@ -821,7 +821,7 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
if ( !(rdes0 & 0x8000) ||
((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
skb = rxptr->rx_skb_ptr;
-
+
/* Good packet, send to upper layer */
/* Shorst packet used new SKB */
if ( (rxlen < RX_COPY_SIZE) &&
@@ -841,7 +841,7 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
dev->last_rx = jiffies;
db->stats.rx_packets++;
db->stats.rx_bytes += rxlen;
-
+
} else {
/* Reuse SKB buffer when the packet is error */
ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
@@ -911,7 +911,7 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_MII);
-
+
ecmd->advertising = (ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
@@ -924,13 +924,13 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
ecmd->phy_address = db->phy_addr;
ecmd->transceiver = XCVR_EXTERNAL;
-
+
ecmd->speed = 10;
ecmd->duplex = DUPLEX_HALF;
-
+
if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
{
- ecmd->speed = 100;
+ ecmd->speed = 100;
}
if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
{
@@ -939,11 +939,11 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
if(db->link_failed)
{
ecmd->speed = -1;
- ecmd->duplex = -1;
+ ecmd->duplex = -1;
}
-
+
if (db->media_mode & ULI526X_AUTO)
- {
+ {
ecmd->autoneg = AUTONEG_ENABLE;
}
}
@@ -964,15 +964,15 @@ static void netdev_get_drvinfo(struct net_device *dev,
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {
struct uli526x_board_info *np = netdev_priv(dev);
-
+
ULi_ethtool_gset(np, cmd);
-
+
return 0;
}
static u32 netdev_get_link(struct net_device *dev) {
struct uli526x_board_info *np = netdev_priv(dev);
-
+
if(np->link_failed)
return 0;
else
@@ -1005,11 +1005,11 @@ static void uli526x_timer(unsigned long data)
struct uli526x_board_info *db = netdev_priv(dev);
unsigned long flags;
u8 TmpSpeed=10;
-
+
//ULI526X_DBUG(0, "uli526x_timer()", 0);
spin_lock_irqsave(&db->lock, flags);
-
+
/* Dynamic reset ULI526X : system error or transmit time-out */
tmp_cr8 = inl(db->ioaddr + DCR8);
if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
@@ -1021,9 +1021,9 @@ static void uli526x_timer(unsigned long data)
/* TX polling kick monitor */
if ( db->tx_packet_cnt &&
time_after(jiffies, dev->trans_start + ULI526X_TX_KICK) ) {
- outl(0x1, dev->base_addr + DCR1); // Tx polling again
+ outl(0x1, dev->base_addr + DCR1); // Tx polling again
- // TX Timeout
+ // TX Timeout
if ( time_after(jiffies, dev->trans_start + ULI526X_TX_TIMEOUT) ) {
db->reset_TXtimeout++;
db->wait_reset = 1;
@@ -1073,7 +1073,7 @@ static void uli526x_timer(unsigned long data)
uli526x_sense_speed(db) )
db->link_failed = 1;
uli526x_process_mode(db);
-
+
if(db->link_failed==0)
{
if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
@@ -1404,7 +1404,7 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db)
phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
if ( (phy_mode & 0x24) == 0x24 ) {
-
+
phy_mode = ((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)<<7);
if(phy_mode&0x8000)
phy_mode = 0x8000;
@@ -1414,7 +1414,7 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db)
phy_mode = 0x2000;
else
phy_mode = 0x1000;
-
+
/* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
switch (phy_mode) {
case 0x1000: db->op_mode = ULI526X_10MHF; break;
@@ -1442,7 +1442,7 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db)
static void uli526x_set_phyxcer(struct uli526x_board_info *db)
{
u16 phy_reg;
-
+
/* Phyxcer capability setting */
phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
@@ -1457,7 +1457,7 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db)
case ULI526X_100MHF: phy_reg |= 0x80; break;
case ULI526X_100MFD: phy_reg |= 0x100; break;
}
-
+
}
/* Write new capability to Phyxcer Reg4 */
@@ -1556,7 +1556,7 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data
/* Write a word data to PHY controller */
for ( i = 0x8000; i > 0; i >>= 1)
phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0, chip_id);
-
+
}
@@ -1574,7 +1574,7 @@ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
return phy_readby_cr10(iobase, phy_addr, offset);
/* M5261/M5263 Chip */
ioaddr = iobase + DCR9;
-
+
/* Send 33 synchronization clock to Phy controller */
for (i = 0; i < 35; i++)
phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
@@ -1610,7 +1610,7 @@ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
{
unsigned long ioaddr,cr10_value;
-
+
ioaddr = iobase + DCR10;
cr10_value = phy_addr;
cr10_value = (cr10_value<<5) + offset;
@@ -1629,7 +1629,7 @@ static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data)
{
unsigned long ioaddr,cr10_value;
-
+
ioaddr = iobase + DCR10;
cr10_value = phy_addr;
cr10_value = (cr10_value<<5) + offset;
@@ -1659,7 +1659,7 @@ static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id)
static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
{
u16 phy_data;
-
+
outl(0x50000 , ioaddr);
udelay(1);
phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index ba05dedf29d3..8fea2aa455d4 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -38,12 +38,12 @@
Copyright (C) 2001 Manfred Spraul
* ethtool support (jgarzik)
* Replace some MII-related magic numbers with constants (jgarzik)
-
+
TODO:
* enable pci_power_off
* Wake-On-LAN
*/
-
+
#define DRV_NAME "winbond-840"
#define DRV_VERSION "1.01-d"
#define DRV_RELDATE "Nov-17-2001"
@@ -57,7 +57,7 @@ c-help-name: Winbond W89c840 PCI Ethernet support
c-help-symbol: CONFIG_WINBOND_840
c-help: This driver is for the Winbond W89c840 chip. It also works with
c-help: the TX9882 chip on the Compex RL100-ATX board.
-c-help: More specific information and updates are available from
+c-help: More specific information and updates are available from
c-help: http://www.scyld.com/network/drivers.html
*/
@@ -207,7 +207,7 @@ Test with 'ping -s 10000' on a fast computer.
*/
-
+
/*
PCI probe table.
@@ -374,7 +374,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
-
+
static int __devinit w840_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -434,7 +434,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write;
np->base_addr = ioaddr;
-
+
pci_set_drvdata(pdev, dev);
if (dev->mem_start)
@@ -510,7 +510,7 @@ err_out_netdev:
return -ENODEV;
}
-
+
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are
often serial bit streams generated by the host processor.
The example below is for the common 93c46 EEPROM, 64 16 bit words. */
@@ -660,7 +660,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
return;
}
-
+
static int netdev_open(struct net_device *dev)
{
struct netdev_private *np = netdev_priv(dev);
@@ -731,7 +731,7 @@ static int update_link(struct net_device *dev)
dev->name, np->phys[0]);
netif_carrier_on(dev);
}
-
+
if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) {
/* If the link partner doesn't support autonegotiation
* the MII detects it's abilities with the "parallel detection".
@@ -761,7 +761,7 @@ static int update_link(struct net_device *dev)
result |= 0x20000000;
if (result != np->csr6 && debug)
printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n",
- dev->name, fasteth ? 100 : 10,
+ dev->name, fasteth ? 100 : 10,
duplex ? "full" : "half", np->phys[0]);
return result;
}
@@ -850,7 +850,7 @@ static void init_rxtx_rings(struct net_device *dev)
break;
skb->dev = dev; /* Mark as being used by this device. */
np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data,
- skb->len,PCI_DMA_FROMDEVICE);
+ np->rx_buf_sz,PCI_DMA_FROMDEVICE);
np->rx_ring[i].buffer1 = np->rx_addr[i];
np->rx_ring[i].status = DescOwn;
@@ -947,7 +947,7 @@ static void init_registers(struct net_device *dev)
iowrite32(i, ioaddr + PCIBusCfg);
np->csr6 = 0;
- /* 128 byte Tx threshold;
+ /* 128 byte Tx threshold;
Transmit on; Receive on; */
update_csr6(dev, 0x00022002 | update_link(dev) | __set_rx_mode(dev));
@@ -1316,7 +1316,7 @@ static int netdev_rx(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
np->rx_addr[entry] = pci_map_single(np->pci_dev,
skb->data,
- skb->len, PCI_DMA_FROMDEVICE);
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
np->rx_ring[entry].buffer1 = np->rx_addr[entry];
}
wmb();
@@ -1584,7 +1584,7 @@ static int netdev_close(struct net_device *dev)
static void __devexit w840_remove1 (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
-
+
if (dev) {
struct netdev_private *np = netdev_priv(dev);
unregister_netdev(dev);
@@ -1605,11 +1605,11 @@ static void __devexit w840_remove1 (struct pci_dev *pdev)
* - get_stats:
* spin_lock_irq(np->lock), doesn't touch hw if not present
* - hard_start_xmit:
- * netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
+ * synchronize_irq + netif_tx_disable;
* - tx_timeout:
- * netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
+ * netif_device_detach + netif_tx_disable;
* - set_multicast_list
- * netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
+ * netif_device_detach + netif_tx_disable;
* - interrupt handler
* doesn't touch hw if not present, synchronize_irq waits for
* running instances of the interrupt handler.
@@ -1635,11 +1635,10 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state)
netif_device_detach(dev);
update_csr6(dev, 0);
iowrite32(0, ioaddr + IntrEnable);
- netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
- spin_unlock_wait(&dev->xmit_lock);
synchronize_irq(dev->irq);
+ netif_tx_disable(dev);
np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 56344103ac23..63c2175ed138 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -1,11 +1,11 @@
/*
- * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards
+ * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards
*
* This software is (C) by the respective authors, and licensed under the GPL
* License.
*
* Written by Arjan van de Ven for Red Hat, Inc.
- * Based on work by Jeff Garzik, Doug Ledford and Donald Becker
+ * Based on work by Jeff Garzik, Doug Ledford and Donald Becker
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
@@ -93,7 +93,7 @@ struct xircom_private {
unsigned long io_port;
int open;
-
+
/* transmit_used is the rotating counter that indicates which transmit
descriptor has to be used next */
int transmit_used;
@@ -153,10 +153,10 @@ static struct pci_device_id xircom_pci_table[] = {
MODULE_DEVICE_TABLE(pci, xircom_pci_table);
static struct pci_driver xircom_ops = {
- .name = "xircom_cb",
- .id_table = xircom_pci_table,
- .probe = xircom_probe,
- .remove = xircom_remove,
+ .name = "xircom_cb",
+ .id_table = xircom_pci_table,
+ .probe = xircom_probe,
+ .remove = xircom_remove,
.suspend =NULL,
.resume =NULL
};
@@ -174,7 +174,7 @@ static void print_binary(unsigned int number)
buffer[i2++]='1';
else
buffer[i2++]='0';
- if ((i&3)==0)
+ if ((i&3)==0)
buffer[i2++]=' ';
}
printk("%s\n",buffer);
@@ -196,10 +196,10 @@ static struct ethtool_ops netdev_ethtool_ops = {
/* xircom_probe is the code that gets called on device insertion.
it sets up the hardware and registers the device to the networklayer.
-
+
TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the
first two packets that get send, and pump hates that.
-
+
*/
static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -209,7 +209,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
unsigned long flags;
unsigned short tmp16;
enter("xircom_probe");
-
+
/* First do the PCI initialisation */
if (pci_enable_device(pdev))
@@ -217,24 +217,24 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
/* disable all powermanagement */
pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
-
+
pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/
- /* clear PCI status, if any */
- pci_read_config_word (pdev,PCI_STATUS, &tmp16);
+ /* clear PCI status, if any */
+ pci_read_config_word (pdev,PCI_STATUS, &tmp16);
pci_write_config_word (pdev, PCI_STATUS,tmp16);
-
+
pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
-
+
if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
return -ENODEV;
}
- /*
+ /*
Before changing the hardware, allocate the memory.
This way, we can fail gracefully if not enough memory
- is available.
+ is available.
*/
dev = alloc_etherdev(sizeof(struct xircom_private));
if (!dev) {
@@ -242,13 +242,13 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
goto device_fail;
}
private = netdev_priv(dev);
-
+
/* Allocate the send/receive buffers */
private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle);
if (private->rx_buffer == NULL) {
printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
goto rx_buf_fail;
- }
+ }
private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle);
if (private->tx_buffer == NULL) {
printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
@@ -265,11 +265,11 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
spin_lock_init(&private->lock);
dev->irq = pdev->irq;
dev->base_addr = private->io_port;
-
+
initialize_card(private);
read_mac_address(private);
setup_descriptors(private);
-
+
dev->open = &xircom_open;
dev->hard_start_xmit = &xircom_start_xmit;
dev->stop = &xircom_close;
@@ -285,19 +285,19 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
printk(KERN_ERR "xircom_probe: netdevice registration failed.\n");
goto reg_fail;
}
-
+
printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
/* start the transmitter to get a heartbeat */
/* TODO: send 2 dummy packets here */
transceiver_voodoo(private);
-
+
spin_lock_irqsave(&private->lock,flags);
activate_transmitter(private);
activate_receiver(private);
spin_unlock_irqrestore(&private->lock,flags);
-
+
trigger_receive(private);
-
+
leave("xircom_probe");
return 0;
@@ -332,7 +332,7 @@ static void __devexit xircom_remove(struct pci_dev *pdev)
free_netdev(dev);
pci_set_drvdata(pdev, NULL);
leave("xircom_remove");
-}
+}
static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
@@ -346,11 +346,11 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs
spin_lock(&card->lock);
status = inl(card->io_port+CSR5);
-#ifdef DEBUG
+#ifdef DEBUG
print_binary(status);
printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]);
printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);
-#endif
+#endif
/* Handle shared irq and hotplug */
if (status == 0 || status == 0xffffffff) {
spin_unlock(&card->lock);
@@ -366,21 +366,21 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs
netif_carrier_on(dev);
else
netif_carrier_off(dev);
-
+
}
- /* Clear all remaining interrupts */
+ /* Clear all remaining interrupts */
status |= 0xffffffff; /* FIXME: make this clear only the
real existing bits */
outl(status,card->io_port+CSR5);
-
- for (i=0;i<NUMDESCRIPTORS;i++)
+
+ for (i=0;i<NUMDESCRIPTORS;i++)
investigate_write_descriptor(dev,card,i,bufferoffsets[i]);
- for (i=0;i<NUMDESCRIPTORS;i++)
+ for (i=0;i<NUMDESCRIPTORS;i++)
investigate_read_descriptor(dev,card,i,bufferoffsets[i]);
-
+
spin_unlock(&card->lock);
leave("xircom_interrupt");
return IRQ_HANDLED;
@@ -393,38 +393,38 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
int nextdescriptor;
int desc;
enter("xircom_start_xmit");
-
+
card = netdev_priv(dev);
spin_lock_irqsave(&card->lock,flags);
-
+
/* First see if we can free some descriptors */
- for (desc=0;desc<NUMDESCRIPTORS;desc++)
+ for (desc=0;desc<NUMDESCRIPTORS;desc++)
investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]);
-
-
+
+
nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS);
desc = card->transmit_used;
-
+
/* only send the packet if the descriptor is free */
if (card->tx_buffer[4*desc]==0) {
/* Copy the packet data; zero the memory first as the card
sometimes sends more than you ask it to. */
-
+
memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536);
memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len);
-
-
+
+
/* FIXME: The specification tells us that the length we send HAS to be a multiple of
4 bytes. */
-
+
card->tx_buffer[4*desc+1] = skb->len;
if (desc == NUMDESCRIPTORS-1)
card->tx_buffer[4*desc+1] |= (1<<25); /* bit 25: last descriptor of the ring */
card->tx_buffer[4*desc+1] |= 0xF0000000;
- /* 0xF0... means want interrupts*/
+ /* 0xF0... means want interrupts*/
card->tx_skb[desc] = skb;
-
+
wmb();
/* This gives the descriptor to the card */
card->tx_buffer[4*desc] = 0x80000000;
@@ -433,18 +433,18 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
card->transmit_used = nextdescriptor;
- leave("xircom-start_xmit - sent");
+ leave("xircom-start_xmit - sent");
spin_unlock_irqrestore(&card->lock,flags);
return 0;
}
-
+
/* Uh oh... no free descriptor... drop the packet */
netif_stop_queue(dev);
spin_unlock_irqrestore(&card->lock,flags);
trigger_transmit(card);
-
+
return -EIO;
}
@@ -462,7 +462,7 @@ static int xircom_open(struct net_device *dev)
leave("xircom_open - No IRQ");
return retval;
}
-
+
xircom_up(xp);
xp->open = 1;
leave("xircom_open");
@@ -473,31 +473,31 @@ static int xircom_close(struct net_device *dev)
{
struct xircom_private *card;
unsigned long flags;
-
+
enter("xircom_close");
card = netdev_priv(dev);
netif_stop_queue(dev); /* we don't want new packets */
-
+
spin_lock_irqsave(&card->lock,flags);
-
+
disable_all_interrupts(card);
-#if 0
+#if 0
/* We can enable this again once we send dummy packets on ifconfig ethX up */
deactivate_receiver(card);
deactivate_transmitter(card);
-#endif
+#endif
remove_descriptors(card);
-
+
spin_unlock_irqrestore(&card->lock,flags);
-
+
card->open = 0;
free_irq(dev->irq,dev);
-
+
leave("xircom_close");
-
+
return 0;
-
+
}
@@ -506,8 +506,8 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev)
{
struct xircom_private *card = netdev_priv(dev);
return &card->stats;
-}
-
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void xircom_poll_controller(struct net_device *dev)
@@ -540,7 +540,7 @@ static void initialize_card(struct xircom_private *card)
outl(val, card->io_port + CSR0);
- val = 0; /* Value 0x00 is a safe and conservative value
+ val = 0; /* Value 0x00 is a safe and conservative value
for the PCI configuration settings */
outl(val, card->io_port + CSR0);
@@ -617,23 +617,23 @@ static void setup_descriptors(struct xircom_private *card)
/* Rx Descr2: address of the buffer
we store the buffer at the 2nd half of the page */
-
+
address = (unsigned long) card->rx_dma_handle;
card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
/* Rx Desc3: address of 2nd buffer -> 0 */
card->rx_buffer[i*4 + 3] = 0;
}
-
+
wmb();
/* Write the receive descriptor ring address to the card */
address = (unsigned long) card->rx_dma_handle;
- val = cpu_to_le32(address);
+ val = cpu_to_le32(address);
outl(val, card->io_port + CSR3); /* Receive descr list address */
/* transmit descriptors */
memset(card->tx_buffer, 0, 128); /* clear the descriptors */
-
+
for (i=0;i<NUMDESCRIPTORS;i++ ) {
/* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
card->tx_buffer[i*4 + 0] = 0x00000000;
@@ -641,7 +641,7 @@ static void setup_descriptors(struct xircom_private *card)
card->tx_buffer[i*4 + 1] = 1536;
if (i==NUMDESCRIPTORS-1)
card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
-
+
/* Tx Descr2: address of the buffer
we store the buffer at the 2nd half of the page */
address = (unsigned long) card->tx_dma_handle;
@@ -748,7 +748,7 @@ static int receive_active(struct xircom_private *card)
activate_receiver enables the receiver on the card.
Before being allowed to active the receiver, the receiver
must be completely de-activated. To achieve this,
-this code actually disables the receiver first; then it waits for the
+this code actually disables the receiver first; then it waits for the
receiver to become inactive, then it activates the receiver and then
it waits for the receiver to be active.
@@ -762,13 +762,13 @@ static void activate_receiver(struct xircom_private *card)
val = inl(card->io_port + CSR6); /* Operation mode */
-
+
/* If the "active" bit is set and the receiver is already
active, no need to do the expensive thing */
if ((val&2) && (receive_active(card)))
return;
-
-
+
+
val = val & ~2; /* disable the receiver */
outl(val, card->io_port + CSR6);
@@ -805,7 +805,7 @@ static void activate_receiver(struct xircom_private *card)
/*
deactivate_receiver disables the receiver on the card.
-To achieve this this code disables the receiver first;
+To achieve this this code disables the receiver first;
then it waits for the receiver to become inactive.
must be called with the lock held and interrupts disabled.
@@ -840,7 +840,7 @@ static void deactivate_receiver(struct xircom_private *card)
activate_transmitter enables the transmitter on the card.
Before being allowed to active the transmitter, the transmitter
must be completely de-activated. To achieve this,
-this code actually disables the transmitter first; then it waits for the
+this code actually disables the transmitter first; then it waits for the
transmitter to become inactive, then it activates the transmitter and then
it waits for the transmitter to be active again.
@@ -856,7 +856,7 @@ static void activate_transmitter(struct xircom_private *card)
val = inl(card->io_port + CSR6); /* Operation mode */
/* If the "active" bit is set and the receiver is already
- active, no need to do the expensive thing */
+ active, no need to do the expensive thing */
if ((val&(1<<13)) && (transmit_active(card)))
return;
@@ -896,7 +896,7 @@ static void activate_transmitter(struct xircom_private *card)
/*
deactivate_transmitter disables the transmitter on the card.
-To achieve this this code disables the transmitter first;
+To achieve this this code disables the transmitter first;
then it waits for the transmitter to become inactive.
must be called with the lock held and interrupts disabled.
@@ -990,7 +990,7 @@ static void disable_all_interrupts(struct xircom_private *card)
{
unsigned int val;
enter("enable_all_interrupts");
-
+
val = 0; /* disable all interrupts */
outl(val, card->io_port + CSR7);
@@ -1031,8 +1031,8 @@ static int enable_promisc(struct xircom_private *card)
unsigned int val;
enter("enable_promisc");
- val = inl(card->io_port + CSR6);
- val = val | (1 << 6);
+ val = inl(card->io_port + CSR6);
+ val = val | (1 << 6);
outl(val, card->io_port + CSR6);
leave("enable_promisc");
@@ -1042,7 +1042,7 @@ static int enable_promisc(struct xircom_private *card)
-/*
+/*
link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
Must be called in locked state with interrupts disabled
@@ -1051,15 +1051,15 @@ static int link_status(struct xircom_private *card)
{
unsigned int val;
enter("link_status");
-
+
val = inb(card->io_port + CSR12);
-
+
if (!(val&(1<<2))) /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */
return 10;
if (!(val&(1<<1))) /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */
return 100;
-
- /* If we get here -> no link at all */
+
+ /* If we get here -> no link at all */
leave("link_status");
return 0;
@@ -1071,7 +1071,7 @@ static int link_status(struct xircom_private *card)
/*
read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure.
-
+
This function will take the spinlock itself and can, as a result, not be called with the lock helt.
*/
static void read_mac_address(struct xircom_private *card)
@@ -1081,7 +1081,7 @@ static void read_mac_address(struct xircom_private *card)
int i;
enter("read_mac_address");
-
+
spin_lock_irqsave(&card->lock, flags);
outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */
@@ -1095,7 +1095,7 @@ static void read_mac_address(struct xircom_private *card)
outl(i + 3, card->io_port + CSR10);
data_count = inl(card->io_port + CSR9) & 0xff;
if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) {
- /*
+ /*
* This is it. We have the data we want.
*/
for (j = 0; j < 6; j++) {
@@ -1136,12 +1136,12 @@ static void transceiver_voodoo(struct xircom_private *card)
spin_lock_irqsave(&card->lock, flags);
outl(0x0008, card->io_port + CSR15);
- udelay(25);
+ udelay(25);
outl(0xa8050000, card->io_port + CSR15);
udelay(25);
outl(0xa00f0000, card->io_port + CSR15);
udelay(25);
-
+
spin_unlock_irqrestore(&card->lock, flags);
netif_start_queue(card->dev);
@@ -1163,15 +1163,15 @@ static void xircom_up(struct xircom_private *card)
spin_lock_irqsave(&card->lock, flags);
-
+
enable_link_interrupt(card);
enable_transmit_interrupt(card);
enable_receive_interrupt(card);
enable_common_interrupts(card);
enable_promisc(card);
-
+
/* The card can have received packets already, read them away now */
- for (i=0;i<NUMDESCRIPTORS;i++)
+ for (i=0;i<NUMDESCRIPTORS;i++)
investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]);
@@ -1185,15 +1185,15 @@ static void xircom_up(struct xircom_private *card)
/* Bufferoffset is in BYTES */
static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
{
- int status;
-
+ int status;
+
enter("investigate_read_descriptor");
status = card->rx_buffer[4*descnr];
-
+
if ((status > 0)) { /* packet received */
-
+
/* TODO: discard error packets */
-
+
short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */
struct sk_buff *skb;
@@ -1216,7 +1216,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
dev->last_rx = jiffies;
card->stats.rx_packets++;
card->stats.rx_bytes += pkt_len;
-
+
out:
/* give the buffer back to the card */
card->rx_buffer[4*descnr] = 0x80000000;
@@ -1234,9 +1234,9 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
int status;
enter("investigate_write_descriptor");
-
+
status = card->tx_buffer[4*descnr];
-#if 0
+#if 0
if (status & 0x8000) { /* Major error */
printk(KERN_ERR "Major transmit error status %x \n", status);
card->tx_buffer[4*descnr] = 0;
@@ -1258,7 +1258,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
}
leave("investigate_write_descriptor");
-
+
}
@@ -1271,8 +1271,8 @@ static int __init xircom_init(void)
static void __exit xircom_exit(void)
{
pci_unregister_driver(&xircom_ops);
-}
+}
-module_init(xircom_init)
+module_init(xircom_init)
module_exit(xircom_exit)
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 6a23964c1317..fdc21037f6dc 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -129,6 +129,7 @@
- Massive clean-up
- Rewrite PHY, media handling (remove options, full_duplex, backoff)
- Fix Tx engine race for good
+ - Craig Brind: Zero padded aligned buffers for short packets.
*/
@@ -490,8 +491,6 @@ struct rhine_private {
u8 tx_thresh, rx_thresh;
struct mii_if_info mii_if;
- struct work_struct tx_timeout_task;
- struct work_struct check_media_task;
void __iomem *base;
};
@@ -499,8 +498,6 @@ static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int rhine_open(struct net_device *dev);
static void rhine_tx_timeout(struct net_device *dev);
-static void rhine_tx_timeout_task(struct net_device *dev);
-static void rhine_check_media_task(struct net_device *dev);
static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static void rhine_tx(struct net_device *dev);
@@ -855,12 +852,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
- INIT_WORK(&rp->tx_timeout_task,
- (void (*)(void *))rhine_tx_timeout_task, dev);
-
- INIT_WORK(&rp->check_media_task,
- (void (*)(void *))rhine_check_media_task, dev);
-
/* dev->name not defined before register_netdev()! */
rc = register_netdev(dev);
if (rc)
@@ -1107,11 +1098,6 @@ static void rhine_set_carrier(struct mii_if_info *mii)
netif_carrier_ok(mii->dev));
}
-static void rhine_check_media_task(struct net_device *dev)
-{
- rhine_check_media(dev, 0);
-}
-
static void init_registers(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -1165,8 +1151,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
if (quirks & rqRhineI) {
iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR
- /* Do not call from ISR! */
- msleep(1);
+ /* Can be called from ISR. Evil. */
+ mdelay(1);
/* 0x80 must be set immediately before turning it off */
iowrite8(0x80, ioaddr + MIICmd);
@@ -1256,16 +1242,6 @@ static int rhine_open(struct net_device *dev)
static void rhine_tx_timeout(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
-
- /*
- * Move bulk of work outside of interrupt context
- */
- schedule_work(&rp->tx_timeout_task);
-}
-
-static void rhine_tx_timeout_task(struct net_device *dev)
-{
- struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
@@ -1326,7 +1302,12 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
rp->stats.tx_dropped++;
return 0;
}
+
+ /* Padding is not copied and so must be redone. */
skb_copy_and_csum_dev(skb, rp->tx_buf[entry]);
+ if (skb->len < ETH_ZLEN)
+ memset(rp->tx_buf[entry] + skb->len, 0,
+ ETH_ZLEN - skb->len);
rp->tx_skbuff_dma[entry] = 0;
rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_bufs_dma +
(rp->tx_buf[entry] -
@@ -1671,7 +1652,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
spin_lock(&rp->lock);
if (intr_status & IntrLinkChange)
- schedule_work(&rp->check_media_task);
+ rhine_check_media(dev, 0);
if (intr_status & IntrStatsMax) {
rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
@@ -1921,9 +1902,6 @@ static int rhine_close(struct net_device *dev)
spin_unlock_irq(&rp->lock);
free_irq(rp->pdev->irq, dev);
-
- flush_scheduled_work();
-
free_rbufs(dev);
free_tbufs(dev);
free_ring(dev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ed1f837c8fda..2eb6b5f9ba0d 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
int pktlen = skb->len;
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+ if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
+ kfree_skb(skb);
+ return 0;
+ }
+#endif
+
spin_lock_irqsave(&vptr->lock, flags);
index = vptr->td_curr[qnum];
@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if (pktlen < ETH_ZLEN) {
/* Cannot occur until ZC support */
- if(skb_linearize(skb, GFP_ATOMIC))
- return 0;
pktlen = ETH_ZLEN;
memcpy(tdinfo->buf, skb->data, skb->len);
memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
@@ -1933,7 +1938,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
int nfrags = skb_shinfo(skb)->nr_frags;
tdinfo->skb = skb;
if (nfrags > 6) {
- skb_linearize(skb, GFP_ATOMIC);
memcpy(tdinfo->buf, skb->data, skb->len);
tdinfo->skb_dma[0] = tdinfo->buf_dma;
td_ptr->tdesc0.pktsize =
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index d9a774b91ddc..f1b2640ebdc6 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -307,7 +307,7 @@ enum velocity_owner {
#define TX_QUEUE_NO 4
#define MAX_HW_MIB_COUNTER 32
-#define VELOCITY_MIN_MTU (1514-14)
+#define VELOCITY_MIN_MTU (64)
#define VELOCITY_MAX_MTU (9000)
/*
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index eba8e5cfacc2..f485a97844cc 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -50,10 +50,6 @@ static const char* devname = "PCI200SYN";
static int pci_clock_freq = 33000000;
#define CLOCK_BASE pci_clock_freq
-#define PCI_VENDOR_ID_GORAMO 0x10B5 /* uses PLX:9050 ID - this card */
-#define PCI_DEVICE_ID_PCI200SYN 0x9050 /* doesn't have its own ID */
-
-
/*
* PLX PCI9052 local configuration and shared runtime registers.
* This structure can be used to access 9052 registers (memory mapped).
@@ -262,7 +258,7 @@ static void pci200_pci_remove_one(struct pci_dev *pdev)
int i;
card_t *card = pci_get_drvdata(pdev);
- for(i = 0; i < 2; i++)
+ for (i = 0; i < 2; i++)
if (card->ports[i].card) {
struct net_device *dev = port_to_dev(&card->ports[i]);
unregister_hdlc_device(dev);
@@ -385,6 +381,15 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
" %u RX packets rings\n", ramsize / 1024, ramphys,
pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers);
+ if (pdev->subsystem_device == PCI_DEVICE_ID_PLX_9050) {
+ printk(KERN_ERR "Detected PCI200SYN card with old "
+ "configuration data.\n");
+ printk(KERN_ERR "See <http://www.kernel.org/pub/"
+ "linux/utils/net/hdlc/pci200syn/> for update.\n");
+ printk(KERN_ERR "The card will stop working with"
+ " future versions of Linux if not updated.\n");
+ }
+
if (card->tx_ring_buffers < 1) {
printk(KERN_ERR "pci200syn: RAM test failed\n");
pci200_pci_remove_one(pdev);
@@ -396,7 +401,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
writew(readw(p) | 0x0040, p);
/* Allocate IRQ */
- if(request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) {
+ if (request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) {
printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n",
pdev->irq);
pci200_pci_remove_one(pdev);
@@ -406,7 +411,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
sca_init(card, 0);
- for(i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
port_t *port = &card->ports[i];
struct net_device *dev = port_to_dev(port);
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -425,7 +430,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
hdlc->xmit = sca_xmit;
port->settings.clock_type = CLOCK_EXT;
port->card = card;
- if(register_hdlc_device(dev)) {
+ if (register_hdlc_device(dev)) {
printk(KERN_ERR "pci200syn: unable to register hdlc "
"device\n");
port->card = NULL;
@@ -445,8 +450,10 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
static struct pci_device_id pci200_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_GORAMO, PCI_DEVICE_ID_PCI200SYN, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX,
+ PCI_DEVICE_ID_PLX_9050, 0, 0, 0 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX,
+ PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 },
{ 0, }
};
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index e0874cbfefea..30ec235e6935 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -235,7 +235,35 @@ config IPW2200_MONITOR
promiscuous mode via the Wireless Tool's Monitor mode. While in this
mode, no packets can be sent.
-config IPW_QOS
+config IPW2200_RADIOTAP
+ bool "Enable radiotap format 802.11 raw packet support"
+ depends on IPW2200_MONITOR
+
+config IPW2200_PROMISCUOUS
+ bool "Enable creation of a RF radiotap promiscuous interface"
+ depends on IPW2200_MONITOR
+ select IPW2200_RADIOTAP
+ ---help---
+ Enables the creation of a second interface prefixed 'rtap'.
+ This second interface will provide every received in radiotap
+ format.
+
+ This is useful for performing wireless network analysis while
+ maintaining an active association.
+
+ Example usage:
+
+ % modprobe ipw2200 rtap_iface=1
+ % ifconfig rtap0 up
+ % tethereal -i rtap0
+
+ If you do not specify 'rtap_iface=1' as a module parameter then
+ the rtap interface will not be created and you will need to turn
+ it on via sysfs:
+
+ % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
+
+config IPW2200_QOS
bool "Enable QoS support"
depends on IPW2200 && EXPERIMENTAL
@@ -503,6 +531,23 @@ config PRISM54
say M here and read <file:Documentation/modules.txt>. The module
will be called prism54.ko.
+config USB_ZD1201
+ tristate "USB ZD1201 based Wireless device support"
+ depends on USB && NET_RADIO
+ select FW_LOADER
+ ---help---
+ Say Y if you want to use wireless LAN adapters based on the ZyDAS
+ ZD1201 chip.
+
+ This driver makes the adapter appear as a normal Ethernet interface,
+ typically on wlan0.
+
+ The zd1201 device requires external firmware to be loaded.
+ This can be found at http://linux-lc100020.sourceforge.net/
+
+ To compile this driver as a module, choose M here: the
+ module will be called zd1201.
+
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c86779879361..512603de309a 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -40,3 +40,5 @@ obj-$(CONFIG_BCM43XX) += bcm43xx/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
+
+obj-$(CONFIG_USB_ZD1201) += zd1201.o
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 00764ddd74d8..4069b79d8259 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -47,6 +47,7 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
+#include <net/ieee80211.h>
#include "airo.h"
@@ -467,6 +468,8 @@ static int do8bitIO = 0;
#define RID_ECHOTEST_RESULTS 0xFF71
#define RID_BSSLISTFIRST 0xFF72
#define RID_BSSLISTNEXT 0xFF73
+#define RID_WPA_BSSLISTFIRST 0xFF74
+#define RID_WPA_BSSLISTNEXT 0xFF75
typedef struct {
u16 cmd;
@@ -739,6 +742,14 @@ typedef struct {
u16 extSoftCap;
} CapabilityRid;
+
+/* Only present on firmware >= 5.30.17 */
+typedef struct {
+ u16 unknown[4];
+ u8 fixed[12]; /* WLAN management frame */
+ u8 iep[624];
+} BSSListRidExtra;
+
typedef struct {
u16 len;
u16 index; /* First is 0 and 0xffff means end of list */
@@ -767,6 +778,9 @@ typedef struct {
} fh;
u16 dsChannel;
u16 atimWindow;
+
+ /* Only present on firmware >= 5.30.17 */
+ BSSListRidExtra extra;
} BSSListRid;
typedef struct {
@@ -1140,8 +1154,6 @@ struct airo_info {
char defindex; // Used with auto wep
struct proc_dir_entry *proc_entry;
spinlock_t aux_lock;
- unsigned long flags;
-#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
#define FLAG_RADIO_MASK 0x03
@@ -1151,6 +1163,7 @@ struct airo_info {
#define FLAG_UPDATE_MULTI 5
#define FLAG_UPDATE_UNI 6
#define FLAG_802_11 7
+#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
#define FLAG_PENDING_XMIT 9
#define FLAG_PENDING_XMIT11 10
#define FLAG_MPI 11
@@ -1158,17 +1171,19 @@ struct airo_info {
#define FLAG_COMMIT 13
#define FLAG_RESET 14
#define FLAG_FLASHING 15
-#define JOB_MASK 0x2ff0000
-#define JOB_DIE 16
-#define JOB_XMIT 17
-#define JOB_XMIT11 18
-#define JOB_STATS 19
-#define JOB_PROMISC 20
-#define JOB_MIC 21
-#define JOB_EVENT 22
-#define JOB_AUTOWEP 23
-#define JOB_WSTATS 24
-#define JOB_SCAN_RESULTS 25
+#define FLAG_WPA_CAPABLE 16
+ unsigned long flags;
+#define JOB_DIE 0
+#define JOB_XMIT 1
+#define JOB_XMIT11 2
+#define JOB_STATS 3
+#define JOB_PROMISC 4
+#define JOB_MIC 5
+#define JOB_EVENT 6
+#define JOB_AUTOWEP 7
+#define JOB_WSTATS 8
+#define JOB_SCAN_RESULTS 9
+ unsigned long jobs;
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
unsigned short *flash;
@@ -1208,6 +1223,11 @@ struct airo_info {
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
char proc_name[IFNAMSIZ];
+ /* WPA-related stuff */
+ unsigned int bssListFirst;
+ unsigned int bssListNext;
+ unsigned int bssListRidLen;
+
struct list_head network_list;
struct list_head network_free_list;
BSSListElement *networks;
@@ -1264,7 +1284,7 @@ static void micinit(struct airo_info *ai)
{
MICRid mic_rid;
- clear_bit(JOB_MIC, &ai->flags);
+ clear_bit(JOB_MIC, &ai->jobs);
PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
up(&ai->sem);
@@ -1705,24 +1725,24 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
static int readBSSListRid(struct airo_info *ai, int first,
BSSListRid *list) {
int rc;
- Cmd cmd;
- Resp rsp;
+ Cmd cmd;
+ Resp rsp;
if (first == 1) {
- if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd=CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
- issuecommand(ai, &cmd, &rsp);
- up(&ai->sem);
- /* Let the command take effect */
- ai->task = current;
- ssleep(3);
- ai->task = NULL;
- }
- rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
- list, sizeof(*list), 1);
+ if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd=CMD_LISTBSS;
+ if (down_interruptible(&ai->sem))
+ return -ERESTARTSYS;
+ issuecommand(ai, &cmd, &rsp);
+ up(&ai->sem);
+ /* Let the command take effect */
+ ai->task = current;
+ ssleep(3);
+ ai->task = NULL;
+ }
+ rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
+ list, ai->bssListRidLen, 1);
list->len = le16_to_cpu(list->len);
list->index = le16_to_cpu(list->index);
@@ -2112,7 +2132,7 @@ static void airo_end_xmit(struct net_device *dev) {
int fid = priv->xmit.fid;
u32 *fids = priv->fids;
- clear_bit(JOB_XMIT, &priv->flags);
+ clear_bit(JOB_XMIT, &priv->jobs);
clear_bit(FLAG_PENDING_XMIT, &priv->flags);
status = transmit_802_3_packet (priv, fids[fid], skb->data);
up(&priv->sem);
@@ -2162,7 +2182,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (down_trylock(&priv->sem) != 0) {
set_bit(FLAG_PENDING_XMIT, &priv->flags);
netif_stop_queue(dev);
- set_bit(JOB_XMIT, &priv->flags);
+ set_bit(JOB_XMIT, &priv->jobs);
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit(dev);
@@ -2177,7 +2197,7 @@ static void airo_end_xmit11(struct net_device *dev) {
int fid = priv->xmit11.fid;
u32 *fids = priv->fids;
- clear_bit(JOB_XMIT11, &priv->flags);
+ clear_bit(JOB_XMIT11, &priv->jobs);
clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
status = transmit_802_11_packet (priv, fids[fid], skb->data);
up(&priv->sem);
@@ -2233,7 +2253,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if (down_trylock(&priv->sem) != 0) {
set_bit(FLAG_PENDING_XMIT11, &priv->flags);
netif_stop_queue(dev);
- set_bit(JOB_XMIT11, &priv->flags);
+ set_bit(JOB_XMIT11, &priv->jobs);
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit11(dev);
@@ -2244,7 +2264,7 @@ static void airo_read_stats(struct airo_info *ai) {
StatsRid stats_rid;
u32 *vals = stats_rid.vals;
- clear_bit(JOB_STATS, &ai->flags);
+ clear_bit(JOB_STATS, &ai->jobs);
if (ai->power.event) {
up(&ai->sem);
return;
@@ -2272,10 +2292,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
{
struct airo_info *local = dev->priv;
- if (!test_bit(JOB_STATS, &local->flags)) {
+ if (!test_bit(JOB_STATS, &local->jobs)) {
/* Get stats out of the card if available */
if (down_trylock(&local->sem) != 0) {
- set_bit(JOB_STATS, &local->flags);
+ set_bit(JOB_STATS, &local->jobs);
wake_up_interruptible(&local->thr_wait);
} else
airo_read_stats(local);
@@ -2290,7 +2310,7 @@ static void airo_set_promisc(struct airo_info *ai) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_SETMODE;
- clear_bit(JOB_PROMISC, &ai->flags);
+ clear_bit(JOB_PROMISC, &ai->jobs);
cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
issuecommand(ai, &cmd, &rsp);
up(&ai->sem);
@@ -2302,7 +2322,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
change_bit(FLAG_PROMISC, &ai->flags);
if (down_trylock(&ai->sem) != 0) {
- set_bit(JOB_PROMISC, &ai->flags);
+ set_bit(JOB_PROMISC, &ai->jobs);
wake_up_interruptible(&ai->thr_wait);
} else
airo_set_promisc(ai);
@@ -2380,7 +2400,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
}
clear_bit(FLAG_REGISTERED, &ai->flags);
}
- set_bit(JOB_DIE, &ai->flags);
+ set_bit(JOB_DIE, &ai->jobs);
kill_proc(ai->thr_pid, SIGTERM, 1);
wait_for_completion(&ai->thr_exited);
@@ -2701,14 +2721,14 @@ static int reset_card( struct net_device *dev , int lock) {
return 0;
}
-#define MAX_NETWORK_COUNT 64
+#define AIRO_MAX_NETWORK_COUNT 64
static int airo_networks_allocate(struct airo_info *ai)
{
if (ai->networks)
return 0;
ai->networks =
- kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement),
+ kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL);
if (!ai->networks) {
airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
@@ -2732,11 +2752,33 @@ static void airo_networks_initialize(struct airo_info *ai)
INIT_LIST_HEAD(&ai->network_free_list);
INIT_LIST_HEAD(&ai->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
+ for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
list_add_tail(&ai->networks[i].list,
&ai->network_free_list);
}
+static int airo_test_wpa_capable(struct airo_info *ai)
+{
+ int status;
+ CapabilityRid cap_rid;
+ const char *name = ai->dev->name;
+
+ status = readCapabilityRid(ai, &cap_rid, 1);
+ if (status != SUCCESS) return 0;
+
+ /* Only firmware versions 5.30.17 or better can do WPA */
+ if ((cap_rid.softVer > 0x530)
+ || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
+ airo_print_info(name, "WPA is supported.");
+ return 1;
+ }
+
+ /* No WPA support */
+ airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17"
+ " and greater support WPA. Detected %s)", cap_rid.prodVer);
+ return 0;
+}
+
static struct net_device *_init_airo_card( unsigned short irq, int port,
int is_pcmcia, struct pci_dev *pci,
struct device *dmdev )
@@ -2759,6 +2801,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai = dev->priv;
ai->wifidev = NULL;
ai->flags = 0;
+ ai->jobs = 0;
ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
airo_print_dbg(dev->name, "Found an MPI350 card");
@@ -2838,6 +2881,18 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
set_bit(FLAG_FLASHING, &ai->flags);
}
+ /* Test for WPA support */
+ if (airo_test_wpa_capable(ai)) {
+ set_bit(FLAG_WPA_CAPABLE, &ai->flags);
+ ai->bssListFirst = RID_WPA_BSSLISTFIRST;
+ ai->bssListNext = RID_WPA_BSSLISTNEXT;
+ ai->bssListRidLen = sizeof(BSSListRid);
+ } else {
+ ai->bssListFirst = RID_BSSLISTFIRST;
+ ai->bssListNext = RID_BSSLISTNEXT;
+ ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
+ }
+
rc = register_netdev(dev);
if (rc) {
airo_print_err(dev->name, "Couldn't register_netdev");
@@ -2875,7 +2930,7 @@ err_out_irq:
err_out_unlink:
del_airo_dev(dev);
err_out_thr:
- set_bit(JOB_DIE, &ai->flags);
+ set_bit(JOB_DIE, &ai->jobs);
kill_proc(ai->thr_pid, SIGTERM, 1);
wait_for_completion(&ai->thr_exited);
err_out_free:
@@ -2933,7 +2988,7 @@ static void airo_send_event(struct net_device *dev) {
union iwreq_data wrqu;
StatusRid status_rid;
- clear_bit(JOB_EVENT, &ai->flags);
+ clear_bit(JOB_EVENT, &ai->jobs);
PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
up(&ai->sem);
wrqu.data.length = 0;
@@ -2947,7 +3002,7 @@ static void airo_send_event(struct net_device *dev) {
static void airo_process_scan_results (struct airo_info *ai) {
union iwreq_data wrqu;
- BSSListRid BSSList;
+ BSSListRid bss;
int rc;
BSSListElement * loop_net;
BSSListElement * tmp_net;
@@ -2960,15 +3015,15 @@ static void airo_process_scan_results (struct airo_info *ai) {
}
/* Try to read the first entry of the scan result */
- rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0);
- if((rc) || (BSSList.index == 0xffff)) {
+ rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
+ if((rc) || (bss.index == 0xffff)) {
/* No scan results */
goto out;
}
/* Read and parse all entries */
tmp_net = NULL;
- while((!rc) && (BSSList.index != 0xffff)) {
+ while((!rc) && (bss.index != 0xffff)) {
/* Grab a network off the free list */
if (!list_empty(&ai->network_free_list)) {
tmp_net = list_entry(ai->network_free_list.next,
@@ -2977,19 +3032,19 @@ static void airo_process_scan_results (struct airo_info *ai) {
}
if (tmp_net != NULL) {
- memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss));
+ memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
list_add_tail(&tmp_net->list, &ai->network_list);
tmp_net = NULL;
}
/* Read next entry */
- rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
- &BSSList, sizeof(BSSList), 0);
+ rc = PC4500_readrid(ai, ai->bssListNext,
+ &bss, ai->bssListRidLen, 0);
}
out:
ai->scan_timeout = 0;
- clear_bit(JOB_SCAN_RESULTS, &ai->flags);
+ clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
up(&ai->sem);
/* Send an empty event to user space.
@@ -3019,10 +3074,10 @@ static int airo_thread(void *data) {
/* make swsusp happy with our thread */
try_to_freeze();
- if (test_bit(JOB_DIE, &ai->flags))
+ if (test_bit(JOB_DIE, &ai->jobs))
break;
- if (ai->flags & JOB_MASK) {
+ if (ai->jobs) {
locked = down_interruptible(&ai->sem);
} else {
wait_queue_t wait;
@@ -3031,16 +3086,16 @@ static int airo_thread(void *data) {
add_wait_queue(&ai->thr_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (ai->flags & JOB_MASK)
+ if (ai->jobs)
break;
if (ai->expires || ai->scan_timeout) {
if (ai->scan_timeout &&
time_after_eq(jiffies,ai->scan_timeout)){
- set_bit(JOB_SCAN_RESULTS,&ai->flags);
+ set_bit(JOB_SCAN_RESULTS, &ai->jobs);
break;
} else if (ai->expires &&
time_after_eq(jiffies,ai->expires)){
- set_bit(JOB_AUTOWEP,&ai->flags);
+ set_bit(JOB_AUTOWEP, &ai->jobs);
break;
}
if (!signal_pending(current)) {
@@ -3069,7 +3124,7 @@ static int airo_thread(void *data) {
if (locked)
continue;
- if (test_bit(JOB_DIE, &ai->flags)) {
+ if (test_bit(JOB_DIE, &ai->jobs)) {
up(&ai->sem);
break;
}
@@ -3079,23 +3134,23 @@ static int airo_thread(void *data) {
continue;
}
- if (test_bit(JOB_XMIT, &ai->flags))
+ if (test_bit(JOB_XMIT, &ai->jobs))
airo_end_xmit(dev);
- else if (test_bit(JOB_XMIT11, &ai->flags))
+ else if (test_bit(JOB_XMIT11, &ai->jobs))
airo_end_xmit11(dev);
- else if (test_bit(JOB_STATS, &ai->flags))
+ else if (test_bit(JOB_STATS, &ai->jobs))
airo_read_stats(ai);
- else if (test_bit(JOB_WSTATS, &ai->flags))
+ else if (test_bit(JOB_WSTATS, &ai->jobs))
airo_read_wireless_stats(ai);
- else if (test_bit(JOB_PROMISC, &ai->flags))
+ else if (test_bit(JOB_PROMISC, &ai->jobs))
airo_set_promisc(ai);
- else if (test_bit(JOB_MIC, &ai->flags))
+ else if (test_bit(JOB_MIC, &ai->jobs))
micinit(ai);
- else if (test_bit(JOB_EVENT, &ai->flags))
+ else if (test_bit(JOB_EVENT, &ai->jobs))
airo_send_event(dev);
- else if (test_bit(JOB_AUTOWEP, &ai->flags))
+ else if (test_bit(JOB_AUTOWEP, &ai->jobs))
timer_func(dev);
- else if (test_bit(JOB_SCAN_RESULTS, &ai->flags))
+ else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
airo_process_scan_results(ai);
else /* Shouldn't get here, but we make sure to unlock */
up(&ai->sem);
@@ -3133,7 +3188,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
if ( status & EV_MIC ) {
OUT4500( apriv, EVACK, EV_MIC );
if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
- set_bit(JOB_MIC, &apriv->flags);
+ set_bit(JOB_MIC, &apriv->jobs);
wake_up_interruptible(&apriv->thr_wait);
}
}
@@ -3187,7 +3242,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
if (down_trylock(&apriv->sem) != 0) {
- set_bit(JOB_EVENT, &apriv->flags);
+ set_bit(JOB_EVENT, &apriv->jobs);
wake_up_interruptible(&apriv->thr_wait);
} else
airo_send_event(dev);
@@ -5485,7 +5540,7 @@ static void timer_func( struct net_device *dev ) {
up(&apriv->sem);
/* Schedule check to see if the change worked */
- clear_bit(JOB_AUTOWEP, &apriv->flags);
+ clear_bit(JOB_AUTOWEP, &apriv->jobs);
apriv->expires = RUN_AT(HZ*3);
}
@@ -6876,7 +6931,7 @@ static int airo_get_range(struct net_device *dev,
}
range->num_txpower = i;
range->txpower_capa = IW_TXPOW_MWATT;
- range->we_version_source = 12;
+ range->we_version_source = 19;
range->we_version_compiled = WIRELESS_EXT;
range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range->retry_flags = IW_RETRY_LIMIT;
@@ -7152,6 +7207,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
u16 capabilities;
char * current_val; /* For rates */
int i;
+ char * buf;
/* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP;
@@ -7238,8 +7294,69 @@ static inline char *airo_translate_scan(struct net_device *dev,
if((current_val - current_ev) > IW_EV_LCP_LEN)
current_ev = current_val;
- /* The other data in the scan result are not really
- * interesting, so for now drop it - Jean II */
+ /* Beacon interval */
+ buf = kmalloc(30, GFP_KERNEL);
+ if (buf) {
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "bcn_int=%d", bss->beaconInterval);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+ kfree(buf);
+ }
+
+ /* Put WPA/RSN Information Elements into the event stream */
+ if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
+ unsigned int num_null_ies = 0;
+ u16 length = sizeof (bss->extra.iep);
+ struct ieee80211_info_element *info_element =
+ (struct ieee80211_info_element *) &bss->extra.iep;
+
+ while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
+ if (sizeof(*info_element) + info_element->len > length) {
+ /* Invalid element, don't continue parsing IE */
+ break;
+ }
+
+ switch (info_element->id) {
+ case MFIE_TYPE_SSID:
+ /* Two zero-length SSID elements
+ * mean we're done parsing elements */
+ if (!info_element->len)
+ num_null_ies++;
+ break;
+
+ case MFIE_TYPE_GENERIC:
+ if (info_element->len >= 4 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x01) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, (char *) info_element);
+ }
+ break;
+
+ case MFIE_TYPE_RSN:
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, (char *) info_element);
+ break;
+
+ default:
+ break;
+ }
+
+ length -= sizeof(*info_element) + info_element->len;
+ info_element =
+ (struct ieee80211_info_element *)&info_element->
+ data[info_element->len];
+ }
+ }
return current_ev;
}
@@ -7521,7 +7638,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
u32 *vals = stats_rid.vals;
/* Get stats out of the card */
- clear_bit(JOB_WSTATS, &local->flags);
+ clear_bit(JOB_WSTATS, &local->jobs);
if (local->power.event) {
up(&local->sem);
return;
@@ -7565,10 +7682,10 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
{
struct airo_info *local = dev->priv;
- if (!test_bit(JOB_WSTATS, &local->flags)) {
+ if (!test_bit(JOB_WSTATS, &local->jobs)) {
/* Get stats out of the card if available */
if (down_trylock(&local->sem) != 0) {
- set_bit(JOB_WSTATS, &local->flags);
+ set_bit(JOB_WSTATS, &local->jobs);
wake_up_interruptible(&local->thr_wait);
} else
airo_read_wireless_stats(local);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 0e1ac338cac1..bed6823d9809 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1838,7 +1838,7 @@ struct net_device * __init arlan_probe(int unit)
}
#ifdef MODULE
-int init_module(void)
+int __init init_module(void)
{
int i = 0;
@@ -1860,7 +1860,7 @@ int init_module(void)
}
-void cleanup_module(void)
+void __exit cleanup_module(void)
{
int i = 0;
struct net_device *dev;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 2e83083935e1..e66fdb1f3cfd 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -645,7 +645,6 @@ struct bcm43xx_private {
unsigned int irq;
void __iomem *mmio_addr;
- unsigned int mmio_len;
/* Do not use the lock directly. Use the bcm43xx_lock* helper
* functions, to be MMIO-safe. */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 35a4fcb6d923..7497fb16076e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -92,7 +92,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
pci_dev->subsystem_vendor, pci_dev->subsystem_device);
fappend("IRQ: %d\n", bcm->irq);
- fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len);
+ fappend("mmio_addr: 0x%p\n", bcm->mmio_addr);
fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
fappend("Radio disabled by hardware!\n");
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index bbecba02e697..d0318e525ba7 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -624,25 +624,28 @@ err_destroy_tx0:
static u16 generate_cookie(struct bcm43xx_dmaring *ring,
int slot)
{
- u16 cookie = 0x0000;
+ u16 cookie = 0xF000;
/* Use the upper 4 bits of the cookie as
* DMA controller ID and store the slot number
- * in the lower 12 bits
+ * in the lower 12 bits.
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
*/
switch (ring->mmio_base) {
default:
assert(0);
case BCM43xx_MMIO_DMA1_BASE:
+ cookie = 0xA000;
break;
case BCM43xx_MMIO_DMA2_BASE:
- cookie = 0x1000;
+ cookie = 0xB000;
break;
case BCM43xx_MMIO_DMA3_BASE:
- cookie = 0x2000;
+ cookie = 0xC000;
break;
case BCM43xx_MMIO_DMA4_BASE:
- cookie = 0x3000;
+ cookie = 0xD000;
break;
}
assert(((u16)slot & 0xF000) == 0x0000);
@@ -660,16 +663,16 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
struct bcm43xx_dmaring *ring = NULL;
switch (cookie & 0xF000) {
- case 0x0000:
+ case 0xA000:
ring = dma->tx_ring0;
break;
- case 0x1000:
+ case 0xB000:
ring = dma->tx_ring1;
break;
- case 0x2000:
+ case 0xC000:
ring = dma->tx_ring2;
break;
- case 0x3000:
+ case 0xD000:
ring = dma->tx_ring3;
break;
default:
@@ -839,8 +842,18 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
/* We received an xmit status. */
struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
struct bcm43xx_xmitstatus stat;
+ int i = 0;
stat.cookie = le16_to_cpu(hw->cookie);
+ while (stat.cookie == 0) {
+ if (unlikely(++i >= 10000)) {
+ assert(0);
+ break;
+ }
+ udelay(2);
+ barrier();
+ stat.cookie = le16_to_cpu(hw->cookie);
+ }
stat.flags = hw->flags;
stat.cnt1 = hw->cnt1;
stat.cnt2 = hw->cnt2;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
index 2d520e4b0276..b7d77638ba8c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -213,6 +213,14 @@ static inline
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
{
}
+static inline
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
+{
+}
+static inline
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
+{
+}
#endif /* CONFIG_BCM43XX_DMA */
#endif /* BCM43xx_DMA_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 9a06e61df0a2..736dde96c4a3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -128,13 +128,15 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
static struct pci_device_id bcm43xx_pci_tbl[] = {
/* Broadcom 4303 802.11b */
{ PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- /* Broadcom 4307 802.11b */
+ /* Broadcom 4307 802.11b */
{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- /* Broadcom 4318 802.11b/g */
+ /* Broadcom 4318 802.11b/g */
{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ /* Broadcom 4319 802.11a/b/g */
+ { PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
/* Broadcom 4306 802.11b/g */
{ PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- /* Broadcom 4306 802.11a */
+ /* Broadcom 4306 802.11a */
// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
/* Broadcom 4309 802.11a/b/g */
{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
@@ -939,9 +941,9 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
return 0;
}
-static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
+static int bcm43xx_geo_init(struct bcm43xx_private *bcm)
{
- struct ieee80211_geo geo;
+ struct ieee80211_geo *geo;
struct ieee80211_channel *chan;
int have_a = 0, have_bg = 0;
int i;
@@ -949,7 +951,10 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
struct bcm43xx_phyinfo *phy;
const char *iso_country;
- memset(&geo, 0, sizeof(geo));
+ geo = kzalloc(sizeof(*geo), GFP_KERNEL);
+ if (!geo)
+ return -ENOMEM;
+
for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) {
@@ -967,31 +972,36 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
if (have_a) {
- for (i = 0, channel = 0; channel < 201; channel++) {
- chan = &geo.a[i++];
+ for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL;
+ channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) {
+ chan = &geo->a[i++];
chan->freq = bcm43xx_channel_to_freq_a(channel);
chan->channel = channel;
}
- geo.a_channels = i;
+ geo->a_channels = i;
}
if (have_bg) {
- for (i = 0, channel = 1; channel < 15; channel++) {
- chan = &geo.bg[i++];
+ for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL;
+ channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) {
+ chan = &geo->bg[i++];
chan->freq = bcm43xx_channel_to_freq_bg(channel);
chan->channel = channel;
}
- geo.bg_channels = i;
+ geo->bg_channels = i;
}
- memcpy(geo.name, iso_country, 2);
+ memcpy(geo->name, iso_country, 2);
if (0 /*TODO: Outdoor use only */)
- geo.name[2] = 'O';
+ geo->name[2] = 'O';
else if (0 /*TODO: Indoor use only */)
- geo.name[2] = 'I';
+ geo->name[2] = 'I';
else
- geo.name[2] = ' ';
- geo.name[3] = '\0';
+ geo->name[2] = ' ';
+ geo->name[3] = '\0';
+
+ ieee80211_set_geo(bcm->ieee, geo);
+ kfree(geo);
- ieee80211_set_geo(bcm->ieee, &geo);
+ return 0;
}
/* DummyTransmission function, as documented on
@@ -3263,6 +3273,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
bcm43xx_sysfs_register(bcm);
//FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+ /*FIXME: This should be handled by softmac instead. */
+ schedule_work(&bcm->softmac->associnfo.work);
+
assert(err == 0);
out:
return err;
@@ -3288,8 +3301,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
bcm43xx_chipset_detach(bcm);
/* Do _not_ access the chip, after it is detached. */
- iounmap(bcm->mmio_addr);
-
+ pci_iounmap(pci_dev, bcm->mmio_addr);
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
@@ -3379,40 +3391,26 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
struct net_device *net_dev = bcm->net_dev;
int err;
int i;
- unsigned long mmio_start, mmio_flags, mmio_len;
u32 coremask;
err = pci_enable_device(pci_dev);
if (err) {
- printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
+ printk(KERN_ERR PFX "pci_enable_device() failed\n");
goto out;
}
- mmio_start = pci_resource_start(pci_dev, 0);
- mmio_flags = pci_resource_flags(pci_dev, 0);
- mmio_len = pci_resource_len(pci_dev, 0);
- if (!(mmio_flags & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX
- "%s, region #0 not an MMIO resource, aborting\n",
- pci_name(pci_dev));
- err = -ENODEV;
- goto err_pci_disable;
- }
err = pci_request_regions(pci_dev, KBUILD_MODNAME);
if (err) {
- printk(KERN_ERR PFX
- "could not access PCI resources (%i)\n", err);
+ printk(KERN_ERR PFX "pci_request_regions() failed\n");
goto err_pci_disable;
}
/* enable PCI bus-mastering */
pci_set_master(pci_dev);
- bcm->mmio_addr = ioremap(mmio_start, mmio_len);
+ bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
if (!bcm->mmio_addr) {
- printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
- pci_name(pci_dev));
+ printk(KERN_ERR PFX "pci_iomap() failed\n");
err = -EIO;
goto err_pci_release;
}
- bcm->mmio_len = mmio_len;
net_dev->base_addr = (unsigned long)bcm->mmio_addr;
bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
@@ -3479,16 +3477,17 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
goto err_80211_unwind;
bcm43xx_wireless_core_disable(bcm);
}
+ err = bcm43xx_geo_init(bcm);
+ if (err)
+ goto err_80211_unwind;
bcm43xx_pctl_set_crystal(bcm, 0);
/* Set the MAC address in the networking subsystem */
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+ if (is_valid_ether_addr(bcm->sprom.et1macaddr))
memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
else
memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
- bcm43xx_geo_init(bcm);
-
snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
"Broadcom %04X", bcm->chip_id);
@@ -3505,7 +3504,7 @@ err_80211_unwind:
err_chipset_detach:
bcm43xx_chipset_detach(bcm);
err_iounmap:
- iounmap(bcm->mmio_addr);
+ pci_iounmap(pci_dev, bcm->mmio_addr);
err_pci_release:
pci_release_regions(pci_dev);
err_pci_disable:
@@ -3556,7 +3555,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
unsigned long flags;
int keyidx;
- dprintk(KERN_INFO PFX "set security called\n");
+ dprintk(KERN_INFO PFX "set security called");
bcm43xx_lock_mmio(bcm, flags);
@@ -3569,24 +3568,25 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
if (sec->flags & SEC_ACTIVE_KEY) {
secinfo->active_key = sec->active_key;
- dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
+ dprintk(", .active_key = %d", sec->active_key);
}
if (sec->flags & SEC_UNICAST_GROUP) {
secinfo->unicast_uses_group = sec->unicast_uses_group;
- dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
+ dprintk(", .unicast_uses_group = %d", sec->unicast_uses_group);
}
if (sec->flags & SEC_LEVEL) {
secinfo->level = sec->level;
- dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
+ dprintk(", .level = %d", sec->level);
}
if (sec->flags & SEC_ENABLED) {
secinfo->enabled = sec->enabled;
- dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
+ dprintk(", .enabled = %d", sec->enabled);
}
if (sec->flags & SEC_ENCRYPT) {
secinfo->encrypt = sec->encrypt;
- dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
+ dprintk(", .encrypt = %d", sec->encrypt);
}
+ dprintk("\n");
if (bcm->initialized && !bcm->ieee->host_encrypt) {
if (secinfo->enabled) {
/* upload WEP keys to hardware */
@@ -3937,9 +3937,6 @@ static int bcm43xx_resume(struct pci_dev *pdev)
netif_device_attach(net_dev);
- /*FIXME: This should be handled by softmac instead. */
- schedule_work(&bcm->softmac->associnfo.work);
-
dprintk(KERN_INFO PFX "Device resumed.\n");
return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index eca79a38594a..30a202b258b5 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -118,12 +118,14 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
static inline
int bcm43xx_is_valid_channel_a(u8 channel)
{
- return (channel <= 200);
+ return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
+ && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
}
static inline
int bcm43xx_is_valid_channel_bg(u8 channel)
{
- return (channel >= 1 && channel <= 14);
+ return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
+ && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
}
static inline
int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 33137165727f..b0abac515530 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1287,7 +1287,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
if (radio->revision == 8)
bcm43xx_phy_write(bcm, 0x0805, 0x3230);
bcm43xx_phy_init_pctl(bcm);
- if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) {
+ if (bcm->chip_id == 0x4306 && bcm->chip_package == 2) {
bcm43xx_phy_write(bcm, 0x0429,
bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF);
bcm43xx_phy_write(bcm, 0x04C3,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index c59ddd40680d..0aa1bd269a25 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -27,6 +27,7 @@
#include "bcm43xx_pio.h"
#include "bcm43xx_main.h"
#include "bcm43xx_xmit.h"
+#include "bcm43xx_power.h"
#include <linux/delay.h>
@@ -44,10 +45,10 @@ static void tx_octet(struct bcm43xx_pioqueue *queue,
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI);
+ BCM43xx_PIO_TXCTL_WRITELO);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI);
+ BCM43xx_PIO_TXCTL_WRITELO);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
}
@@ -103,7 +104,7 @@ static void tx_complete(struct bcm43xx_pioqueue *queue,
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
skb->data[skb->len - 1]);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI |
+ BCM43xx_PIO_TXCTL_WRITELO |
BCM43xx_PIO_TXCTL_COMPLETE);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
@@ -112,9 +113,10 @@ static void tx_complete(struct bcm43xx_pioqueue *queue,
}
static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
- int packetindex)
+ struct bcm43xx_pio_txpacket *packet)
{
u16 cookie = 0x0000;
+ int packetindex;
/* We use the upper 4 bits for the PIO
* controller ID and the lower 12 bits
@@ -135,6 +137,7 @@ static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
default:
assert(0);
}
+ packetindex = pio_txpacket_getindex(packet);
assert(((u16)packetindex & 0xF000) == 0x0000);
cookie |= (u16)packetindex;
@@ -184,7 +187,7 @@ static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
bcm43xx_generate_txhdr(queue->bcm,
&txhdr, skb->data, skb->len,
(packet->xmitted_frags == 0),
- generate_cookie(queue, pio_txpacket_getindex(packet)));
+ generate_cookie(queue, packet));
tx_start(queue);
octets = skb->len + sizeof(txhdr);
@@ -241,7 +244,7 @@ static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
queue->tx_devq_packets++;
queue->tx_devq_used += octets;
- assert(packet->xmitted_frags <= packet->txb->nr_frags);
+ assert(packet->xmitted_frags < packet->txb->nr_frags);
packet->xmitted_frags++;
packet->xmitted_octets += octets;
}
@@ -257,8 +260,14 @@ static void tx_tasklet(unsigned long d)
unsigned long flags;
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
int err;
+ u16 txctl;
bcm43xx_lock_mmio(bcm, flags);
+
+ txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
+ if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
assert(packet->xmitted_frags < packet->txb->nr_frags);
if (packet->xmitted_frags == 0) {
@@ -288,6 +297,7 @@ static void tx_tasklet(unsigned long d)
next_packet:
continue;
}
+out_unlock:
bcm43xx_unlock_mmio(bcm, flags);
}
@@ -330,12 +340,19 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
(unsigned long)queue);
value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
- value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
+ value &= ~BCM43xx_SBF_XFER_REG_BYTESWAP;
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ printk(KERN_ERR PFX "ERROR: This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
if (qsize <= BCM43xx_PIO_TXQADJUST) {
- printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize);
+ printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n",
+ qsize);
goto err_freequeue;
}
qsize -= BCM43xx_PIO_TXQADJUST;
@@ -444,15 +461,10 @@ int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
{
struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
struct bcm43xx_pio_txpacket *packet;
- u16 tmp;
assert(!queue->tx_suspended);
assert(!list_empty(&queue->txfree));
- tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
- if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
- return -EBUSY;
-
packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
packet->txb = txb;
packet->xmitted_frags = 0;
@@ -462,7 +474,7 @@ int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
/* Suspend TX, if we are out of packets in the "free" queue. */
- if (unlikely(list_empty(&queue->txfree))) {
+ if (list_empty(&queue->txfree)) {
netif_stop_queue(queue->bcm->net_dev);
queue->tx_suspended = 1;
}
@@ -480,15 +492,15 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
queue = parse_cookie(bcm, status->cookie, &packet);
assert(queue);
-//TODO
-if (!queue)
-return;
+
free_txpacket(packet, 1);
- if (unlikely(queue->tx_suspended)) {
+ if (queue->tx_suspended) {
queue->tx_suspended = 0;
netif_wake_queue(queue->bcm->net_dev);
}
- /* If there are packets on the txqueue, poke the tasklet. */
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
if (!list_empty(&queue->txqueue))
tasklet_schedule(&queue->txtask);
}
@@ -519,12 +531,9 @@ void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
int i, preamble_readwords;
struct sk_buff *skb;
-return;
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
- if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
- dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
+ if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE))
return;
- }
bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
BCM43xx_PIO_RXCTL_DATAAVAILABLE);
@@ -538,8 +547,7 @@ return;
return;
data_ready:
-//FIXME: endianess in this function.
- len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+ len = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
if (unlikely(len > 0x700)) {
pio_rx_error(queue, 0, "len > 0x700");
return;
@@ -555,7 +563,7 @@ data_ready:
preamble_readwords = 18 / sizeof(u16);
for (i = 0; i < preamble_readwords; i++) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
- preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
+ preamble[i + 1] = cpu_to_le16(tmp);
}
rxhdr = (struct bcm43xx_rxhdr *)preamble;
rxflags2 = le16_to_cpu(rxhdr->flags2);
@@ -591,16 +599,40 @@ data_ready:
}
skb_put(skb, len);
for (i = 0; i < len - 1; i += 2) {
- tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
- *((u16 *)(skb->data + i)) = tmp;
+ tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+ *((u16 *)(skb->data + i)) = cpu_to_le16(tmp);
}
if (len % 2) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
skb->data[len - 1] = (tmp & 0x00FF);
+/* The specs say the following is required, but
+ * it is wrong and corrupts the PLCP. If we don't do
+ * this, the PLCP seems to be correct. So ifdef it out for now.
+ */
+#if 0
if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
- skb->data[0x20] = (tmp & 0xFF00) >> 8;
+ skb->data[2] = (tmp & 0xFF00) >> 8;
else
- skb->data[0x1E] = (tmp & 0xFF00) >> 8;
+ skb->data[0] = (tmp & 0xFF00) >> 8;
+#endif
}
+ skb_trim(skb, len - IEEE80211_FCS_LEN);
bcm43xx_rx(queue->bcm, skb, rxhdr);
}
+
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
+{
+ bcm43xx_power_saving_ctl_bits(queue->bcm, -1, 1);
+ bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+ bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
+ | BCM43xx_PIO_TXCTL_SUSPEND);
+}
+
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
+{
+ bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+ bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
+ & ~BCM43xx_PIO_TXCTL_SUSPEND);
+ bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
+ tasklet_schedule(&queue->txtask);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index 970627bc1769..dfc78209e3a3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -14,8 +14,8 @@
#define BCM43xx_PIO_RXCTL 0x08
#define BCM43xx_PIO_RXDATA 0x0A
-#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0)
-#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1)
+#define BCM43xx_PIO_TXCTL_WRITELO (1 << 0)
+#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 1)
#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2)
#define BCM43xx_PIO_TXCTL_INIT (1 << 3)
#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7)
@@ -95,6 +95,7 @@ void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
u16 offset, u16 value)
{
bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+ mmiowb();
}
@@ -107,6 +108,9 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
struct bcm43xx_xmitstatus *status);
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+
#else /* CONFIG_BCM43XX_PIO */
static inline
@@ -133,6 +137,14 @@ static inline
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
{
}
+static inline
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
+{
+}
+static inline
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
+{
+}
#endif /* CONFIG_BCM43XX_PIO */
#endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 3edbb481a0a0..b45063974ae9 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -182,8 +182,11 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
mode = BCM43xx_INITIAL_IWMODE;
bcm43xx_lock_mmio(bcm, flags);
- if (bcm->ieee->iw_mode != mode)
- bcm43xx_set_iwmode(bcm, mode);
+ if (bcm->initialized) {
+ if (bcm->ieee->iw_mode != mode)
+ bcm43xx_set_iwmode(bcm, mode);
+ } else
+ bcm->ieee->iw_mode = mode;
bcm43xx_unlock_mmio(bcm, flags);
return 0;
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
index 346c6febb033..2aa2f389c0d5 100644
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/hermes.c
@@ -121,12 +121,6 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
hw->iobase = address;
hw->reg_spacing = reg_spacing;
hw->inten = 0x0;
-
-#ifdef HERMES_DEBUG_BUFFER
- hw->dbufp = 0;
- memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
- memset(&hw->profile, 0, sizeof(hw->profile));
-#endif
}
int hermes_init(hermes_t *hw)
@@ -347,19 +341,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
reg = hermes_read_reg(hw, oreg);
}
-#ifdef HERMES_DEBUG_BUFFER
- hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
-
- if (k < HERMES_BAP_BUSY_TIMEOUT) {
- struct hermes_debug_entry *e =
- &hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
- e->bap = bap;
- e->id = id;
- e->offset = offset;
- e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
- }
-#endif
-
if (reg & HERMES_OFFSET_BUSY)
return -ETIMEDOUT;
@@ -419,8 +400,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
}
/* Write a block of data to the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem. len
- * must be even.
+ * BAP. Synchronization/serialization is the caller's problem.
*
* Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
*/
@@ -430,7 +410,7 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
int err = 0;
- if ( (len < 0) || (len % 2) )
+ if (len < 0)
return -EINVAL;
err = hermes_bap_seek(hw, bap, id, offset);
@@ -438,49 +418,12 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
goto out;
/* Actually do the transfer */
- hermes_write_words(hw, dreg, buf, len/2);
+ hermes_write_bytes(hw, dreg, buf, len);
out:
return err;
}
-/* Write a block of data to the chip's buffer with padding if
- * neccessary, via the BAP. Synchronization/serialization is the
- * caller's problem. len must be even.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
- */
-int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, int len,
- u16 id, u16 offset)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
-
- if (len < 0 || len % 2 || data_len > len)
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, id, offset);
- if (err)
- goto out;
-
- /* Transfer all the complete words of data */
- hermes_write_words(hw, dreg, buf, data_len/2);
- /* If there is an odd byte left over pad and transfer it */
- if (data_len & 1) {
- u8 end[2];
- end[1] = 0;
- end[0] = ((unsigned char *)buf)[data_len - 1];
- hermes_write_words(hw, dreg, end, 1);
- data_len ++;
- }
- /* Now send zeros for the padding */
- if (data_len < len)
- hermes_clear_words(hw, dreg, (len - data_len) / 2);
- /* Complete */
- out:
- return err;
-}
-
/* Read a Length-Type-Value record from the card.
*
* If length is NULL, we ignore the length read from the card, and
@@ -553,7 +496,7 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
count = length - 1;
- hermes_write_words(hw, dreg, value, count);
+ hermes_write_bytes(hw, dreg, value, count << 1);
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
rid, NULL);
@@ -568,7 +511,6 @@ EXPORT_SYMBOL(hermes_allocate);
EXPORT_SYMBOL(hermes_bap_pread);
EXPORT_SYMBOL(hermes_bap_pwrite);
-EXPORT_SYMBOL(hermes_bap_pwrite_pad);
EXPORT_SYMBOL(hermes_read_ltv);
EXPORT_SYMBOL(hermes_write_ltv);
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
index 7644f72a9f4e..8e3f0e3edb58 100644
--- a/drivers/net/wireless/hermes.h
+++ b/drivers/net/wireless/hermes.h
@@ -328,16 +328,6 @@ struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
} __attribute__ ((packed));
-// #define HERMES_DEBUG_BUFFER 1
-#define HERMES_DEBUG_BUFSIZE 4096
-struct hermes_debug_entry {
- int bap;
- u16 id, offset;
- int cycles;
-};
-
-#ifdef __KERNEL__
-
/* Timeouts */
#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
@@ -347,14 +337,7 @@ typedef struct hermes {
int reg_spacing;
#define HERMES_16BIT_REGSPACING 0
#define HERMES_32BIT_REGSPACING 1
-
u16 inten; /* Which interrupts should be enabled? */
-
-#ifdef HERMES_DEBUG_BUFFER
- struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE];
- unsigned long dbufp;
- unsigned long profile[HERMES_BAP_BUSY_TIMEOUT+1];
-#endif
} hermes_t;
/* Register access convenience macros */
@@ -376,8 +359,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
u16 id, u16 offset);
int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
u16 id, u16 offset);
-int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf,
- unsigned data_len, int len, u16 id, u16 offset);
int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
u16 *length, void *buf);
int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
@@ -425,10 +406,13 @@ static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsi
ioread16_rep(hw->iobase + off, buf, count);
}
-static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count)
+static inline void hermes_write_bytes(struct hermes *hw, int off,
+ const char *buf, unsigned count)
{
off = off << hw->reg_spacing;
- iowrite16_rep(hw->iobase + off, buf, count);
+ iowrite16_rep(hw->iobase + off, buf, count >> 1);
+ if (unlikely(count & 1))
+ iowrite8(buf[count - 1], hw->iobase + off);
}
static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
@@ -462,21 +446,4 @@ static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word)
return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
}
-#else /* ! __KERNEL__ */
-
-/* These are provided for the benefit of userspace drivers and testing programs
- which use ioperm() or iopl() */
-
-#define hermes_read_reg(base, off) (inw((base) + (off)))
-#define hermes_write_reg(base, off, val) (outw((val), (base) + (off)))
-
-#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name))
-#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val)))
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count)))
-#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count)))
-
-#endif /* ! __KERNEL__ */
-
#endif /* _HERMES_H */
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 06a5214145e3..4a5be70c0419 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -534,5 +534,4 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
-EXPORT_SYMBOL(hostap_dump_tx_80211);
EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 06c3fa32b310..ba13125024cb 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -3276,17 +3276,6 @@ EXPORT_SYMBOL(hostap_init_data);
EXPORT_SYMBOL(hostap_init_ap_proc);
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_is_sta_authorized);
-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 --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 55bed923fbe9..db03dc2646df 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -881,6 +881,12 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12(
"ZoomAir 11Mbps High", "Rate wireless Networking",
0x273fe3db, 0x32a1eaee),
+ PCMCIA_DEVICE_PROD_ID123(
+ "Pretec", "CompactWLAN Card 802.11b", "2.5",
+ 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
+ PCMCIA_DEVICE_PROD_ID123(
+ "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
+ 0xc7b8df9d, 0x1700d087, 0x4b74baa0),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 8b37e824dfcb..8399de581893 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1860,7 +1860,7 @@ static char * __prism2_translate_scan(local_info_t *local,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
if (scan) {
- chan = scan->chid;
+ chan = le16_to_cpu(scan->chid);
} else if (bss) {
chan = bss->chan;
} else {
@@ -1868,7 +1868,7 @@ static char * __prism2_translate_scan(local_info_t *local,
}
if (chan > 0) {
- iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000;
+ iwe.u.freq.m = freq_list[chan - 1] * 100000;
iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 8dd4c4446a64..93786f4218f0 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -1125,11 +1125,9 @@ EXPORT_SYMBOL(hostap_set_auth_algs);
EXPORT_SYMBOL(hostap_dump_rx_header);
EXPORT_SYMBOL(hostap_dump_tx_header);
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_set_hostapd_sta);
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index bca89cff85a6..39f82f219749 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -33,7 +33,44 @@
#include "ipw2200.h"
#include <linux/version.h>
-#define IPW2200_VERSION "git-1.1.1"
+
+#ifndef KBUILD_EXTMOD
+#define VK "k"
+#else
+#define VK
+#endif
+
+#ifdef CONFIG_IPW2200_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IPW2200_MONITOR
+#define VM "m"
+#else
+#define VM
+#endif
+
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+#define VP "p"
+#else
+#define VP
+#endif
+
+#ifdef CONFIG_IPW2200_RADIOTAP
+#define VR "r"
+#else
+#define VR
+#endif
+
+#ifdef CONFIG_IPW2200_QOS
+#define VQ "q"
+#else
+#define VQ
+#endif
+
+#define IPW2200_VERSION "1.1.2" VK VD VM VP VR VQ
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
#define DRV_VERSION IPW2200_VERSION
@@ -46,7 +83,9 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
static int cmdlog = 0;
+#ifdef CONFIG_IPW2200_DEBUG
static int debug = 0;
+#endif
static int channel = 0;
static int mode = 0;
@@ -61,8 +100,14 @@ static int roaming = 1;
static const char ipw_modes[] = {
'a', 'b', 'g', '?'
};
+static int antenna = CFG_SYS_ANTENNA_BOTH;
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
+#endif
+
+
+#ifdef CONFIG_IPW2200_QOS
static int qos_enable = 0;
static int qos_burst_enable = 0;
static int qos_no_ack_mask = 0;
@@ -126,7 +171,7 @@ static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_q
*qos_param);
static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
*qos_param);
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
static void ipw_remove_current_network(struct ipw_priv *priv);
@@ -1269,6 +1314,105 @@ static ssize_t show_cmd_log(struct device *d,
static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL);
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+static void ipw_prom_free(struct ipw_priv *priv);
+static int ipw_prom_alloc(struct ipw_priv *priv);
+static ssize_t store_rtap_iface(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ int rc = 0;
+
+ if (count < 1)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ if (!rtap_iface)
+ return count;
+
+ if (netif_running(priv->prom_net_dev)) {
+ IPW_WARNING("Interface is up. Cannot unregister.\n");
+ return count;
+ }
+
+ ipw_prom_free(priv);
+ rtap_iface = 0;
+ break;
+
+ case '1':
+ if (rtap_iface)
+ return count;
+
+ rc = ipw_prom_alloc(priv);
+ if (!rc)
+ rtap_iface = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (rc) {
+ IPW_ERROR("Failed to register promiscuous network "
+ "device (error %d).\n", rc);
+ }
+
+ return count;
+}
+
+static ssize_t show_rtap_iface(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ if (rtap_iface)
+ return sprintf(buf, "%s", priv->prom_net_dev->name);
+ else {
+ buf[0] = '-';
+ buf[1] = '1';
+ buf[2] = '\0';
+ return 3;
+ }
+}
+
+static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface,
+ store_rtap_iface);
+
+static ssize_t store_rtap_filter(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+
+ if (!priv->prom_priv) {
+ IPW_ERROR("Attempting to set filter without "
+ "rtap_iface enabled.\n");
+ return -EPERM;
+ }
+
+ priv->prom_priv->filter = simple_strtol(buf, NULL, 0);
+
+ IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n",
+ BIT_ARG16(priv->prom_priv->filter));
+
+ return count;
+}
+
+static ssize_t show_rtap_filter(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "0x%04X",
+ priv->prom_priv ? priv->prom_priv->filter : 0);
+}
+
+static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter,
+ store_rtap_filter);
+#endif
+
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
char *buf)
{
@@ -2025,16 +2169,11 @@ static int ipw_send_host_complete(struct ipw_priv *priv)
return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);
}
-static int ipw_send_system_config(struct ipw_priv *priv,
- struct ipw_sys_config *config)
+static int ipw_send_system_config(struct ipw_priv *priv)
{
- if (!priv || !config) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(*config),
- config);
+ return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG,
+ sizeof(priv->sys_config),
+ &priv->sys_config);
}
static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
@@ -3104,10 +3243,10 @@ static int ipw_reset_nic(struct ipw_priv *priv)
struct ipw_fw {
- u32 ver;
- u32 boot_size;
- u32 ucode_size;
- u32 fw_size;
+ __le32 ver;
+ __le32 boot_size;
+ __le32 ucode_size;
+ __le32 fw_size;
u8 data[0];
};
@@ -3131,8 +3270,8 @@ static int ipw_get_fw(struct ipw_priv *priv,
fw = (void *)(*raw)->data;
- if ((*raw)->size < sizeof(*fw) +
- fw->boot_size + fw->ucode_size + fw->fw_size) {
+ if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) +
+ le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) {
IPW_ERROR("%s is too small or corrupt (%zd)\n",
name, (*raw)->size);
return -EINVAL;
@@ -3237,8 +3376,9 @@ static int ipw_load(struct ipw_priv *priv)
fw = (void *)raw->data;
boot_img = &fw->data[0];
- ucode_img = &fw->data[fw->boot_size];
- fw_img = &fw->data[fw->boot_size + fw->ucode_size];
+ ucode_img = &fw->data[le32_to_cpu(fw->boot_size)];
+ fw_img = &fw->data[le32_to_cpu(fw->boot_size) +
+ le32_to_cpu(fw->ucode_size)];
if (rc < 0)
goto error;
@@ -3272,7 +3412,7 @@ static int ipw_load(struct ipw_priv *priv)
IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
/* DMA the initial boot firmware into the device */
- rc = ipw_load_firmware(priv, boot_img, fw->boot_size);
+ rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size));
if (rc < 0) {
IPW_ERROR("Unable to load boot firmware: %d\n", rc);
goto error;
@@ -3294,7 +3434,7 @@ static int ipw_load(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
/* DMA the ucode into the device */
- rc = ipw_load_ucode(priv, ucode_img, fw->ucode_size);
+ rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size));
if (rc < 0) {
IPW_ERROR("Unable to load ucode: %d\n", rc);
goto error;
@@ -3304,7 +3444,7 @@ static int ipw_load(struct ipw_priv *priv)
ipw_stop_nic(priv);
/* DMA bss firmware into the device */
- rc = ipw_load_firmware(priv, fw_img, fw->fw_size);
+ rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size));
if (rc < 0) {
IPW_ERROR("Unable to load firmware: %d\n", rc);
goto error;
@@ -3700,7 +3840,17 @@ static void ipw_bg_disassociate(void *data)
static void ipw_system_config(void *data)
{
struct ipw_priv *priv = data;
- ipw_send_system_config(priv, &priv->sys_config);
+
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
+ priv->sys_config.accept_all_data_frames = 1;
+ priv->sys_config.accept_non_directed_frames = 1;
+ priv->sys_config.accept_all_mgmt_bcpr = 1;
+ priv->sys_config.accept_all_mgmt_frames = 1;
+ }
+#endif
+
+ ipw_send_system_config(priv);
}
struct ipw_status_code {
@@ -3771,6 +3921,13 @@ static void inline average_init(struct average *avg)
memset(avg, 0, sizeof(*avg));
}
+#define DEPTH_RSSI 8
+#define DEPTH_NOISE 16
+static s16 exponential_average(s16 prev_avg, s16 val, u8 depth)
+{
+ return ((depth-1)*prev_avg + val)/depth;
+}
+
static void average_add(struct average *avg, s16 val)
{
avg->sum -= avg->entries[avg->pos];
@@ -3800,8 +3957,8 @@ static void ipw_reset_stats(struct ipw_priv *priv)
priv->quality = 0;
average_init(&priv->average_missed_beacons);
- average_init(&priv->average_rssi);
- average_init(&priv->average_noise);
+ priv->exp_avg_rssi = -60;
+ priv->exp_avg_noise = -85 + 0x100;
priv->last_rate = 0;
priv->last_missed_beacons = 0;
@@ -4008,7 +4165,7 @@ static void ipw_gather_stats(struct ipw_priv *priv)
IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n",
tx_quality, tx_failures_delta, tx_packets_delta);
- rssi = average_value(&priv->average_rssi);
+ rssi = priv->exp_avg_rssi;
signal_quality =
(100 *
(priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
@@ -4185,7 +4342,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
queue_work(priv->workqueue,
&priv->system_config);
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl))
if ((priv->status & STATUS_AUTH) &&
@@ -4482,6 +4639,24 @@ static void ipw_rx_notification(struct ipw_priv *priv,
&& priv->status & STATUS_ASSOCIATED)
queue_delayed_work(priv->workqueue,
&priv->request_scan, HZ);
+
+ /* Send an empty event to user space.
+ * We don't send the received data on the event because
+ * it would require us to do complex transcoding, and
+ * we want to minimise the work done in the irq handler
+ * Use a request to extract the data.
+ * Also, we generate this even for any scan, regardless
+ * on how the scan was initiated. User space can just
+ * sync on periodic scan to get fresh data...
+ * Jean II */
+ if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) {
+ union iwreq_data wrqu;
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN,
+ &wrqu, NULL);
+ }
break;
}
@@ -4577,11 +4752,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
case HOST_NOTIFICATION_NOISE_STATS:{
if (notif->size == sizeof(u32)) {
- priv->last_noise =
- (u8) (le32_to_cpu(notif->u.noise.value) &
- 0xff);
- average_add(&priv->average_noise,
- priv->last_noise);
+ priv->exp_avg_noise =
+ exponential_average(priv->exp_avg_noise,
+ (u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
+ DEPTH_NOISE);
break;
}
@@ -6170,8 +6344,6 @@ static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie,
{
/* make sure WPA is enabled */
ipw_wpa_enable(priv, 1);
-
- ipw_disassociate(priv);
}
static int ipw_set_rsn_capa(struct ipw_priv *priv,
@@ -6365,6 +6537,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
case IW_AUTH_WPA_ENABLED:
ret = ipw_wpa_enable(priv, param->value);
+ ipw_disassociate(priv);
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
@@ -6506,7 +6679,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
return 0;
}
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
/* QoS */
/*
@@ -6853,61 +7026,55 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
return from_priority_to_tx_queue[priority] - 1;
}
-/*
-* add QoS parameter to the TX command
-*/
-static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
- u16 priority,
- struct tfd_data *tfd, u8 unicast)
+static int ipw_is_qos_active(struct net_device *dev,
+ struct sk_buff *skb)
{
- int ret = 0;
- int tx_queue_id = 0;
+ struct ipw_priv *priv = ieee80211_priv(dev);
struct ieee80211_qos_data *qos_data = NULL;
int active, supported;
- unsigned long flags;
+ u8 *daddr = skb->data + ETH_ALEN;
+ int unicast = !is_multicast_ether_addr(daddr);
if (!(priv->status & STATUS_ASSOCIATED))
return 0;
qos_data = &priv->assoc_network->qos_data;
- spin_lock_irqsave(&priv->ieee->lock, flags);
-
if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
if (unicast == 0)
qos_data->active = 0;
else
qos_data->active = qos_data->supported;
}
-
active = qos_data->active;
supported = qos_data->supported;
-
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d "
"unicast %d\n",
priv->qos_data.qos_enable, active, supported, unicast);
- if (active && priv->qos_data.qos_enable) {
- ret = from_priority_to_tx_queue[priority];
- tx_queue_id = ret - 1;
- IPW_DEBUG_QOS("QoS packet priority is %d \n", priority);
- if (priority <= 7) {
- tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
- tfd->tfd.tfd_26.mchdr.qos_ctrl = priority;
- tfd->tfd.tfd_26.mchdr.frame_ctl |=
- IEEE80211_STYPE_QOS_DATA;
-
- if (priv->qos_data.qos_no_ack_mask &
- (1UL << tx_queue_id)) {
- tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
- tfd->tfd.tfd_26.mchdr.qos_ctrl |=
- CTRL_QOS_NO_ACK;
- }
- }
- }
+ if (active && priv->qos_data.qos_enable)
+ return 1;
- return ret;
+ return 0;
+
+}
+/*
+* add QoS parameter to the TX command
+*/
+static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
+ u16 priority,
+ struct tfd_data *tfd)
+{
+ int tx_queue_id = 0;
+
+
+ tx_queue_id = from_priority_to_tx_queue[priority] - 1;
+ tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
+
+ if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
+ tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
+ tfd->tfd.tfd_26.mchdr.qos_ctrl |= CTRL_QOS_NO_ACK;
+ }
+ return 0;
}
/*
@@ -6977,7 +7144,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos
qos_param);
}
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
static int ipw_associate_network(struct ipw_priv *priv,
struct ieee80211_network *network,
@@ -7116,7 +7283,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
else
priv->sys_config.answer_broadcast_ssid_probe = 0;
- err = ipw_send_system_config(priv, &priv->sys_config);
+ err = ipw_send_system_config(priv);
if (err) {
IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
return err;
@@ -7141,7 +7308,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
priv->assoc_network = network;
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
ipw_qos_association(priv, network);
#endif
@@ -7415,7 +7582,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
}
}
-#ifdef CONFIG_IEEE80211_RADIOTAP
+#ifdef CONFIG_IPW2200_RADIOTAP
static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
struct ipw_rx_mem_buffer *rxb,
struct ieee80211_rx_stats *stats)
@@ -7432,15 +7599,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
/* Magic struct that slots into the radiotap header -- no reason
* to build this manually element by element, we can write it much
* more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- u8 rt_flags; /* radiotap packet flags */
- u8 rt_rate; /* rate in 500kb/s */
- u16 rt_channel; /* channel in mhz */
- u16 rt_chbitmask; /* channel bitfield */
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- u8 rt_antenna; /* antenna number */
- } *ipw_rt;
+ struct ipw_rt_hdr *ipw_rt;
short len = le16_to_cpu(pkt->u.frame.length);
@@ -7494,9 +7653,11 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
/* Big bitfield of all the fields we provide in radiotap */
ipw_rt->rt_hdr.it_present =
((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_TSFT) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
(1 << IEEE80211_RADIOTAP_ANTENNA));
/* Zero the flags, we'll add to them as we go */
@@ -7582,6 +7743,217 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
}
#endif
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+#define ieee80211_is_probe_response(fc) \
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP )
+
+#define ieee80211_is_management(fc) \
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+
+#define ieee80211_is_control(fc) \
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+
+#define ieee80211_is_data(fc) \
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+
+#define ieee80211_is_assoc_request(fc) \
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ)
+
+#define ieee80211_is_reassoc_request(fc) \
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+
+static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
+ struct ipw_rx_mem_buffer *rxb,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
+ struct ipw_rx_frame *frame = &pkt->u.frame;
+ struct ipw_rt_hdr *ipw_rt;
+
+ /* First cache any information we need before we overwrite
+ * the information provided in the skb from the hardware */
+ struct ieee80211_hdr *hdr;
+ u16 channel = frame->received_channel;
+ u8 phy_flags = frame->antennaAndPhy;
+ s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
+ s8 noise = frame->noise;
+ u8 rate = frame->rate;
+ short len = le16_to_cpu(pkt->u.frame.length);
+ u64 tsf = 0;
+ struct sk_buff *skb;
+ int hdr_only = 0;
+ u16 filter = priv->prom_priv->filter;
+
+ /* If the filter is set to not include Rx frames then return */
+ if (filter & IPW_PROM_NO_RX)
+ return;
+
+ /* We received data from the HW, so stop the watchdog */
+ priv->prom_net_dev->trans_start = jiffies;
+
+ if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+ priv->prom_priv->ieee->stats.rx_errors++;
+ IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
+ return;
+ }
+
+ /* We only process data packets if the interface is open */
+ if (unlikely(!netif_running(priv->prom_net_dev))) {
+ priv->prom_priv->ieee->stats.rx_dropped++;
+ IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+ return;
+ }
+
+ /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
+ * that now */
+ if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
+ /* FIXME: Should alloc bigger skb instead */
+ priv->prom_priv->ieee->stats.rx_dropped++;
+ IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
+ if (ieee80211_is_management(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_MGMT)
+ return;
+ if (filter & IPW_PROM_MGMT_HEADER_ONLY)
+ hdr_only = 1;
+ } else if (ieee80211_is_control(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_CTL)
+ return;
+ if (filter & IPW_PROM_CTL_HEADER_ONLY)
+ hdr_only = 1;
+ } else if (ieee80211_is_data(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_DATA)
+ return;
+ if (filter & IPW_PROM_DATA_HEADER_ONLY)
+ hdr_only = 1;
+ }
+
+ /* Copy the SKB since this is for the promiscuous side */
+ skb = skb_copy(rxb->skb, GFP_ATOMIC);
+ if (skb == NULL) {
+ IPW_ERROR("skb_clone failed for promiscuous copy.\n");
+ return;
+ }
+
+ /* copy the frame data to write after where the radiotap header goes */
+ ipw_rt = (void *)skb->data;
+
+ if (hdr_only)
+ len = ieee80211_get_hdrlen(hdr->frame_ctl);
+
+ memcpy(ipw_rt->payload, hdr, len);
+
+ /* Zero the radiotap static buffer ... We only need to zero the bytes
+ * NOT part of our real header, saves a little time.
+ *
+ * No longer necessary since we fill in all our data. Purge before
+ * merging patch officially.
+ * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
+ * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
+ */
+
+ ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
+ ipw_rt->rt_hdr.it_len = sizeof(*ipw_rt); /* total header+data */
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(skb, ipw_rt->rt_hdr.it_len + len);
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ ipw_rt->rt_hdr.it_present =
+ ((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA));
+
+ /* Zero the flags, we'll add to them as we go */
+ ipw_rt->rt_flags = 0;
+
+ ipw_rt->rt_tsf = tsf;
+
+ /* Convert to DBM */
+ ipw_rt->rt_dbmsignal = signal;
+ ipw_rt->rt_dbmnoise = noise;
+
+ /* Convert the channel data and set the flags */
+ ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel));
+ if (channel > 14) { /* 802.11a */
+ ipw_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ } else if (phy_flags & (1 << 5)) { /* 802.11b */
+ ipw_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ } else { /* 802.11g */
+ ipw_rt->rt_chbitmask =
+ (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
+ }
+
+ /* set the rate in multiples of 500k/s */
+ switch (rate) {
+ case IPW_TX_RATE_1MB:
+ ipw_rt->rt_rate = 2;
+ break;
+ case IPW_TX_RATE_2MB:
+ ipw_rt->rt_rate = 4;
+ break;
+ case IPW_TX_RATE_5MB:
+ ipw_rt->rt_rate = 10;
+ break;
+ case IPW_TX_RATE_6MB:
+ ipw_rt->rt_rate = 12;
+ break;
+ case IPW_TX_RATE_9MB:
+ ipw_rt->rt_rate = 18;
+ break;
+ case IPW_TX_RATE_11MB:
+ ipw_rt->rt_rate = 22;
+ break;
+ case IPW_TX_RATE_12MB:
+ ipw_rt->rt_rate = 24;
+ break;
+ case IPW_TX_RATE_18MB:
+ ipw_rt->rt_rate = 36;
+ break;
+ case IPW_TX_RATE_24MB:
+ ipw_rt->rt_rate = 48;
+ break;
+ case IPW_TX_RATE_36MB:
+ ipw_rt->rt_rate = 72;
+ break;
+ case IPW_TX_RATE_48MB:
+ ipw_rt->rt_rate = 96;
+ break;
+ case IPW_TX_RATE_54MB:
+ ipw_rt->rt_rate = 108;
+ break;
+ default:
+ ipw_rt->rt_rate = 0;
+ break;
+ }
+
+ /* antenna number */
+ ipw_rt->rt_antenna = (phy_flags & 3);
+
+ /* set the preamble flag if we have it */
+ if (phy_flags & (1 << 6))
+ ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
+
+ if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) {
+ priv->prom_priv->ieee->stats.rx_errors++;
+ dev_kfree_skb_any(skb);
+ }
+}
+#endif
+
static int is_network_packet(struct ipw_priv *priv,
struct ieee80211_hdr_4addr *header)
{
@@ -7808,15 +8180,21 @@ static void ipw_rx(struct ipw_priv *priv)
priv->rx_packets++;
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ if (priv->prom_net_dev && netif_running(priv->prom_net_dev))
+ ipw_handle_promiscuous_rx(priv, rxb, &stats);
+#endif
+
#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
-#ifdef CONFIG_IEEE80211_RADIOTAP
- ipw_handle_data_packet_monitor(priv,
- rxb,
- &stats);
+#ifdef CONFIG_IPW2200_RADIOTAP
+
+ ipw_handle_data_packet_monitor(priv,
+ rxb,
+ &stats);
#else
- ipw_handle_data_packet(priv, rxb,
- &stats);
+ ipw_handle_data_packet(priv, rxb,
+ &stats);
#endif
break;
}
@@ -7837,9 +8215,9 @@ static void ipw_rx(struct ipw_priv *priv)
if (network_packet && priv->assoc_network) {
priv->assoc_network->stats.rssi =
stats.rssi;
- average_add(&priv->average_rssi,
- stats.rssi);
- priv->last_rx_rssi = stats.rssi;
+ priv->exp_avg_rssi =
+ exponential_average(priv->exp_avg_rssi,
+ stats.rssi, DEPTH_RSSI);
}
IPW_DEBUG_RX("Frame: len=%u\n",
@@ -7982,10 +8360,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
/* TODO: Validate that provided channel is in range */
}
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
ipw_qos_init(priv, qos_enable, qos_burst_enable,
burst_duration_CCK, burst_duration_OFDM);
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
switch (mode) {
case 1:
@@ -7996,7 +8374,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
#ifdef CONFIG_IPW2200_MONITOR
case 2:
priv->ieee->iw_mode = IW_MODE_MONITOR;
-#ifdef CONFIG_IEEE80211_RADIOTAP
+#ifdef CONFIG_IPW2200_RADIOTAP
priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
priv->net_dev->type = ARPHRD_IEEE80211;
@@ -8251,7 +8629,7 @@ static int ipw_wx_set_mode(struct net_device *dev,
priv->net_dev->type = ARPHRD_ETHER;
if (wrqu->mode == IW_MODE_MONITOR)
-#ifdef CONFIG_IEEE80211_RADIOTAP
+#ifdef CONFIG_IPW2200_RADIOTAP
priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
priv->net_dev->type = ARPHRD_IEEE80211;
@@ -8379,7 +8757,8 @@ static int ipw_wx_get_range(struct net_device *dev,
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP));
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
@@ -8734,6 +9113,7 @@ static int ipw_wx_get_rate(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
wrqu->bitrate.value = priv->last_rate;
+ wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
mutex_unlock(&priv->mutex);
IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
return 0;
@@ -9351,7 +9731,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
if (enable) {
if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
-#ifdef CONFIG_IEEE80211_RADIOTAP
+#ifdef CONFIG_IPW2200_RADIOTAP
priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
priv->net_dev->type = ARPHRD_IEEE80211;
@@ -9579,8 +9959,8 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
}
wstats->qual.qual = priv->quality;
- wstats->qual.level = average_value(&priv->average_rssi);
- wstats->qual.noise = average_value(&priv->average_noise);
+ wstats->qual.level = priv->exp_avg_rssi;
+ wstats->qual.noise = priv->exp_avg_noise;
wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM;
@@ -9608,7 +9988,9 @@ static void init_sys_config(struct ipw_sys_config *sys_config)
sys_config->disable_unicast_decryption = 1;
sys_config->exclude_multicast_unencrypted = 0;
sys_config->disable_multicast_decryption = 1;
- sys_config->antenna_diversity = CFG_SYS_ANTENNA_SLOW_DIV;
+ if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B)
+ antenna = CFG_SYS_ANTENNA_BOTH;
+ sys_config->antenna_diversity = antenna;
sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */
sys_config->dot11g_auto_detection = 0;
sys_config->enable_cts_to_self = 0;
@@ -9647,11 +10029,11 @@ we need to heavily modify the ieee80211_skb_to_txb.
static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
int pri)
{
- struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
+ struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *)
txb->fragments[0]->data;
int i = 0;
struct tfd_frame *tfd;
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
int tx_id = ipw_get_tx_queue_number(priv, pri);
struct clx2_tx_queue *txq = &priv->txq[tx_id];
#else
@@ -9662,9 +10044,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
u16 remaining_bytes;
int fc;
+ hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
- hdr_len = IEEE80211_3ADDR_LEN;
unicast = !is_multicast_ether_addr(hdr->addr1);
id = ipw_find_station(priv, hdr->addr1);
if (id == IPW_INVALID_STATION) {
@@ -9681,7 +10063,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
case IW_MODE_INFRA:
default:
unicast = !is_multicast_ether_addr(hdr->addr3);
- hdr_len = IEEE80211_3ADDR_LEN;
id = 0;
break;
}
@@ -9759,9 +10140,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
/* No hardware encryption */
tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
-#ifdef CONFIG_IPW_QOS
- ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast);
-#endif /* CONFIG_IPW_QOS */
+#ifdef CONFIG_IPW2200_QOS
+ if (fc & IEEE80211_STYPE_QOS_DATA)
+ ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data));
+#endif /* CONFIG_IPW2200_QOS */
/* payload */
tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
@@ -9841,12 +10223,12 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
static int ipw_net_is_queue_full(struct net_device *dev, int pri)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
int tx_id = ipw_get_tx_queue_number(priv, pri);
struct clx2_tx_queue *txq = &priv->txq[tx_id];
#else
struct clx2_tx_queue *txq = &priv->txq[0];
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
if (ipw_queue_space(&txq->q) < txq->q.high_mark)
return 1;
@@ -9854,6 +10236,88 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri)
return 0;
}
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
+ struct ieee80211_txb *txb)
+{
+ struct ieee80211_rx_stats dummystats;
+ struct ieee80211_hdr *hdr;
+ u8 n;
+ u16 filter = priv->prom_priv->filter;
+ int hdr_only = 0;
+
+ if (filter & IPW_PROM_NO_TX)
+ return;
+
+ memset(&dummystats, 0, sizeof(dummystats));
+
+ /* Filtering of fragment chains is done agains the first fragment */
+ hdr = (void *)txb->fragments[0]->data;
+ if (ieee80211_is_management(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_MGMT)
+ return;
+ if (filter & IPW_PROM_MGMT_HEADER_ONLY)
+ hdr_only = 1;
+ } else if (ieee80211_is_control(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_CTL)
+ return;
+ if (filter & IPW_PROM_CTL_HEADER_ONLY)
+ hdr_only = 1;
+ } else if (ieee80211_is_data(hdr->frame_ctl)) {
+ if (filter & IPW_PROM_NO_DATA)
+ return;
+ if (filter & IPW_PROM_DATA_HEADER_ONLY)
+ hdr_only = 1;
+ }
+
+ for(n=0; n<txb->nr_frags; ++n) {
+ struct sk_buff *src = txb->fragments[n];
+ struct sk_buff *dst;
+ struct ieee80211_radiotap_header *rt_hdr;
+ int len;
+
+ if (hdr_only) {
+ hdr = (void *)src->data;
+ len = ieee80211_get_hdrlen(hdr->frame_ctl);
+ } else
+ len = src->len;
+
+ dst = alloc_skb(
+ len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC);
+ if (!dst) continue;
+
+ rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr));
+
+ rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
+ rt_hdr->it_pad = 0;
+ rt_hdr->it_present = 0; /* after all, it's just an idea */
+ rt_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL);
+
+ *(u16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
+ ieee80211chan2mhz(priv->channel));
+ if (priv->channel > 14) /* 802.11a */
+ *(u16*)skb_put(dst, sizeof(u16)) =
+ cpu_to_le16(IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_5GHZ);
+ else if (priv->ieee->mode == IEEE_B) /* 802.11b */
+ *(u16*)skb_put(dst, sizeof(u16)) =
+ cpu_to_le16(IEEE80211_CHAN_CCK |
+ IEEE80211_CHAN_2GHZ);
+ else /* 802.11g */
+ *(u16*)skb_put(dst, sizeof(u16)) =
+ cpu_to_le16(IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_2GHZ);
+
+ rt_hdr->it_len = dst->len;
+
+ memcpy(skb_put(dst, len), src->data, len);
+
+ if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats))
+ dev_kfree_skb_any(dst);
+ }
+}
+#endif
+
static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
struct net_device *dev, int pri)
{
@@ -9871,6 +10335,11 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
goto fail_unlock;
}
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ if (rtap_iface && netif_running(priv->prom_net_dev))
+ ipw_handle_promiscuous_tx(priv, txb);
+#endif
+
ret = ipw_tx_skb(priv, txb, pri);
if (ret == NETDEV_TX_OK)
__ipw_led_activity_on(priv);
@@ -10169,10 +10638,10 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
INIT_WORK(&priv->merge_networks,
(void (*)(void *))ipw_merge_adhoc_network, priv);
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate,
priv);
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
ipw_irq_tasklet, (unsigned long)priv);
@@ -10318,12 +10787,21 @@ static int ipw_config(struct ipw_priv *priv)
|= CFG_BT_COEXISTENCE_OOB;
}
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
+ priv->sys_config.accept_all_data_frames = 1;
+ priv->sys_config.accept_non_directed_frames = 1;
+ priv->sys_config.accept_all_mgmt_bcpr = 1;
+ priv->sys_config.accept_all_mgmt_frames = 1;
+ }
+#endif
+
if (priv->ieee->iw_mode == IW_MODE_ADHOC)
priv->sys_config.answer_broadcast_ssid_probe = 1;
else
priv->sys_config.answer_broadcast_ssid_probe = 0;
- if (ipw_send_system_config(priv, &priv->sys_config))
+ if (ipw_send_system_config(priv))
goto error;
init_supported_rates(priv, &priv->rates);
@@ -10335,10 +10813,10 @@ static int ipw_config(struct ipw_priv *priv)
if (ipw_send_rts_threshold(priv, priv->rts_threshold))
goto error;
}
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
ipw_qos_activate(priv, NULL);
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
if (ipw_set_random_seed(priv))
goto error;
@@ -10639,6 +11117,7 @@ static int ipw_up(struct ipw_priv *priv)
if (priv->cmdlog == NULL) {
IPW_ERROR("Error allocating %d command log entries.\n",
cmdlog);
+ return -ENOMEM;
} else {
memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
priv->cmdlog_len = cmdlog;
@@ -10860,6 +11339,10 @@ static struct attribute *ipw_sysfs_entries[] = {
&dev_attr_led.attr,
&dev_attr_speed_scan.attr,
&dev_attr_net_stats.attr,
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ &dev_attr_rtap_iface.attr,
+ &dev_attr_rtap_filter.attr,
+#endif
NULL
};
@@ -10868,6 +11351,109 @@ static struct attribute_group ipw_attribute_group = {
.attrs = ipw_sysfs_entries,
};
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+static int ipw_prom_open(struct net_device *dev)
+{
+ struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = prom_priv->priv;
+
+ IPW_DEBUG_INFO("prom dev->open\n");
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+ priv->sys_config.accept_all_data_frames = 1;
+ priv->sys_config.accept_non_directed_frames = 1;
+ priv->sys_config.accept_all_mgmt_bcpr = 1;
+ priv->sys_config.accept_all_mgmt_frames = 1;
+
+ ipw_send_system_config(priv);
+ }
+
+ return 0;
+}
+
+static int ipw_prom_stop(struct net_device *dev)
+{
+ struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
+ struct ipw_priv *priv = prom_priv->priv;
+
+ IPW_DEBUG_INFO("prom dev->stop\n");
+
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+ priv->sys_config.accept_all_data_frames = 0;
+ priv->sys_config.accept_non_directed_frames = 0;
+ priv->sys_config.accept_all_mgmt_bcpr = 0;
+ priv->sys_config.accept_all_mgmt_frames = 0;
+
+ ipw_send_system_config(priv);
+ }
+
+ return 0;
+}
+
+static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ IPW_DEBUG_INFO("prom dev->xmit\n");
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+}
+
+static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev)
+{
+ struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
+ return &prom_priv->ieee->stats;
+}
+
+static int ipw_prom_alloc(struct ipw_priv *priv)
+{
+ int rc = 0;
+
+ if (priv->prom_net_dev)
+ return -EPERM;
+
+ priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv));
+ if (priv->prom_net_dev == NULL)
+ return -ENOMEM;
+
+ priv->prom_priv = ieee80211_priv(priv->prom_net_dev);
+ priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev);
+ priv->prom_priv->priv = priv;
+
+ strcpy(priv->prom_net_dev->name, "rtap%d");
+
+ priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ priv->prom_net_dev->open = ipw_prom_open;
+ priv->prom_net_dev->stop = ipw_prom_stop;
+ priv->prom_net_dev->get_stats = ipw_prom_get_stats;
+ priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit;
+
+ priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
+
+ rc = register_netdev(priv->prom_net_dev);
+ if (rc) {
+ free_ieee80211(priv->prom_net_dev);
+ priv->prom_net_dev = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+static void ipw_prom_free(struct ipw_priv *priv)
+{
+ if (!priv->prom_net_dev)
+ return;
+
+ unregister_netdev(priv->prom_net_dev);
+ free_ieee80211(priv->prom_net_dev);
+
+ priv->prom_net_dev = NULL;
+}
+
+#endif
+
+
static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = 0;
@@ -10959,11 +11545,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->ieee->set_security = shim__set_security;
priv->ieee->is_queue_full = ipw_net_is_queue_full;
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_QOS
+ priv->ieee->is_qos_active = ipw_is_qos_active;
priv->ieee->handle_probe_response = ipw_handle_beacon;
priv->ieee->handle_beacon = ipw_handle_probe_response;
priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
priv->ieee->perfect_rssi = -20;
priv->ieee->worst_rssi = -85;
@@ -10997,6 +11584,18 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_remove_sysfs;
}
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ if (rtap_iface) {
+ err = ipw_prom_alloc(priv);
+ if (err) {
+ IPW_ERROR("Failed to register promiscuous network "
+ "device (error %d).\n", err);
+ unregister_netdev(priv->net_dev);
+ goto out_remove_sysfs;
+ }
+ }
+#endif
+
printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg "
"channels, %d 802.11a channels)\n",
priv->ieee->geo.name, priv->ieee->geo.bg_channels,
@@ -11076,6 +11675,10 @@ static void ipw_pci_remove(struct pci_dev *pdev)
priv->error = NULL;
}
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ ipw_prom_free(priv);
+#endif
+
free_irq(pdev->irq, priv);
iounmap(priv->hw_base);
pci_release_regions(pdev);
@@ -11200,7 +11803,12 @@ MODULE_PARM_DESC(debug, "debug output mask");
module_param(channel, int, 0444);
MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
-#ifdef CONFIG_IPW_QOS
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+module_param(rtap_iface, int, 0444);
+MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)");
+#endif
+
+#ifdef CONFIG_IPW2200_QOS
module_param(qos_enable, int, 0444);
MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis");
@@ -11215,7 +11823,7 @@ MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
module_param(burst_duration_OFDM, int, 0444);
MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
-#endif /* CONFIG_IPW_QOS */
+#endif /* CONFIG_IPW2200_QOS */
#ifdef CONFIG_IPW2200_MONITOR
module_param(mode, int, 0444);
@@ -11238,5 +11846,8 @@ MODULE_PARM_DESC(cmdlog,
module_param(roaming, int, 0444);
MODULE_PARM_DESC(roaming, "enable roaming support (default on)");
+module_param(antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)");
+
module_exit(ipw_exit);
module_init(ipw_init);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 4b9804900702..6044c0be2c80 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -789,7 +789,7 @@ struct ipw_sys_config {
u8 bt_coexist_collision_thr;
u8 silence_threshold;
u8 accept_all_mgmt_bcpr;
- u8 accept_all_mgtm_frames;
+ u8 accept_all_mgmt_frames;
u8 pass_noise_stats_to_host;
u8 reserved3;
} __attribute__ ((packed));
@@ -1122,6 +1122,52 @@ struct ipw_fw_error {
u8 payload[0];
} __attribute__ ((packed));
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+
+enum ipw_prom_filter {
+ IPW_PROM_CTL_HEADER_ONLY = (1 << 0),
+ IPW_PROM_MGMT_HEADER_ONLY = (1 << 1),
+ IPW_PROM_DATA_HEADER_ONLY = (1 << 2),
+ IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */
+ IPW_PROM_NO_TX = (1 << 4),
+ IPW_PROM_NO_RX = (1 << 5),
+ IPW_PROM_NO_CTL = (1 << 6),
+ IPW_PROM_NO_MGMT = (1 << 7),
+ IPW_PROM_NO_DATA = (1 << 8),
+};
+
+struct ipw_priv;
+struct ipw_prom_priv {
+ struct ipw_priv *priv;
+ struct ieee80211_device *ieee;
+ enum ipw_prom_filter filter;
+ int tx_packets;
+ int rx_packets;
+};
+#endif
+
+#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS)
+/* Magic struct that slots into the radiotap header -- no reason
+ * to build this manually element by element, we can write it much
+ * more efficiently than we can parse it. ORDER MATTERS HERE
+ *
+ * When sent to us via the simulated Rx interface in sysfs, the entire
+ * structure is provided regardless of any bits unset.
+ */
+struct ipw_rt_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u64 rt_tsf; /* TSF */
+ u8 rt_flags; /* radiotap packet flags */
+ u8 rt_rate; /* rate in 500kb/s */
+ u16 rt_channel; /* channel in mhz */
+ u16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
+ s8 rt_dbmnoise;
+ u8 rt_antenna; /* antenna number */
+ u8 payload[0]; /* payload... */
+} __attribute__ ((packed));
+#endif
+
struct ipw_priv {
/* ieee device used by generic ieee processing code */
struct ieee80211_device *ieee;
@@ -1133,6 +1179,12 @@ struct ipw_priv {
struct pci_dev *pci_dev;
struct net_device *net_dev;
+#ifdef CONFIG_IPW2200_PROMISCUOUS
+ /* Promiscuous mode */
+ struct ipw_prom_priv *prom_priv;
+ struct net_device *prom_net_dev;
+#endif
+
/* pci hardware address support */
void __iomem *hw_base;
unsigned long hw_len;
@@ -1153,11 +1205,9 @@ struct ipw_priv {
u32 config;
u32 capability;
- u8 last_rx_rssi;
- u8 last_noise;
struct average average_missed_beacons;
- struct average average_rssi;
- struct average average_noise;
+ s16 exp_avg_rssi;
+ s16 exp_avg_noise;
u32 port_type;
int rx_bufs_min; /**< minimum number of bufs in Rx queue */
int rx_pend_max; /**< maximum pending buffers for one IRQ */
@@ -1308,6 +1358,29 @@ struct ipw_priv {
/* debug macros */
+/* Debug and printf string expansion helpers for printing bitfields */
+#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
+#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
+#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
+
+#define BITC(x,y) (((x>>y)&1)?'1':'0')
+#define BIT_ARG8(x) \
+BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\
+BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0)
+
+#define BIT_ARG16(x) \
+BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\
+BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\
+BIT_ARG8(x)
+
+#define BIT_ARG32(x) \
+BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\
+BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\
+BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\
+BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
+BIT_ARG16(x)
+
+
#ifdef CONFIG_IPW2200_DEBUG
#define IPW_DEBUG(level, fmt, args...) \
do { if (ipw_debug_level & (level)) \
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 06523e2a8471..8a31b591a901 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -201,41 +201,12 @@ static struct {
/* Data types */
/********************************************************************/
-/* Used in Event handling.
- * We avoid nested structures as they break on ARM -- Moustafa */
-struct hermes_tx_descriptor_802_11 {
- /* hermes_tx_descriptor */
- __le16 status;
- __le16 reserved1;
- __le16 reserved2;
- __le32 sw_support;
- u8 retry_count;
- u8 tx_rate;
- __le16 tx_control;
-
- /* ieee80211_hdr */
+/* Beginning of the Tx descriptor, used in TxExc handling */
+struct hermes_txexc_data {
+ struct hermes_tx_descriptor desc;
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
-
- __le16 data_len;
-
- /* ethhdr */
- u8 h_dest[ETH_ALEN]; /* destination eth addr */
- u8 h_source[ETH_ALEN]; /* source ether addr */
- __be16 h_proto; /* packet type ID field */
-
- /* p8022_hdr */
- u8 dsap;
- u8 ssap;
- u8 ctrl;
- u8 oui[3];
-
- __be16 ethertype;
} __attribute__ ((packed));
/* Rx frame header except compatibility 802.3 header */
@@ -450,53 +421,39 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
hermes_t *hw = &priv->hw;
int err = 0;
u16 txfid = priv->txfid;
- char *p;
struct ethhdr *eh;
- int len, data_len, data_off;
+ int data_off;
struct hermes_tx_descriptor desc;
unsigned long flags;
- TRACE_ENTER(dev->name);
-
if (! netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n",
dev->name);
- TRACE_EXIT(dev->name);
- return 1;
+ return NETDEV_TX_BUSY;
}
if (netif_queue_stopped(dev)) {
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
dev->name);
- TRACE_EXIT(dev->name);
- return 1;
+ return NETDEV_TX_BUSY;
}
if (orinoco_lock(priv, &flags) != 0) {
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
dev->name);
- TRACE_EXIT(dev->name);
- return 1;
+ return NETDEV_TX_BUSY;
}
if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
- stats->tx_errors++;
- orinoco_unlock(priv, &flags);
- dev_kfree_skb(skb);
- TRACE_EXIT(dev->name);
- return 0;
+ goto drop;
}
- /* Length of the packet body */
- /* FIXME: what if the skb is smaller than this? */
- len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
- skb = skb_padto(skb, len);
- if (skb == NULL)
- goto fail;
- len -= ETH_HLEN;
+ /* Check packet length */
+ if (skb->len < ETH_HLEN)
+ goto drop;
eh = (struct ethhdr *)skb->data;
@@ -507,8 +464,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit())
printk(KERN_ERR "%s: Error %d writing Tx descriptor "
"to BAP\n", dev->name, err);
- stats->tx_errors++;
- goto fail;
+ goto busy;
}
/* Clear the 802.11 header and data length fields - some
@@ -519,50 +475,38 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
/* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
- struct header_struct hdr;
- data_len = len;
- data_off = HERMES_802_3_OFFSET + sizeof(hdr);
- p = skb->data + ETH_HLEN;
-
- /* 802.3 header */
- memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
- memcpy(hdr.src, eh->h_source, ETH_ALEN);
- hdr.len = htons(data_len + ENCAPS_OVERHEAD);
-
- /* 802.2 header */
- memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr));
-
- hdr.ethertype = eh->h_proto;
- err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
- txfid, HERMES_802_3_OFFSET);
+ struct header_struct {
+ struct ethhdr eth; /* 802.3 header */
+ u8 encap[6]; /* 802.2 header */
+ } __attribute__ ((packed)) hdr;
+
+ /* Strip destination and source from the data */
+ skb_pull(skb, 2 * ETH_ALEN);
+ data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr);
+
+ /* And move them to a separate header */
+ memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+ hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
+ memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+
+ err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
+ txfid, HERMES_802_3_OFFSET);
if (err) {
if (net_ratelimit())
printk(KERN_ERR "%s: Error %d writing packet "
"header to BAP\n", dev->name, err);
- stats->tx_errors++;
- goto fail;
+ goto busy;
}
- /* Actual xfer length - allow for padding */
- len = ALIGN(data_len, 2);
- if (len < ETH_ZLEN - ETH_HLEN)
- len = ETH_ZLEN - ETH_HLEN;
} else { /* IEEE 802.3 frame */
- data_len = len + ETH_HLEN;
data_off = HERMES_802_3_OFFSET;
- p = skb->data;
- /* Actual xfer length - round up for odd length packets */
- len = ALIGN(data_len, 2);
- if (len < ETH_ZLEN)
- len = ETH_ZLEN;
}
- err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len,
+ err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
txfid, data_off);
if (err) {
printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
dev->name, err);
- stats->tx_errors++;
- goto fail;
+ goto busy;
}
/* Finally, we actually initiate the send */
@@ -575,25 +519,27 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit())
printk(KERN_ERR "%s: Error %d transmitting packet\n",
dev->name, err);
- stats->tx_errors++;
- goto fail;
+ goto busy;
}
dev->trans_start = jiffies;
- stats->tx_bytes += data_off + data_len;
+ stats->tx_bytes += data_off + skb->len;
+ goto ok;
- orinoco_unlock(priv, &flags);
+ drop:
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ ok:
+ orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
- TRACE_EXIT(dev->name);
-
- return 0;
- fail:
- TRACE_EXIT(dev->name);
-
+ busy:
+ if (err == -EIO)
+ schedule_work(&priv->reset_work);
orinoco_unlock(priv, &flags);
- return err;
+ return NETDEV_TX_BUSY;
}
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
@@ -629,7 +575,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status;
- struct hermes_tx_descriptor_802_11 hdr;
+ struct hermes_txexc_data hdr;
int err = 0;
if (fid == DUMMY_FID)
@@ -637,8 +583,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
/* Read part of the frame header - we need status and addr1 */
err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
- offsetof(struct hermes_tx_descriptor_802_11,
- addr2),
+ sizeof(struct hermes_txexc_data),
fid, 0);
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
@@ -658,7 +603,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
* 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 */
- status = le16_to_cpu(hdr.status);
+ status = le16_to_cpu(hdr.desc.status);
if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
union iwreq_data wrqu;
@@ -812,7 +757,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
if (datalen > IEEE80211_DATA_LEN + 12) {
printk(KERN_DEBUG "%s: oversized monitor frame, "
"data length = %d\n", dev->name, datalen);
- err = -EIO;
stats->rx_length_errors++;
goto update_stats;
}
@@ -821,8 +765,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
if (!skb) {
printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
dev->name);
- err = -ENOMEM;
- goto drop;
+ goto update_stats;
}
/* Copy the 802.11 header to the skb */
@@ -1400,16 +1343,12 @@ int __orinoco_down(struct net_device *dev)
return 0;
}
-int orinoco_reinit_firmware(struct net_device *dev)
+static int orinoco_allocate_fid(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
- err = hermes_init(hw);
- if (err)
- return err;
-
err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
/* Try workaround for old Symbol firmware bug */
@@ -1428,6 +1367,19 @@ int orinoco_reinit_firmware(struct net_device *dev)
return err;
}
+int orinoco_reinit_firmware(struct net_device *dev)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_init(hw);
+ if (!err)
+ err = orinoco_allocate_fid(dev);
+
+ return err;
+}
+
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
@@ -1835,7 +1787,9 @@ static int __orinoco_program_rids(struct net_device *dev)
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
- __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
+
+ /* FIXME: what about netif_tx_lock */
+ __orinoco_set_multicast_list(dev);
return 0;
}
@@ -2274,14 +2228,12 @@ static int orinoco_init(struct net_device *dev)
u16 reclen;
int len;
- TRACE_ENTER(dev->name);
-
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
/* Initialize the firmware */
- err = orinoco_reinit_firmware(dev);
+ err = hermes_init(hw);
if (err != 0) {
printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
dev->name, err);
@@ -2339,6 +2291,13 @@ static int orinoco_init(struct net_device *dev)
printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
+ err = orinoco_allocate_fid(dev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
+ dev->name);
+ goto out;
+ }
+
/* Get allowed channels */
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
&priv->channel_mask);
@@ -2429,7 +2388,6 @@ static int orinoco_init(struct net_device *dev)
printk(KERN_DEBUG "%s: ready\n", dev->name);
out:
- TRACE_EXIT(dev->name);
return err;
}
@@ -2797,8 +2755,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
int numrates;
int i, k;
- TRACE_ENTER(dev->name);
-
rrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -2888,8 +2844,6 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
- TRACE_EXIT(dev->name);
-
return 0;
}
@@ -3071,8 +3025,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
int err = 0;
unsigned long flags;
- TRACE_ENTER(dev->name);
-
if (netif_running(dev)) {
err = orinoco_hw_get_essid(priv, &active, essidbuf);
if (err)
@@ -3087,8 +3039,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
erq->flags = 1;
erq->length = strlen(essidbuf) + 1;
- TRACE_EXIT(dev->name);
-
return 0;
}
@@ -4349,69 +4299,6 @@ static struct ethtool_ops orinoco_ethtool_ops = {
};
/********************************************************************/
-/* Debugging */
-/********************************************************************/
-
-#if 0
-static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
-{
- printk(KERN_DEBUG "RX descriptor:\n");
- printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status);
- printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time);
- printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence);
- printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal);
- printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate);
- printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow);
- printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved);
-
- printk(KERN_DEBUG "IEEE 802.11 header:\n");
- printk(KERN_DEBUG " frame_ctl = 0x%04x\n",
- frame->p80211.frame_ctl);
- printk(KERN_DEBUG " duration_id = 0x%04x\n",
- frame->p80211.duration_id);
- printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p80211.addr1[0], frame->p80211.addr1[1],
- frame->p80211.addr1[2], frame->p80211.addr1[3],
- frame->p80211.addr1[4], frame->p80211.addr1[5]);
- printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p80211.addr2[0], frame->p80211.addr2[1],
- frame->p80211.addr2[2], frame->p80211.addr2[3],
- frame->p80211.addr2[4], frame->p80211.addr2[5]);
- printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p80211.addr3[0], frame->p80211.addr3[1],
- frame->p80211.addr3[2], frame->p80211.addr3[3],
- frame->p80211.addr3[4], frame->p80211.addr3[5]);
- printk(KERN_DEBUG " seq_ctl = 0x%04x\n",
- frame->p80211.seq_ctl);
- printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p80211.addr4[0], frame->p80211.addr4[1],
- frame->p80211.addr4[2], frame->p80211.addr4[3],
- frame->p80211.addr4[4], frame->p80211.addr4[5]);
- printk(KERN_DEBUG " data_len = 0x%04x\n",
- frame->p80211.data_len);
-
- printk(KERN_DEBUG "IEEE 802.3 header:\n");
- printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p8023.h_dest[0], frame->p8023.h_dest[1],
- frame->p8023.h_dest[2], frame->p8023.h_dest[3],
- frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
- printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
- frame->p8023.h_source[0], frame->p8023.h_source[1],
- frame->p8023.h_source[2], frame->p8023.h_source[3],
- frame->p8023.h_source[4], frame->p8023.h_source[5]);
- printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto);
-
- printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
- printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap);
- printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap);
- printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl);
- printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n",
- frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
- printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
-}
-#endif /* 0 */
-
-/********************************************************************/
/* Module initialization */
/********************************************************************/
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index f5d856db92a1..16db3e14b7d2 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,7 +7,7 @@
#ifndef _ORINOCO_H
#define _ORINOCO_H
-#define DRIVER_VERSION "0.15rc3"
+#define DRIVER_VERSION "0.15"
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -30,20 +30,6 @@ struct orinoco_key {
char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed));
-struct header_struct {
- /* 802.3 */
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- __be16 len;
- /* 802.2 */
- u8 dsap;
- u8 ssap;
- u8 ctrl;
- /* SNAP */
- u8 oui[3];
- unsigned short ethertype;
-} __attribute__ ((packed));
-
typedef enum {
FIRMWARE_TYPE_AGERE,
FIRMWARE_TYPE_INTERSIL,
@@ -132,9 +118,6 @@ extern int orinoco_debug;
#define DEBUG(n, args...) do { } while (0)
#endif /* ORINOCO_DEBUG */
-#define TRACE_ENTER(devname) DEBUG(2, "%s: -> %s()\n", devname, __FUNCTION__);
-#define TRACE_EXIT(devname) DEBUG(2, "%s: <- %s()\n", devname, __FUNCTION__);
-
/********************************************************************/
/* Exported prototypes */
/********************************************************************/
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 434f7d7ad841..b2aec4d9fbb1 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -147,14 +147,11 @@ static void orinoco_cs_detach(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
+ if (link->dev_node)
+ unregister_netdev(dev);
+
orinoco_cs_release(link);
- DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
- if (link->dev_node) {
- DEBUG(0, PFX "About to unregister net device %p\n",
- dev);
- unregister_netdev(dev);
- }
free_orinocodev(dev);
} /* orinoco_cs_detach */
@@ -178,13 +175,10 @@ orinoco_cs_config(struct pcmcia_device *link)
int last_fn, last_ret;
u_char buf[64];
config_info_t conf;
- cisinfo_t info;
tuple_t tuple;
cisparse_t parse;
void __iomem *mem;
- CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
-
/*
* This reads the card's CONFIG tuple to find its
* configuration registers.
@@ -234,12 +228,6 @@ orinoco_cs_config(struct pcmcia_device *link)
goto next_entry;
link->conf.ConfigIndex = cfg->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)) {
@@ -355,19 +343,10 @@ orinoco_cs_config(struct pcmcia_device *link)
net_device has been registered */
/* Finally, report what we've done */
- printk(KERN_DEBUG "%s: index 0x%02x: ",
- dev->name, link->conf.ConfigIndex);
- if (link->conf.Vpp)
- printk(", Vpp %d.%d", link->conf.Vpp / 10,
- link->conf.Vpp % 10);
- 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");
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+ "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ link->irq.AssignedIRQ, link->io.BasePort1,
+ link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
@@ -436,7 +415,6 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
struct orinoco_private *priv = netdev_priv(dev);
struct orinoco_pccard *card = priv->card;
int err = 0;
- unsigned long flags;
if (! test_bit(0, &card->hard_reset_in_progress)) {
err = orinoco_reinit_firmware(dev);
@@ -446,7 +424,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
return -EIO;
}
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
netif_device_attach(dev);
priv->hw_unavailable--;
@@ -458,10 +436,10 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
dev->name, err);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
}
- return 0;
+ return err;
}
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index d1a670b35338..74b9d5b2ba9e 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -1,9 +1,8 @@
/* orinoco_nortel.c
- *
+ *
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
* Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
- * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter.
*
* Copyright (C) 2002 Tobias Hoffmann
* (C) 2003 Christoph Jungegger <disdos@traum404.de>
@@ -50,67 +49,62 @@
#include <pcmcia/cisreg.h>
#include "orinoco.h"
+#include "orinoco_pci.h"
#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-/* Nortel specific data */
-struct nortel_pci_card {
- unsigned long iobase1;
- unsigned long iobase2;
-};
-
/*
- * Do a soft reset of the PCI card using the Configuration Option Register
+ * Do a soft reset of the card using the Configuration Option Register
* We need this to get going...
* This is the part of the code that is strongly inspired from wlan-ng
*
* Note bis : Don't try to access HERMES_CMD during the reset phase.
* It just won't work !
*/
-static int nortel_pci_cor_reset(struct orinoco_private *priv)
+static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
{
- struct nortel_pci_card *card = priv->card;
+ struct orinoco_pci_card *card = priv->card;
- /* Assert the reset until the card notice */
- outw_p(8, card->iobase1 + 2);
- inw(card->iobase2 + COR_OFFSET);
- outw_p(0x80, card->iobase2 + COR_OFFSET);
+ /* Assert the reset until the card notices */
+ iowrite16(8, card->bridge_io + 2);
+ ioread16(card->attr_io + COR_OFFSET);
+ iowrite16(0x80, card->attr_io + COR_OFFSET);
mdelay(1);
/* Give time for the card to recover from this hard effort */
- outw_p(0, card->iobase2 + COR_OFFSET);
- outw_p(0, card->iobase2 + COR_OFFSET);
+ iowrite16(0, card->attr_io + COR_OFFSET);
+ iowrite16(0, card->attr_io + COR_OFFSET);
mdelay(1);
- /* set COR as usual */
- outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
- outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ /* Set COR as usual */
+ iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
+ iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1);
- outw_p(0x228, card->iobase1 + 2);
+ iowrite16(0x228, card->bridge_io + 2);
return 0;
}
-static int nortel_pci_hw_init(struct nortel_pci_card *card)
+static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
{
int i;
u32 reg;
- /* setup bridge */
- if (inw(card->iobase1) & 1) {
+ /* Setup bridge */
+ if (ioread16(card->bridge_io) & 1) {
printk(KERN_ERR PFX "brg1 answer1 wrong\n");
return -EBUSY;
}
- outw_p(0x118, card->iobase1 + 2);
- outw_p(0x108, card->iobase1 + 2);
+ iowrite16(0x118, card->bridge_io + 2);
+ iowrite16(0x108, card->bridge_io + 2);
mdelay(30);
- outw_p(0x8, card->iobase1 + 2);
+ iowrite16(0x8, card->bridge_io + 2);
for (i = 0; i < 30; i++) {
mdelay(30);
- if (inw(card->iobase1) & 0x10) {
+ if (ioread16(card->bridge_io) & 0x10) {
break;
}
}
@@ -118,42 +112,42 @@ static int nortel_pci_hw_init(struct nortel_pci_card *card)
printk(KERN_ERR PFX "brg1 timed out\n");
return -EBUSY;
}
- if (inw(card->iobase2 + 0xe0) & 1) {
+ if (ioread16(card->attr_io + COR_OFFSET) & 1) {
printk(KERN_ERR PFX "brg2 answer1 wrong\n");
return -EBUSY;
}
- if (inw(card->iobase2 + 0xe2) & 1) {
+ if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
printk(KERN_ERR PFX "brg2 answer2 wrong\n");
return -EBUSY;
}
- if (inw(card->iobase2 + 0xe4) & 1) {
+ if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
printk(KERN_ERR PFX "brg2 answer3 wrong\n");
return -EBUSY;
}
- /* set the PCMCIA COR-Register */
- outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ /* Set the PCMCIA COR register */
+ iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1);
- reg = inw(card->iobase2 + COR_OFFSET);
+ reg = ioread16(card->attr_io + COR_OFFSET);
if (reg != COR_VALUE) {
printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
reg);
return -EBUSY;
}
- /* set leds */
- outw_p(1, card->iobase1 + 10);
+ /* Set LEDs */
+ iowrite16(1, card->bridge_io + 10);
return 0;
}
-static int nortel_pci_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int orinoco_nortel_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
int err;
struct orinoco_private *priv;
- struct nortel_pci_card *card;
+ struct orinoco_pci_card *card;
struct net_device *dev;
- void __iomem *iomem;
+ void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev);
if (err) {
@@ -162,19 +156,34 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
}
err = pci_request_regions(pdev, DRIVER_NAME);
- if (err != 0) {
+ if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources;
}
- iomem = pci_iomap(pdev, 2, 0);
- if (!iomem) {
- err = -ENOMEM;
- goto fail_map_io;
+ bridge_io = pci_iomap(pdev, 0, 0);
+ if (!bridge_io) {
+ printk(KERN_ERR PFX "Cannot map bridge registers\n");
+ err = -EIO;
+ goto fail_map_bridge;
+ }
+
+ attr_io = pci_iomap(pdev, 1, 0);
+ if (!attr_io) {
+ printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
+ err = -EIO;
+ goto fail_map_attr;
+ }
+
+ hermes_io = pci_iomap(pdev, 2, 0);
+ if (!hermes_io) {
+ printk(KERN_ERR PFX "Cannot map chipset registers\n");
+ err = -EIO;
+ goto fail_map_hermes;
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
+ dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset);
if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
@@ -183,16 +192,12 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
- card->iobase1 = pci_resource_start(pdev, 0);
- card->iobase2 = pci_resource_start(pdev, 1);
- dev->base_addr = pci_resource_start(pdev, 2);
+ card->bridge_io = bridge_io;
+ card->attr_io = attr_io;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING);
-
- printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
- "io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
+ hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
@@ -201,21 +206,19 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
err = -EBUSY;
goto fail_irq;
}
- dev->irq = pdev->irq;
- err = nortel_pci_hw_init(card);
+ err = orinoco_nortel_hw_init(card);
if (err) {
printk(KERN_ERR PFX "Hardware initialization failed\n");
goto fail;
}
- err = nortel_pci_cor_reset(priv);
+ err = orinoco_nortel_cor_reset(priv);
if (err) {
printk(KERN_ERR PFX "Initial reset failed\n");
goto fail;
}
-
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register network device\n");
@@ -223,6 +226,8 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
}
pci_set_drvdata(pdev, dev);
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+ pci_name(pdev));
return 0;
@@ -234,9 +239,15 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
free_orinocodev(dev);
fail_alloc:
- pci_iounmap(pdev, iomem);
+ pci_iounmap(pdev, hermes_io);
- fail_map_io:
+ fail_map_hermes:
+ pci_iounmap(pdev, attr_io);
+
+ fail_map_attr:
+ pci_iounmap(pdev, bridge_io);
+
+ fail_map_bridge:
pci_release_regions(pdev);
fail_resources:
@@ -245,26 +256,27 @@ static int nortel_pci_init_one(struct pci_dev *pdev,
return err;
}
-static void __devexit nortel_pci_remove_one(struct pci_dev *pdev)
+static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
- struct nortel_pci_card *card = priv->card;
+ struct orinoco_pci_card *card = priv->card;
- /* clear leds */
- outw_p(0, card->iobase1 + 10);
+ /* Clear LEDs */
+ iowrite16(0, card->bridge_io + 10);
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(pdev->irq, dev);
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase);
+ pci_iounmap(pdev, card->attr_io);
+ pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
-
-static struct pci_device_id nortel_pci_id_table[] = {
+static struct pci_device_id orinoco_nortel_id_table[] = {
/* Nortel emobility PCI */
{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
/* Symbol LA-4123 PCI */
@@ -272,13 +284,15 @@ static struct pci_device_id nortel_pci_id_table[] = {
{0,},
};
-MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
+MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
-static struct pci_driver nortel_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = nortel_pci_id_table,
- .probe = nortel_pci_init_one,
- .remove = __devexit_p(nortel_pci_remove_one),
+static struct pci_driver orinoco_nortel_driver = {
+ .name = DRIVER_NAME,
+ .id_table = orinoco_nortel_id_table,
+ .probe = orinoco_nortel_init_one,
+ .remove = __devexit_p(orinoco_nortel_remove_one),
+ .suspend = orinoco_pci_suspend,
+ .resume = orinoco_pci_resume,
};
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@@ -288,20 +302,19 @@ MODULE_DESCRIPTION
("Driver for wireless LAN cards using the Nortel PCI bridge");
MODULE_LICENSE("Dual MPL/GPL");
-static int __init nortel_pci_init(void)
+static int __init orinoco_nortel_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&nortel_pci_driver);
+ return pci_module_init(&orinoco_nortel_driver);
}
-static void __exit nortel_pci_exit(void)
+static void __exit orinoco_nortel_exit(void)
{
- pci_unregister_driver(&nortel_pci_driver);
- ssleep(1);
+ pci_unregister_driver(&orinoco_nortel_driver);
}
-module_init(nortel_pci_init);
-module_exit(nortel_pci_exit);
+module_init(orinoco_nortel_init);
+module_exit(orinoco_nortel_exit);
/*
* Local variables:
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 5362c214fc8e..1c105f40f8d5 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -1,11 +1,11 @@
/* orinoco_pci.c
*
- * Driver for Prism II devices that have a direct PCI interface
- * (i.e., not in a Pcmcia or PLX bridge)
- *
- * Specifically here we're talking about the Linksys WMP11
+ * Driver for Prism 2.5/3 devices that have a direct PCI interface
+ * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
+ * The card contains only one PCI region, which contains all the usual
+ * hermes registers, as well as the COR register.
*
- * Current maintainers (as of 29 September 2003) are:
+ * Current maintainers are:
* Pavel Roskin <proski AT gnu.org>
* and David Gibson <hermes AT gibson.dropbear.id.au>
*
@@ -41,54 +41,6 @@
* under either the MPL or the GPL.
*/
-/*
- * Theory of operation...
- * -------------------
- * Maybe you had a look in orinoco_plx. Well, this is totally different...
- *
- * The card contains only one PCI region, which contains all the usual
- * hermes registers.
- *
- * The driver will memory map this region in normal memory. Because
- * the hermes registers are mapped in normal memory and not in ISA I/O
- * post space, we can't use the usual inw/outw macros and we need to
- * use readw/writew.
- * This slight difference force us to compile our own version of
- * hermes.c with the register access macro changed. That's a bit
- * hackish but works fine.
- *
- * Note that the PCI region is pretty big (4K). That's much more than
- * the usual set of hermes register (0x0 -> 0x3E). I've got a strong
- * suspicion that the whole memory space of the adapter is in fact in
- * this region. Accessing directly the adapter memory instead of going
- * through the usual register would speed up significantely the
- * operations...
- *
- * Finally, the card looks like this :
------------------------
- Bus 0, device 14, function 0:
- Network controller: PCI device 1260:3873 (Harris Semiconductor) (rev 1).
- IRQ 11.
- Master Capable. Latency=248.
- Prefetchable 32 bit memory at 0xffbcc000 [0xffbccfff].
------------------------
-00:0e.0 Network controller: Harris Semiconductor: Unknown device 3873 (rev 01)
- Subsystem: Unknown device 1737:3874
- Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
- Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- Latency: 248 set, cache line size 08
- Interrupt: pin A routed to IRQ 11
- Region 0: Memory at ffbcc000 (32-bit, prefetchable) [size=4K]
- Capabilities: [dc] Power Management version 2
- Flags: PMEClk- AuxPwr- DSI- D1+ D2+ PME+
- Status: D0 PME-Enable- DSel=0 DScale=0 PME-
------------------------
- *
- * That's all..
- *
- * Jean II
- */
-
#define DRIVER_NAME "orinoco_pci"
#define PFX DRIVER_NAME ": "
@@ -100,12 +52,14 @@
#include <linux/pci.h>
#include "orinoco.h"
+#include "orinoco_pci.h"
-/* All the magic there is from wlan-ng */
-/* Magic offset of the reset register of the PCI card */
+/* Offset of the COR register of the PCI card */
#define HERMES_PCI_COR (0x26)
-/* Magic bitmask to reset the card */
+
+/* Bitmask to reset the card */
#define HERMES_PCI_COR_MASK (0x0080)
+
/* Magic timeouts for doing the reset.
* Those times are straight from wlan-ng, and it is claimed that they
* are necessary. Alan will kill me. Take your time and grab a coffee. */
@@ -113,13 +67,8 @@
#define HERMES_PCI_COR_OFFT (500) /* ms */
#define HERMES_PCI_COR_BUSYT (500) /* ms */
-/* Orinoco PCI specific data */
-struct orinoco_pci_card {
- void __iomem *pci_ioaddr;
-};
-
/*
- * Do a soft reset of the PCI card using the Configuration Option Register
+ * Do a soft reset of the card using the Configuration Option Register
* We need this to get going...
* This is the part of the code that is strongly inspired from wlan-ng
*
@@ -131,14 +80,13 @@ struct orinoco_pci_card {
* Note bis : Don't try to access HERMES_CMD during the reset phase.
* It just won't work !
*/
-static int
-orinoco_pci_cor_reset(struct orinoco_private *priv)
+static int orinoco_pci_cor_reset(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
- unsigned long timeout;
- u16 reg;
+ unsigned long timeout;
+ u16 reg;
- /* Assert the reset until the card notice */
+ /* Assert the reset until the card notices */
hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
mdelay(HERMES_PCI_COR_ONT);
@@ -163,19 +111,14 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
return 0;
}
-/*
- * Initialise a card. Mostly similar to PLX code.
- */
static int orinoco_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int err = 0;
- unsigned long pci_iorange;
- u16 __iomem *pci_ioaddr = NULL;
- unsigned long pci_iolen;
- struct orinoco_private *priv = NULL;
+ int err;
+ struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev = NULL;
+ struct net_device *dev;
+ void __iomem *hermes_io;
err = pci_enable_device(pdev);
if (err) {
@@ -184,39 +127,32 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
err = pci_request_regions(pdev, DRIVER_NAME);
- if (err != 0) {
+ if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources;
}
- /* Resource 0 is mapped to the hermes registers */
- pci_iorange = pci_resource_start(pdev, 0);
- pci_iolen = pci_resource_len(pdev, 0);
- pci_ioaddr = ioremap(pci_iorange, pci_iolen);
- if (!pci_iorange) {
- printk(KERN_ERR PFX "Cannot remap hardware registers\n");
- goto fail_map;
+ hermes_io = pci_iomap(pdev, 0, 0);
+ if (!hermes_io) {
+ printk(KERN_ERR PFX "Cannot remap chipset registers\n");
+ err = -EIO;
+ goto fail_map_hermes;
}
/* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset);
- if (! dev) {
+ if (!dev) {
+ printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
priv = netdev_priv(dev);
card = priv->card;
- card->pci_ioaddr = pci_ioaddr;
- dev->mem_start = pci_iorange;
- dev->mem_end = pci_iorange + pci_iolen - 1;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- hermes_struct_init(&priv->hw, pci_ioaddr, HERMES_32BIT_REGSPACING);
-
- printk(KERN_DEBUG PFX "Detected device %s, mem:0x%lx-0x%lx, irq %d\n",
- pci_name(pdev), dev->mem_start, dev->mem_end, pdev->irq);
+ hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
@@ -225,9 +161,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
err = -EBUSY;
goto fail_irq;
}
- dev->irq = pdev->irq;
- /* Perform a COR reset to start the card */
err = orinoco_pci_cor_reset(priv);
if (err) {
printk(KERN_ERR PFX "Initial reset failed\n");
@@ -236,11 +170,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Failed to register net device\n");
+ printk(KERN_ERR PFX "Cannot register network device\n");
goto fail;
}
pci_set_drvdata(pdev, dev);
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+ pci_name(pdev));
return 0;
@@ -252,9 +188,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
free_orinocodev(dev);
fail_alloc:
- iounmap(pci_ioaddr);
+ pci_iounmap(pdev, hermes_io);
- fail_map:
+ fail_map_hermes:
pci_release_regions(pdev);
fail_resources:
@@ -267,87 +203,17 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
- struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(pdev->irq, dev);
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
- iounmap(card->pci_ioaddr);
+ pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
-static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n",
- dev->name);
- return err;
- }
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
-
- pci_save_state(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-static int orinoco_pci_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
-
- pci_set_power_state(pdev, 0);
- pci_restore_state(pdev);
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
- dev->name, err);
- return err;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-
- priv->hw_unavailable--;
-
- if (priv->open && (! priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static struct pci_device_id orinoco_pci_pci_id_table[] = {
+static struct pci_device_id orinoco_pci_id_table[] = {
/* Intersil Prism 3 */
{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
/* Intersil Prism 2.5 */
@@ -357,11 +223,11 @@ static struct pci_device_id orinoco_pci_pci_id_table[] = {
{0,},
};
-MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table);
+MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
static struct pci_driver orinoco_pci_driver = {
.name = DRIVER_NAME,
- .id_table = orinoco_pci_pci_id_table,
+ .id_table = orinoco_pci_id_table,
.probe = orinoco_pci_init_one,
.remove = __devexit_p(orinoco_pci_remove_one),
.suspend = orinoco_pci_suspend,
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h
new file mode 100644
index 000000000000..7eb1e08113e0
--- /dev/null
+++ b/drivers/net/wireless/orinoco_pci.h
@@ -0,0 +1,104 @@
+/* orinoco_pci.h
+ *
+ * Common code for all Orinoco drivers for PCI devices, including
+ * both native PCI and PCMCIA-to-PCI bridges.
+ *
+ * Copyright (C) 2005, Pavel Roskin.
+ * See orinoco.c for license.
+ */
+
+#ifndef _ORINOCO_PCI_H
+#define _ORINOCO_PCI_H
+
+#include <linux/netdevice.h>
+
+/* Driver specific data */
+struct orinoco_pci_card {
+ void __iomem *bridge_io;
+ void __iomem *attr_io;
+};
+
+#ifdef CONFIG_PM
+static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ err = orinoco_lock(priv, &flags);
+ if (err) {
+ printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
+ dev->name);
+ return err;
+ }
+
+ err = __orinoco_down(dev);
+ if (err)
+ printk(KERN_WARNING "%s: error %d bringing interface down "
+ "for suspend\n", dev->name, err);
+
+ netif_device_detach(dev);
+
+ priv->hw_unavailable++;
+
+ orinoco_unlock(priv, &flags);
+
+ free_irq(pdev->irq, dev);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int orinoco_pci_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ pci_set_power_state(pdev, 0);
+ pci_enable_device(pdev);
+ pci_restore_state(pdev);
+
+ err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ dev->name, dev);
+ if (err) {
+ printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
+ dev->name);
+ pci_disable_device(pdev);
+ return -EBUSY;
+ }
+
+ err = orinoco_reinit_firmware(dev);
+ if (err) {
+ printk(KERN_ERR "%s: error %d re-initializing firmware "
+ "on resume\n", dev->name, err);
+ return err;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ netif_device_attach(dev);
+
+ priv->hw_unavailable--;
+
+ if (priv->open && (! priv->hw_unavailable)) {
+ err = __orinoco_up(dev);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card on resume\n",
+ dev->name, err);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+#else
+#define orinoco_pci_suspend NULL
+#define orinoco_pci_resume NULL
+#endif
+
+#endif /* _ORINOCO_PCI_H */
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 210e73776545..84f696c77551 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -3,7 +3,7 @@
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a PLX9052.
*
- * Current maintainers (as of 29 September 2003) are:
+ * Current maintainers are:
* Pavel Roskin <proski AT gnu.org>
* and David Gibson <hermes AT gibson.dropbear.id.au>
*
@@ -30,38 +30,18 @@
* 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 MPL or the GPL.
-
- * Caution: this is experimental and probably buggy. For success and
- * failure reports for different cards and adaptors, see
- * orinoco_plx_pci_id_table near the end of the file. If you have a
- * card we don't have the PCI id for, and looks like it should work,
- * drop me mail with the id and "it works"/"it doesn't work".
- *
- * Note: if everything gets detected fine but it doesn't actually send
- * or receive packets, your first port of call should probably be to
- * try newer firmware in the card. Especially if you're doing Ad-Hoc
- * modes.
- *
- * The actual driving is done by orinoco.c, this is just resource
- * allocation stuff. The explanation below is courtesy of Ryan Niemi
- * on the linux-wlan-ng list at
- * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html
*
- * The PLX9052-based cards (WL11000 and several others) are a
- * different beast than the usual PCMCIA-based PRISM2 configuration
- * expected by wlan-ng. Here's the general details on how the WL11000
- * PCI adapter works:
+ * Here's the general details on how the PLX9052 adapter works:
*
* - Two PCI I/O address spaces, one 0x80 long which contains the
* PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
* slot I/O address space.
*
- * - One PCI memory address space, mapped to the PCMCIA memory space
+ * - One PCI memory address space, mapped to the PCMCIA attribute space
* (containing the CIS).
*
- * After identifying the I/O and memory space, you can read through
- * the memory space to confirm the CIS's device ID or manufacturer ID
- * to make sure it's the expected card. qKeep in mind that the PCMCIA
+ * Using the later, you can read through the CIS data to make sure the
+ * card is compatible with the driver. Keep in mind that the PCMCIA
* spec specifies the CIS as the lower 8 bits of each word read from
* the CIS, so to read the bytes of the CIS, read every other byte
* (0,2,4,...). Passing that test, you need to enable the I/O address
@@ -71,7 +51,7 @@
* within the PCI memory space. Write 0x41 to the COR register to
* enable I/O mode and to select level triggered interrupts. To
* confirm you actually succeeded, read the COR register back and make
- * sure it actually got set to 0x41, incase you have an unexpected
+ * sure it actually got set to 0x41, in case you have an unexpected
* card inserted.
*
* Following that, you can treat the second PCI I/O address space (the
@@ -101,16 +81,6 @@
* that, I've hot-swapped a number of times during debugging and
* driver development for various reasons (stuck WAIT# line after the
* radio card's firmware locks up).
- *
- * Hope this is enough info for someone to add PLX9052 support to the
- * wlan-ng card. In the case of the WL11000, the PCI ID's are
- * 0x1639/0x0200, with matching subsystem ID's. Other PLX9052-based
- * manufacturers other than Eumitcom (or on cards other than the
- * WL11000) may have different PCI ID's.
- *
- * If anyone needs any more specific info, let me know. I haven't had
- * time to implement support myself yet, and with the way things are
- * going, might not have time for a while..
*/
#define DRIVER_NAME "orinoco_plx"
@@ -125,6 +95,7 @@
#include <pcmcia/cisreg.h>
#include "orinoco.h"
+#include "orinoco_pci.h"
#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
@@ -134,30 +105,20 @@
#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */
-static const u8 cis_magic[] = {
- 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
-};
-
-/* Orinoco PLX specific data */
-struct orinoco_plx_card {
- void __iomem *attr_mem;
-};
-
/*
* Do a soft reset of the card using the Configuration Option Register
*/
static int orinoco_plx_cor_reset(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
- struct orinoco_plx_card *card = priv->card;
- u8 __iomem *attr_mem = card->attr_mem;
+ struct orinoco_pci_card *card = priv->card;
unsigned long timeout;
u16 reg;
- writeb(COR_VALUE | COR_RESET, attr_mem + COR_OFFSET);
+ iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
mdelay(1);
- writeb(COR_VALUE, attr_mem + COR_OFFSET);
+ iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
@@ -168,7 +129,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
reg = hermes_read_regn(hw, CMD);
}
- /* Did we timeout ? */
+ /* Still busy? */
if (reg & HERMES_CMD_BUSY) {
printk(KERN_ERR PFX "Busy timeout\n");
return -ETIMEDOUT;
@@ -177,20 +138,55 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
return 0;
}
+static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
+{
+ int i;
+ u32 csr_reg;
+ static const u8 cis_magic[] = {
+ 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
+ };
+
+ printk(KERN_DEBUG PFX "CIS: ");
+ for (i = 0; i < 16; i++) {
+ printk("%02X:", ioread8(card->attr_io + (i << 1)));
+ }
+ printk("\n");
+
+ /* Verify whether a supported PC card is present */
+ /* FIXME: we probably need to be smarted about this */
+ for (i = 0; i < sizeof(cis_magic); i++) {
+ if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
+ printk(KERN_ERR PFX "The CIS value of Prism2 PC "
+ "card is unexpected\n");
+ return -ENODEV;
+ }
+ }
+
+ /* bjoern: We need to tell the card to enable interrupts, in
+ case the serial eprom didn't do this already. See the
+ PLX9052 data book, p8-1 and 8-24 for reference. */
+ csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
+ if (!(csr_reg & PLX_INTCSR_INTEN)) {
+ csr_reg |= PLX_INTCSR_INTEN;
+ iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
+ csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
+ if (!(csr_reg & PLX_INTCSR_INTEN)) {
+ printk(KERN_ERR PFX "Cannot enable interrupts\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
static int orinoco_plx_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int err = 0;
- u8 __iomem *attr_mem = NULL;
- u32 csr_reg, plx_addr;
- struct orinoco_private *priv = NULL;
- struct orinoco_plx_card *card;
- unsigned long pccard_ioaddr = 0;
- unsigned long pccard_iolen = 0;
- struct net_device *dev = NULL;
- void __iomem *mem;
- int i;
+ int err;
+ struct orinoco_private *priv;
+ struct orinoco_pci_card *card;
+ struct net_device *dev;
+ void __iomem *hermes_io, *attr_io, *bridge_io;
err = pci_enable_device(pdev);
if (err) {
@@ -199,30 +195,30 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
err = pci_request_regions(pdev, DRIVER_NAME);
- if (err != 0) {
+ if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources;
}
- /* Resource 1 is mapped to PLX-specific registers */
- plx_addr = pci_resource_start(pdev, 1);
+ bridge_io = pci_iomap(pdev, 1, 0);
+ if (!bridge_io) {
+ printk(KERN_ERR PFX "Cannot map bridge registers\n");
+ err = -EIO;
+ goto fail_map_bridge;
+ }
- /* Resource 2 is mapped to the PCMCIA attribute memory */
- attr_mem = ioremap(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
- if (!attr_mem) {
- printk(KERN_ERR PFX "Cannot remap PCMCIA space\n");
+ attr_io = pci_iomap(pdev, 2, 0);
+ if (!attr_io) {
+ printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
+ err = -EIO;
goto fail_map_attr;
}
- /* Resource 3 is mapped to the PCMCIA I/O address space */
- pccard_ioaddr = pci_resource_start(pdev, 3);
- pccard_iolen = pci_resource_len(pdev, 3);
-
- mem = pci_iomap(pdev, 3, 0);
- if (!mem) {
- err = -ENOMEM;
- goto fail_map_io;
+ hermes_io = pci_iomap(pdev, 3, 0);
+ if (!hermes_io) {
+ printk(KERN_ERR PFX "Cannot map chipset registers\n");
+ err = -EIO;
+ goto fail_map_hermes;
}
/* Allocate network device */
@@ -235,16 +231,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
- card->attr_mem = attr_mem;
- dev->base_addr = pccard_ioaddr;
+ card->bridge_io = bridge_io;
+ card->attr_io = attr_io;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING);
-
- printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 PLX device "
- "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
- pccard_ioaddr);
+ hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
@@ -253,20 +245,11 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
err = -EBUSY;
goto fail_irq;
}
- dev->irq = pdev->irq;
- /* bjoern: We need to tell the card to enable interrupts, in
- case the serial eprom didn't do this already. See the
- PLX9052 data book, p8-1 and 8-24 for reference. */
- csr_reg = inl(plx_addr + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- csr_reg |= PLX_INTCSR_INTEN;
- outl(csr_reg, plx_addr + PLX_INTCSR);
- csr_reg = inl(plx_addr + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- printk(KERN_ERR PFX "Cannot enable interrupts\n");
- goto fail;
- }
+ err = orinoco_plx_hw_init(card);
+ if (err) {
+ printk(KERN_ERR PFX "Hardware initialization failed\n");
+ goto fail;
}
err = orinoco_plx_cor_reset(priv);
@@ -275,23 +258,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail;
}
- printk(KERN_DEBUG PFX "CIS: ");
- for (i = 0; i < 16; i++) {
- printk("%02X:", readb(attr_mem + 2*i));
- }
- printk("\n");
-
- /* Verify whether a supported PC card is present */
- /* FIXME: we probably need to be smarted about this */
- for (i = 0; i < sizeof(cis_magic); i++) {
- if (cis_magic[i] != readb(attr_mem +2*i)) {
- printk(KERN_ERR PFX "The CIS value of Prism2 PC "
- "card is unexpected\n");
- err = -EIO;
- goto fail;
- }
- }
-
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register network device\n");
@@ -299,6 +265,8 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
pci_set_drvdata(pdev, dev);
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+ pci_name(pdev));
return 0;
@@ -310,12 +278,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
free_orinocodev(dev);
fail_alloc:
- pci_iounmap(pdev, mem);
+ pci_iounmap(pdev, hermes_io);
- fail_map_io:
- iounmap(attr_mem);
+ fail_map_hermes:
+ pci_iounmap(pdev, attr_io);
fail_map_attr:
+ pci_iounmap(pdev, bridge_io);
+
+ fail_map_bridge:
pci_release_regions(pdev);
fail_resources:
@@ -328,23 +299,20 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = netdev_priv(dev);
- struct orinoco_plx_card *card = priv->card;
- u8 __iomem *attr_mem = card->attr_mem;
-
- BUG_ON(! dev);
+ struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(pdev->irq, dev);
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase);
- iounmap(attr_mem);
+ pci_iounmap(pdev, card->attr_io);
+ pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
-
-static struct pci_device_id orinoco_plx_pci_id_table[] = {
+static struct pci_device_id orinoco_plx_id_table[] = {
{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */
@@ -362,13 +330,15 @@ static struct pci_device_id orinoco_plx_pci_id_table[] = {
{0,},
};
-MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
+MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
static struct pci_driver orinoco_plx_driver = {
.name = DRIVER_NAME,
- .id_table = orinoco_plx_pci_id_table,
+ .id_table = orinoco_plx_id_table,
.probe = orinoco_plx_init_one,
.remove = __devexit_p(orinoco_plx_remove_one),
+ .suspend = orinoco_pci_suspend,
+ .resume = orinoco_pci_resume,
};
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@@ -388,7 +358,6 @@ static int __init orinoco_plx_init(void)
static void __exit orinoco_plx_exit(void)
{
pci_unregister_driver(&orinoco_plx_driver);
- ssleep(1);
}
module_init(orinoco_plx_init);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 5e68b7026186..d2b4decb7a7d 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -1,5 +1,5 @@
/* orinoco_tmd.c
- *
+ *
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a TMD7160.
*
@@ -26,25 +26,13 @@
* 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 MPL or the GPL.
-
- * Caution: this is experimental and probably buggy. For success and
- * failure reports for different cards and adaptors, see
- * orinoco_tmd_pci_id_table near the end of the file. If you have a
- * card we don't have the PCI id for, and looks like it should work,
- * drop me mail with the id and "it works"/"it doesn't work".
- *
- * Note: if everything gets detected fine but it doesn't actually send
- * or receive packets, your first port of call should probably be to
- * try newer firmware in the card. Especially if you're doing Ad-Hoc
- * modes
*
* The actual driving is done by orinoco.c, this is just resource
* allocation stuff.
*
* This driver is modeled after the orinoco_plx driver. The main
- * difference is that the TMD chip has only IO port ranges and no
- * memory space, i.e. no access to the CIS. Compared to the PLX chip,
- * the io range functionalities are exchanged.
+ * difference is that the TMD chip has only IO port ranges and doesn't
+ * provide access to the PCMCIA attribute space.
*
* Pheecom sells cards with the TMD chip as "ASIC version"
*/
@@ -61,32 +49,26 @@
#include <pcmcia/cisreg.h>
#include "orinoco.h"
+#include "orinoco_pci.h"
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
#define COR_RESET (0x80) /* reset bit in the COR register */
#define TMD_RESET_TIME (500) /* milliseconds */
-/* Orinoco TMD specific data */
-struct orinoco_tmd_card {
- u32 tmd_io;
-};
-
-
/*
* Do a soft reset of the card using the Configuration Option Register
*/
static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
{
hermes_t *hw = &priv->hw;
- struct orinoco_tmd_card *card = priv->card;
- u32 addr = card->tmd_io;
+ struct orinoco_pci_card *card = priv->card;
unsigned long timeout;
u16 reg;
- outb(COR_VALUE | COR_RESET, addr);
+ iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
mdelay(1);
- outb(COR_VALUE, addr);
+ iowrite8(COR_VALUE, card->bridge_io);
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
@@ -97,7 +79,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
reg = hermes_read_regn(hw, CMD);
}
- /* Did we timeout ? */
+ /* Still busy? */
if (reg & HERMES_CMD_BUSY) {
printk(KERN_ERR PFX "Busy timeout\n");
return -ETIMEDOUT;
@@ -110,11 +92,11 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
static int orinoco_tmd_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int err = 0;
- struct orinoco_private *priv = NULL;
- struct orinoco_tmd_card *card;
- struct net_device *dev = NULL;
- void __iomem *mem;
+ int err;
+ struct orinoco_private *priv;
+ struct orinoco_pci_card *card;
+ struct net_device *dev;
+ void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev);
if (err) {
@@ -123,20 +105,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
err = pci_request_regions(pdev, DRIVER_NAME);
- if (err != 0) {
+ if (err) {
printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
goto fail_resources;
}
- mem = pci_iomap(pdev, 2, 0);
- if (! mem) {
- err = -ENOMEM;
- goto fail_iomap;
+ bridge_io = pci_iomap(pdev, 1, 0);
+ if (!bridge_io) {
+ printk(KERN_ERR PFX "Cannot map bridge registers\n");
+ err = -EIO;
+ goto fail_map_bridge;
+ }
+
+ hermes_io = pci_iomap(pdev, 2, 0);
+ if (!hermes_io) {
+ printk(KERN_ERR PFX "Cannot map chipset registers\n");
+ err = -EIO;
+ goto fail_map_hermes;
}
/* Allocate network device */
dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset);
- if (! dev) {
+ if (!dev) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
@@ -144,16 +134,11 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
- card->tmd_io = pci_resource_start(pdev, 1);
- dev->base_addr = pci_resource_start(pdev, 2);
+ card->bridge_io = bridge_io;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- hermes_struct_init(&priv->hw, mem, HERMES_16BIT_REGSPACING);
-
- printk(KERN_DEBUG PFX "Detected Orinoco/Prism2 TMD device "
- "at %s irq:%d, io addr:0x%lx\n", pci_name(pdev), pdev->irq,
- dev->base_addr);
+ hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
@@ -162,7 +147,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
err = -EBUSY;
goto fail_irq;
}
- dev->irq = pdev->irq;
err = orinoco_tmd_cor_reset(priv);
if (err) {
@@ -177,6 +161,8 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
pci_set_drvdata(pdev, dev);
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+ pci_name(pdev));
return 0;
@@ -188,9 +174,12 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
free_orinocodev(dev);
fail_alloc:
- pci_iounmap(pdev, mem);
+ pci_iounmap(pdev, hermes_io);
+
+ fail_map_hermes:
+ pci_iounmap(pdev, bridge_io);
- fail_iomap:
+ fail_map_bridge:
pci_release_regions(pdev);
fail_resources:
@@ -203,31 +192,32 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = dev->priv;
-
- BUG_ON(! dev);
+ struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(pdev->irq, dev);
pci_set_drvdata(pdev, NULL);
free_orinocodev(dev);
pci_iounmap(pdev, priv->hw.iobase);
+ pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
-
-static struct pci_device_id orinoco_tmd_pci_id_table[] = {
+static struct pci_device_id orinoco_tmd_id_table[] = {
{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
{0,},
};
-MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table);
+MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
static struct pci_driver orinoco_tmd_driver = {
.name = DRIVER_NAME,
- .id_table = orinoco_tmd_pci_id_table,
+ .id_table = orinoco_tmd_id_table,
.probe = orinoco_tmd_init_one,
.remove = __devexit_p(orinoco_tmd_remove_one),
+ .suspend = orinoco_pci_suspend,
+ .resume = orinoco_pci_resume,
};
static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
@@ -245,7 +235,6 @@ static int __init orinoco_tmd_init(void)
static void __exit orinoco_tmd_exit(void)
{
pci_unregister_driver(&orinoco_tmd_driver);
- ssleep(1);
}
module_init(orinoco_tmd_init);
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index f7b77ce54d7b..7f9aa139c347 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -1,6 +1,6 @@
/*
* Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
- * Symbol Wireless Networker LA4100, CompactFlash cards by Socket
+ * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
* Communications and Intel PRO/Wireless 2011B.
*
* The driver implements Symbol firmware download. The rest is handled
@@ -120,8 +120,8 @@ static void spectrum_cs_release(struct pcmcia_device *link);
* Each block has the following structure.
*/
struct dblock {
- __le32 _addr; /* adapter address where to write the block */
- __le16 _len; /* length of the data only, in bytes */
+ __le32 addr; /* adapter address where to write the block */
+ __le16 len; /* length of the data only, in bytes */
char data[0]; /* data to be written */
} __attribute__ ((packed));
@@ -131,9 +131,9 @@ struct dblock {
* items with matching ID should be written.
*/
struct pdr {
- __le32 _id; /* record ID */
- __le32 _addr; /* adapter address where to write the data */
- __le32 _len; /* expected length of the data, in bytes */
+ __le32 id; /* record ID */
+ __le32 addr; /* adapter address where to write the data */
+ __le32 len; /* expected length of the data, in bytes */
char next[0]; /* next PDR starts here */
} __attribute__ ((packed));
@@ -144,8 +144,8 @@ struct pdr {
* be plugged into the secondary firmware.
*/
struct pdi {
- __le16 _len; /* length of ID and data, in words */
- __le16 _id; /* record ID */
+ __le16 len; /* length of ID and data, in words */
+ __le16 id; /* record ID */
char data[0]; /* plug data */
} __attribute__ ((packed));
@@ -154,44 +154,44 @@ struct pdi {
static inline u32
dblock_addr(const struct dblock *blk)
{
- return le32_to_cpu(blk->_addr);
+ return le32_to_cpu(blk->addr);
}
static inline u32
dblock_len(const struct dblock *blk)
{
- return le16_to_cpu(blk->_len);
+ return le16_to_cpu(blk->len);
}
static inline u32
pdr_id(const struct pdr *pdr)
{
- return le32_to_cpu(pdr->_id);
+ return le32_to_cpu(pdr->id);
}
static inline u32
pdr_addr(const struct pdr *pdr)
{
- return le32_to_cpu(pdr->_addr);
+ return le32_to_cpu(pdr->addr);
}
static inline u32
pdr_len(const struct pdr *pdr)
{
- return le32_to_cpu(pdr->_len);
+ return le32_to_cpu(pdr->len);
}
static inline u32
pdi_id(const struct pdi *pdi)
{
- return le16_to_cpu(pdi->_id);
+ return le16_to_cpu(pdi->id);
}
/* Return length of the data only, in bytes */
static inline u32
pdi_len(const struct pdi *pdi)
{
- return 2 * (le16_to_cpu(pdi->_len) - 1);
+ return 2 * (le16_to_cpu(pdi->len) - 1);
}
@@ -343,8 +343,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
/* do the actual plugging */
spectrum_aux_setaddr(hw, pdr_addr(pdr));
- hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
- pdi_len(pdi) / 2);
+ hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
return 0;
}
@@ -424,8 +423,8 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
while (dblock_addr(blk) != BLOCK_END) {
spectrum_aux_setaddr(hw, blkaddr);
- hermes_write_words(hw, HERMES_AUXDATA, blk->data,
- blklen / 2);
+ hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
+ blklen);
blk = (struct dblock *) &blk->data[blklen];
blkaddr = dblock_addr(blk);
@@ -626,14 +625,11 @@ static void spectrum_cs_detach(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
+ if (link->dev_node)
+ unregister_netdev(dev);
+
spectrum_cs_release(link);
- DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
- if (link->dev_node) {
- DEBUG(0, PFX "About to unregister net device %p\n",
- dev);
- unregister_netdev(dev);
- }
free_orinocodev(dev);
} /* spectrum_cs_detach */
@@ -653,13 +649,10 @@ spectrum_cs_config(struct pcmcia_device *link)
int last_fn, last_ret;
u_char buf[64];
config_info_t conf;
- cisinfo_t info;
tuple_t tuple;
cisparse_t parse;
void __iomem *mem;
- CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
-
/*
* This reads the card's CONFIG tuple to find its
* configuration registers.
@@ -709,12 +702,6 @@ spectrum_cs_config(struct pcmcia_device *link)
goto next_entry;
link->conf.ConfigIndex = cfg->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)) {
@@ -835,19 +822,10 @@ spectrum_cs_config(struct pcmcia_device *link)
net_device has been registered */
/* Finally, report what we've done */
- printk(KERN_DEBUG "%s: index 0x%02x: ",
- dev->name, link->conf.ConfigIndex);
- if (link->conf.Vpp)
- printk(", Vpp %d.%d", link->conf.Vpp / 10,
- link->conf.Vpp % 10);
- 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");
+ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+ "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ link->irq.AssignedIRQ, link->io.BasePort1,
+ link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
@@ -888,11 +866,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
int err = 0;
/* Mark the device as stopped, to block IO until later */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
err = __orinoco_down(dev);
if (err)
@@ -902,9 +879,9 @@ spectrum_cs_suspend(struct pcmcia_device *link)
netif_device_detach(dev);
priv->hw_unavailable++;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
- return 0;
+ return err;
}
static int
@@ -932,7 +909,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
" David Gibson <hermes@gibson.dropbear.id.au>, et al)";
static struct pcmcia_device_id spectrum_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
+ PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index ff192e96268a..dade4b903579 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -4306,7 +4306,7 @@ out:
* Insertion of the module
* I'm now quite proud of the multi-device support.
*/
-int init_module(void)
+int __init init_module(void)
{
int ret = -EIO; /* Return error if no cards found */
int i;
diff --git a/drivers/usb/net/zd1201.c b/drivers/net/wireless/zd1201.c
index 9b1e4ed1d07e..662ecc8a33ff 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -33,7 +33,7 @@ static struct usb_device_id zd1201_table[] = {
{}
};
-static int ap = 0; /* Are we an AP or a normal station? */
+static int ap; /* Are we an AP or a normal station? */
#define ZD1201_VERSION "0.15"
@@ -49,7 +49,7 @@ MODULE_DEVICE_TABLE(usb, zd1201_table);
static int zd1201_fw_upload(struct usb_device *dev, int apfw)
{
const struct firmware *fw_entry;
- char* data;
+ char *data;
unsigned long len;
int err;
unsigned char ret;
@@ -65,7 +65,7 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw)
if (err) {
dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile);
dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n");
- dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info\n");
+ dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n");
return err;
}
@@ -94,12 +94,12 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw)
USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT);
if (err < 0)
goto exit;
-
+
err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
if (err < 0)
goto exit;
-
+
if (ret & 0x80) {
err = -EIO;
goto exit;
@@ -166,13 +166,13 @@ static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
return -ENOMEM;
}
usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
- command, 16, zd1201_usbfree, zd);
+ command, 16, zd1201_usbfree, zd);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
kfree(command);
usb_free_urb(urb);
}
-
+
return ret;
}
@@ -316,7 +316,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
fc = le16_to_cpu(*(__le16 *)&data[datalen-16]);
seq = le16_to_cpu(*(__le16 *)&data[datalen-24]);
- if(zd->monitor) {
+ if (zd->monitor) {
if (datalen < 24)
goto resubmit;
if (!(skb = dev_alloc_skb(datalen+24)))
@@ -364,7 +364,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
hlist_for_each_entry(frag, node, &zd->fraglist, fnode)
- if(frag->seq == (seq&IEEE80211_SCTL_SEQ))
+ if (frag->seq == (seq&IEEE80211_SCTL_SEQ))
break;
if (!frag)
goto resubmit;
@@ -376,7 +376,6 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
goto resubmit;
hlist_del_init(&frag->fnode);
kfree(frag);
- /* Fallthrough */
} else {
if (datalen<14)
goto resubmit;
@@ -422,7 +421,7 @@ static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
int rid_fid;
int length;
unsigned char *pdata;
-
+
zd->rxdatas = 0;
err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0);
if (err)
@@ -471,11 +470,11 @@ static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
length = zd->rxlen;
do {
- int actual_length;
+ int actual_length;
actual_length = (length > 64) ? 64 : length;
- if(pdata[0] != 0x3) {
+ if (pdata[0] != 0x3) {
dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n",
pdata[0]);
return -EINVAL;
@@ -487,11 +486,10 @@ static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
}
/* Skip the 4 bytes header (RID length and RID) */
- if(i == 0) {
+ if (i == 0) {
pdata += 8;
actual_length -= 8;
- }
- else {
+ } else {
pdata += 4;
actual_length -= 4;
}
@@ -620,7 +618,7 @@ static int zd1201_drvr_start(struct zd1201 *zd)
short max;
__le16 zdmax;
unsigned char *buffer;
-
+
buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -632,7 +630,7 @@ static int zd1201_drvr_start(struct zd1201 *zd)
err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);
if (err)
goto err_buffer;
-
+
err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
if (err)
goto err_urb;
@@ -684,7 +682,7 @@ static int zd1201_enable(struct zd1201 *zd)
static int zd1201_disable(struct zd1201 *zd)
{
int err;
-
+
if (!zd->mac_enabled)
return 0;
if (zd->monitor) {
@@ -764,7 +762,6 @@ static int zd1201_net_open(struct net_device *dev)
static int zd1201_net_stop(struct net_device *dev)
{
netif_stop_queue(dev);
-
return 0;
}
@@ -915,7 +912,6 @@ static int zd1201_get_name(struct net_device *dev,
struct iw_request_info *info, char *name, char *extra)
{
strcpy(name, "IEEE 802.11b");
-
return 0;
}
@@ -1013,11 +1009,10 @@ static int zd1201_set_mode(struct net_device *dev,
if (err)
return err;
}
- zd->monitor=monitor;
+ zd->monitor = monitor;
/* If monitor mode is set we don't actually turn it on here since it
* is done during mac reset anyway (see zd1201_mac_enable).
*/
-
zd1201_mac_reset(zd);
return 0;
@@ -1117,7 +1112,7 @@ static int zd1201_get_wap(struct net_device *dev,
zd->iwstats.qual.updated = 2;
}
- return zd1201_getconfig(zd,ZD1201_RID_CURRENTBSSID,ap_addr->sa_data,6);
+ return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6);
}
static int zd1201_set_scan(struct net_device *dev,
@@ -1275,7 +1270,7 @@ static int zd1201_set_rate(struct net_device *dev,
if (!rrq->fixed) { /* Also enable all lower bitrates */
rate |= rate-1;
}
-
+
err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate);
if (err)
return err;
@@ -1486,7 +1481,7 @@ static int zd1201_get_encode(struct net_device *dev,
return -EINVAL;
erq->flags |= i+1;
-
+
erq->length = zd->encode_keylen[i];
memcpy(key, zd->encode_keys[i], erq->length);
@@ -1529,11 +1524,7 @@ static int zd1201_set_power(struct net_device *dev,
return -EINVAL;
}
out:
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
- if (err)
- return err;
-
- return 0;
+ return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
}
static int zd1201_get_power(struct net_device *dev,
@@ -1627,15 +1618,11 @@ static int zd1201_set_hostauth(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
struct zd1201 *zd = (struct zd1201 *)dev->priv;
- int err;
if (!zd->ap)
return -EOPNOTSUPP;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
- if (err)
- return err;
- return 0;
+ return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
}
static int zd1201_get_hostauth(struct net_device *dev,
@@ -1744,7 +1731,7 @@ static int zd1201_probe(struct usb_interface *interface,
{
struct zd1201 *zd;
struct usb_device *usb;
- int i, err;
+ int err;
short porttype;
char buf[IW_ESSID_MAX_SIZE+2];
@@ -1773,9 +1760,7 @@ static int zd1201_probe(struct usb_interface *interface,
if (!zd->rx_urb || !zd->tx_urb)
goto err_zd;
- for(i = 0; i<100; i++)
- udelay(1000);
-
+ mdelay(100);
err = zd1201_drvr_start(zd);
if (err)
goto err_zd;
@@ -1833,7 +1818,7 @@ static int zd1201_probe(struct usb_interface *interface,
goto err_net;
dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
zd->dev->name);
-
+
usb_set_intfdata(interface, zd);
return 0;
diff --git a/drivers/usb/net/zd1201.h b/drivers/net/wireless/zd1201.h
index 235f0ee34b24..235f0ee34b24 100644
--- a/drivers/usb/net/zd1201.h
+++ b/drivers/net/wireless/zd1201.h
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 4e53be9c03ab..bbeabe3fc4c6 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -535,7 +535,7 @@ pdcs_auto_read(struct subsystem *entry, char *buf, int knob)
{
char *out = buf;
struct pdcspath_entry *pathentry;
-
+
if (!entry || !buf)
return -EINVAL;
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 42b32ff2fca6..278f325021ee 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -178,6 +178,11 @@ extern struct proc_dir_entry * proc_mckinley_root;
#define ROPE6_CTL 0x230
#define ROPE7_CTL 0x238
+#define IOC_ROPE0_CFG 0x500 /* pluto only */
+#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
+
+
+
#define HF_ENABLE 0x40
@@ -1759,19 +1764,33 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
sba_dev->num_ioc = num_ioc;
for (i = 0; i < num_ioc; i++) {
- /*
- ** Make sure the box crashes if we get any errors on a rope.
- */
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
-
- /* flush out the writes */
+ unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+ unsigned int j;
+
+ for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
+
+ /*
+ * Clear ROPE(N)_CONFIG AO bit.
+ * Disables "NT Ordering" (~= !"Relaxed Ordering")
+ * Overrides bit 1 in DMA Hint Sets.
+ * Improves netperf UDP_STREAM by ~10% for bcm5701.
+ */
+ if (IS_PLUTO(sba_dev->iodc)) {
+ unsigned long rope_cfg, cfg_val;
+
+ rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
+ cfg_val = READ_REG(rope_cfg);
+ cfg_val &= ~IOC_ROPE_AO;
+ WRITE_REG(cfg_val, rope_cfg);
+ }
+
+ /*
+ ** Make sure the box crashes on rope errors.
+ */
+ WRITE_REG(HF_ENABLE, ioc_hpa + ROPE0_CTL + j);
+ }
+
+ /* flush out the last writes */
READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
DBG_INIT(" ioc[%d] ROPE_CFG 0x%Lx ROPE_DBG 0x%Lx\n",
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 719b863bc20e..828eb45062de 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -155,7 +155,7 @@ superio_init(struct pci_dev *pcidev)
struct pci_dev *pdev = sio->lio_pdev;
u16 word;
- if (sio->suckyio_irq_enabled)
+ if (sio->suckyio_irq_enabled)
return;
BUG_ON(!pdev);
@@ -194,7 +194,7 @@ superio_init(struct pci_dev *pcidev)
request_region (sio->acpi_base, 0x1f, "acpi");
/* Enable the legacy I/O function */
- pci_read_config_word (pdev, PCI_COMMAND, &word);
+ pci_read_config_word (pdev, PCI_COMMAND, &word);
word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
pci_write_config_word (pdev, PCI_COMMAND, word);
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index f63c387976cf..6c8452ede0e1 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -48,7 +48,7 @@ config PARPORT_PC
config PARPORT_SERIAL
tristate "Multi-IO cards (parallel and serial)"
- depends on SERIAL_8250 && PARPORT_PC && PCI
+ depends on SERIAL_8250_PCI && PARPORT_PC && PCI
help
This adds support for multi-IO PCI cards that have parallel and
serial ports. You should say Y or M here. If you say M, the module
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 2087a397ef16..9855c4c920b8 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -793,8 +793,10 @@ static int msix_capability_init(struct pci_dev *dev,
if (!entry)
break;
vector = get_msi_vector(dev);
- if (vector < 0)
+ if (vector < 0) {
+ kmem_cache_free(msi_cachep, entry);
break;
+ }
j = entries[i].entry;
entries[i].vector = vector;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 6917c6cb0912..c2ecae5ff0c1 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -33,13 +33,10 @@ acpi_query_osc (
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[4];
- struct acpi_buffer output;
- union acpi_object out_obj;
+ struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *out_obj;
u32 osc_dw0;
- /* Setting up output buffer */
- output.length = sizeof(out_obj) + 3*sizeof(u32);
- output.pointer = &out_obj;
/* Setting up input parameters */
input.count = 4;
@@ -61,12 +58,15 @@ acpi_query_osc (
"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
return status;
}
- if (out_obj.type != ACPI_TYPE_BUFFER) {
+ out_obj = output.pointer;
+
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
printk(KERN_DEBUG
"Evaluate _OSC returns wrong type\n");
- return AE_TYPE;
+ status = AE_TYPE;
+ goto query_osc_out;
}
- osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+ osc_dw0 = *((u32 *) out_obj->buffer.pointer);
if (osc_dw0) {
if (osc_dw0 & OSC_REQUEST_ERROR)
printk(KERN_DEBUG "_OSC request fails\n");
@@ -76,15 +76,21 @@ acpi_query_osc (
printk(KERN_DEBUG "_OSC invalid revision\n");
if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
/* Update Global Control Set */
- global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8));
- return AE_OK;
+ global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8));
+ status = AE_OK;
+ goto query_osc_out;
}
- return AE_ERROR;
+ status = AE_ERROR;
+ goto query_osc_out;
}
/* Update Global Control Set */
- global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8));
- return AE_OK;
+ global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
+ status = AE_OK;
+
+query_osc_out:
+ kfree(output.pointer);
+ return status;
}
@@ -96,14 +102,10 @@ acpi_run_osc (
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[4];
- struct acpi_buffer output;
- union acpi_object out_obj;
+ struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *out_obj;
u32 osc_dw0;
- /* Setting up output buffer */
- output.length = sizeof(out_obj) + 3*sizeof(u32);
- output.pointer = &out_obj;
-
/* Setting up input parameters */
input.count = 4;
input.pointer = in_params;
@@ -124,12 +126,14 @@ acpi_run_osc (
"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
return status;
}
- if (out_obj.type != ACPI_TYPE_BUFFER) {
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
printk(KERN_DEBUG
"Evaluate _OSC returns wrong type\n");
- return AE_TYPE;
+ status = AE_TYPE;
+ goto run_osc_out;
}
- osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+ osc_dw0 = *((u32 *) out_obj->buffer.pointer);
if (osc_dw0) {
if (osc_dw0 & OSC_REQUEST_ERROR)
printk(KERN_DEBUG "_OSC request fails\n");
@@ -139,11 +143,17 @@ acpi_run_osc (
printk(KERN_DEBUG "_OSC invalid revision\n");
if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
printk(KERN_DEBUG "_OSC FW not grant req. control\n");
- return AE_SUPPORT;
+ status = AE_SUPPORT;
+ goto run_osc_out;
}
- return AE_ERROR;
+ status = AE_ERROR;
+ goto run_osc_out;
}
- return AE_OK;
+ status = AE_OK;
+
+run_osc_out:
+ kfree(output.pointer);
+ return status;
}
/**
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 1456759936c5..10e1a905c144 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -285,9 +285,9 @@ static int pci_device_suspend(struct device * dev, pm_message_t state)
* Default resume method for devices that have no driver provided resume,
* or not even a driver at all.
*/
-static void pci_default_resume(struct pci_dev *pci_dev)
+static int pci_default_resume(struct pci_dev *pci_dev)
{
- int retval;
+ int retval = 0;
/* restore the PCI config space */
pci_restore_state(pci_dev);
@@ -297,18 +297,21 @@ static void pci_default_resume(struct pci_dev *pci_dev)
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
+
+ return retval;
}
static int pci_device_resume(struct device * dev)
{
+ int error;
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
if (drv && drv->resume)
- drv->resume(pci_dev);
+ error = drv->resume(pci_dev);
else
- pci_default_resume(pci_dev);
- return 0;
+ error = pci_default_resume(pci_dev);
+ return error;
}
static void pci_device_shutdown(struct device *dev)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2329f941a0dc..fde41cc14734 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -164,7 +164,6 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);
}
-#if 0
/**
* pci_find_ext_capability - Find an extended capability
* @dev: PCI device to query
@@ -212,7 +211,7 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
return 0;
}
-#endif /* 0 */
+EXPORT_SYMBOL_GPL(pci_find_ext_capability);
/**
* pci_find_parent_resource - return resource region of parent bus of given region
@@ -461,9 +460,23 @@ int
pci_restore_state(struct pci_dev *dev)
{
int i;
+ int val;
- for (i = 0; i < 16; i++)
- pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]);
+ /*
+ * The Base Address register should be programmed before the command
+ * register(s)
+ */
+ for (i = 15; i >= 0; i--) {
+ pci_read_config_dword(dev, i * 4, &val);
+ if (val != dev->saved_config_space[i]) {
+ printk(KERN_DEBUG "PM: Writing back config space on "
+ "device %s at offset %x (was %x, writing %x)\n",
+ pci_name(dev), i,
+ val, (int)dev->saved_config_space[i]);
+ pci_write_config_dword(dev,i * 4,
+ dev->saved_config_space[i]);
+ }
+ }
pci_restore_msi_state(dev);
pci_restore_msix_state(dev);
return 0;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c42ae2cf8d64..d378478612fb 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -634,6 +634,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi
* non-x86 architectures (yes Via exists on PPC among other places),
* we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
* interrupts delivered properly.
+ *
+ * Some of the on-chip devices are actually '586 devices' so they are
+ * listed here.
*/
static void quirk_via_irq(struct pci_dev *dev)
{
@@ -642,13 +645,19 @@ static void quirk_via_irq(struct pci_dev *dev)
new_irq = dev->irq & 0xf;
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
- printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
+ printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n",
pci_name(dev), irq, new_irq);
udelay(15); /* unknown if delay really needed */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq);
/*
* VIA VT82C598 has its device ID settable and many BIOSes
@@ -893,6 +902,7 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
+#ifndef CONFIG_ACPI_SLEEP
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
* is not activated. The myth is that Asus said that they do not want the
@@ -904,8 +914,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
* becomes necessary to do this tweak in two steps -- I've chosen the Host
* bridge as trigger.
+ *
+ * Actually, leaving it unhidden and not redoing the quirk over suspend2ram
+ * will cause thermal management to break down, and causing machine to
+ * overheat.
*/
-static int __initdata asus_hides_smbus = 0;
+static int __initdata asus_hides_smbus;
static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
{
@@ -1048,6 +1062,8 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
+#endif
+
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
*/
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index cba6c9eef28e..61cb4b29f55c 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -250,7 +250,7 @@ config M32R_CFC_NUM
config PCMCIA_VRC4171
tristate "NEC VRC4171 Card Controllers support"
- depends on VRC4171 && PCMCIA
+ depends on CPU_VR41XX && ISA && PCMCIA
config PCMCIA_VRC4173
tristate "NEC VRC4173 CARDU support"
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index ae10d1eed65e..74b3124e8247 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -236,11 +236,11 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
/**
* pcmcia_load_firmware - load CIS from userspace if device-provided is broken
* @dev - the pcmcia device which needs a CIS override
- * @filename - requested filename in /lib/firmware/cis/
+ * @filename - requested filename in /lib/firmware/
*
* This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
* the one provided by the card is broken. The firmware files reside in
- * /lib/firmware/cis/ in userspace.
+ * /lib/firmware/ in userspace.
*/
static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
{
@@ -298,9 +298,6 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam
*
* Registers a PCMCIA driver with the PCMCIA bus core.
*/
-static int pcmcia_device_probe(struct device *dev);
-static int pcmcia_device_remove(struct device * dev);
-
int pcmcia_register_driver(struct pcmcia_driver *driver)
{
if (!driver)
@@ -400,7 +397,7 @@ static int pcmcia_device_probe(struct device * dev)
* call which will then check whether there are two
* pseudo devices, and if not, add the second one.
*/
- did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
+ did = p_dev->dev.driver_data;
if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
pcmcia_add_pseudo_device(p_dev->socket);
@@ -448,7 +445,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
return;
}
-
static int pcmcia_device_remove(struct device * dev)
{
struct pcmcia_device *p_dev;
@@ -463,7 +459,7 @@ static int pcmcia_device_remove(struct device * dev)
* pseudo multi-function card, we need to unbind
* all devices
*/
- did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
+ did = p_dev->dev.driver_data;
if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count != 0) &&
(p_dev->device_no == 0))
@@ -476,6 +472,8 @@ static int pcmcia_device_remove(struct device * dev)
if (p_drv->remove)
p_drv->remove(p_dev);
+ p_dev->dev_node = NULL;
+
/* check for proper unloading */
if (p_dev->_irq || p_dev->_io || p_dev->_locked)
printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
@@ -628,7 +626,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
}
/* Add to the list in pcmcia_bus_socket */
- list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+ list_add(&p_dev->socket_device_list, &s->devices_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
@@ -1145,6 +1143,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
{
struct pcmcia_socket *s = pcmcia_get_socket(skt);
+ if (!s) {
+ printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \
+ "failed, event 0x%x lost!\n", skt, event);
+ return -ENODEV;
+ }
+
ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
event, priority, skt);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index bd0308e89815..a2f05f485156 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -509,7 +509,8 @@ static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs)
static u_int __init test_irq(u_short sock, int irq)
{
debug(2, " testing ISA irq %d\n", irq);
- if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0)
+ if (request_irq(irq, i365_count_irq, SA_PROBEIRQ, "scan",
+ i365_count_irq) != 0)
return 1;
irq_hits = 0; irq_sock = sock;
msleep(10);
@@ -561,7 +562,7 @@ static u_int __init isa_scan(u_short sock, u_int mask0)
} else {
/* Fallback: just find interrupts that aren't in use */
for (i = 0; i < 16; i++)
- if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0))
+ if ((mask0 & (1 << i)) && (_check_irq(i, SA_PROBEIRQ) == 0))
mask1 |= (1 << i);
printk("default");
/* If scan failed, default to polled status */
@@ -725,7 +726,7 @@ static void __init add_pcic(int ns, int type)
u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
for (cs_irq = 15; cs_irq > 0; cs_irq--)
if ((cs_mask & (1 << cs_irq)) &&
- (_check_irq(cs_irq, 0) == 0))
+ (_check_irq(cs_irq, SA_PROBEIRQ) == 0))
break;
if (cs_irq) {
grab_irq = 1;
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index c53db7ceda5e..738b1ef595a3 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -426,7 +426,7 @@ static int ds_open(struct inode *inode, struct file *file)
if (!warning_printed) {
printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
- "usage.\n");
+ "usage from process: %s.\n", current->comm);
printk(KERN_INFO "pcmcia: This interface will soon be removed from "
"the kernel; please expect breakage unless you upgrade "
"to new tools.\n");
@@ -601,8 +601,12 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
- ret = pccard_get_configuration_info(s, p_dev, &buf->config);
- pcmcia_put_dev(p_dev);
+ if (p_dev == NULL)
+ ret = CS_BAD_ARGS;
+ else {
+ ret = pccard_get_configuration_info(s, p_dev, &buf->config);
+ pcmcia_put_dev(p_dev);
+ }
}
break;
case DS_GET_FIRST_TUPLE:
@@ -632,8 +636,12 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
- ret = pccard_get_status(s, p_dev, &buf->status);
- pcmcia_put_dev(p_dev);
+ if (p_dev == NULL)
+ ret = CS_BAD_ARGS;
+ else {
+ ret = pccard_get_status(s, p_dev, &buf->status);
+ pcmcia_put_dev(p_dev);
+ }
}
break;
case DS_VALIDATE_CIS:
@@ -665,9 +673,10 @@ static int ds_ioctl(struct inode * inode, struct file * file,
if (!(buf->conf_reg.Function &&
(buf->conf_reg.Function >= s->functions))) {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
- if (p_dev)
+ if (p_dev) {
ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
- pcmcia_put_dev(p_dev);
+ pcmcia_put_dev(p_dev);
+ }
}
break;
case DS_GET_FIRST_REGION:
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 45063b4e5b78..3131bb0a0095 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -88,7 +88,6 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
}
if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
*base = s->io_offset | (*base & 0x0fff);
- s->io[0].res->flags = (s->io[0].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
return 0;
}
/* Check for an already-allocated window that must conflict with
@@ -209,7 +208,6 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- config->Function = p_dev->func;
#ifdef CONFIG_CARDBUS
if (s->state & SOCKET_CARDBUS) {
@@ -223,14 +221,22 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
config->AssignedIRQ = s->irq.AssignedIRQ;
if (config->AssignedIRQ)
config->Attributes |= CONF_ENABLE_IRQ;
- config->BasePort1 = s->io[0].res->start;
- config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
+ if (s->io[0].res) {
+ config->BasePort1 = s->io[0].res->start;
+ config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
+ }
}
return CS_SUCCESS;
}
#endif
- c = (p_dev) ? p_dev->function_config : NULL;
+ if (p_dev) {
+ c = p_dev->function_config;
+ config->Function = p_dev->func;
+ } else {
+ c = NULL;
+ config->Function = 0;
+ }
if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
config->Attributes = 0;
@@ -947,7 +953,5 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) {
pcmcia_release_irq(p_dev, &p_dev->irq);
if (&p_dev->win)
pcmcia_release_window(p_dev->win);
-
- p_dev->dev_node = NULL;
}
EXPORT_SYMBOL(pcmcia_disable_device);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 16d1ea7b0a18..247ab837f841 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -589,7 +589,7 @@ static int pd6729_check_irq(int irq, int flags)
return 0;
}
-static u_int __init pd6729_isa_scan(void)
+static u_int __devinit pd6729_isa_scan(void)
{
u_int mask0, mask = 0;
int i;
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index b1e3e6179e56..2011567005f9 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -58,7 +58,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned long data;
ssize_t ret;
- if (count < sizeof(unsigned long))
+ if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&rtc->irq_queue, &wait);
@@ -90,11 +90,16 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (ret == 0) {
/* Check for any data updates */
if (rtc->ops->read_callback)
- data = rtc->ops->read_callback(rtc->class_dev.dev, data);
-
- ret = put_user(data, (unsigned long __user *)buf);
- if (ret == 0)
- ret = sizeof(unsigned long);
+ data = rtc->ops->read_callback(rtc->class_dev.dev,
+ data);
+
+ if (sizeof(int) != sizeof(long) &&
+ count == sizeof(unsigned int))
+ ret = put_user(data, (unsigned int __user *)buf) ?:
+ sizeof(unsigned int);
+ else
+ ret = put_user(data, (unsigned long __user *)buf) ?:
+ sizeof(unsigned long);
}
return ret;
}
@@ -136,13 +141,13 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
/* try the driver's ioctl interface */
if (ops->ioctl) {
err = ops->ioctl(class_dev->dev, cmd, arg);
- if (err != -EINVAL)
+ if (err != -ENOIOCTLCMD)
return err;
}
/* if the driver does not provide the ioctl interface
* or if that particular ioctl was not implemented
- * (-EINVAL), we will try to emulate here.
+ * (-ENOIOCTLCMD), we will try to emulate here.
*/
switch (cmd) {
@@ -228,7 +233,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
break;
default:
- err = -EINVAL;
+ err = -ENOTTY;
break;
}
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index f6e7ee04f3dc..8c0d1a6739ad 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -48,33 +48,33 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
struct platform_device *pdev = to_platform_device(dev);
struct m48t86_ops *ops = pdev->dev.platform_data;
- reg = ops->readb(M48T86_REG_B);
+ reg = ops->readbyte(M48T86_REG_B);
if (reg & M48T86_REG_B_DM) {
/* data (binary) mode */
- tm->tm_sec = ops->readb(M48T86_REG_SEC);
- tm->tm_min = ops->readb(M48T86_REG_MIN);
- tm->tm_hour = ops->readb(M48T86_REG_HOUR) & 0x3F;
- tm->tm_mday = ops->readb(M48T86_REG_DOM);
+ tm->tm_sec = ops->readbyte(M48T86_REG_SEC);
+ tm->tm_min = ops->readbyte(M48T86_REG_MIN);
+ tm->tm_hour = ops->readbyte(M48T86_REG_HOUR) & 0x3F;
+ tm->tm_mday = ops->readbyte(M48T86_REG_DOM);
/* tm_mon is 0-11 */
- tm->tm_mon = ops->readb(M48T86_REG_MONTH) - 1;
- tm->tm_year = ops->readb(M48T86_REG_YEAR) + 100;
- tm->tm_wday = ops->readb(M48T86_REG_DOW);
+ tm->tm_mon = ops->readbyte(M48T86_REG_MONTH) - 1;
+ tm->tm_year = ops->readbyte(M48T86_REG_YEAR) + 100;
+ tm->tm_wday = ops->readbyte(M48T86_REG_DOW);
} else {
/* bcd mode */
- tm->tm_sec = BCD2BIN(ops->readb(M48T86_REG_SEC));
- tm->tm_min = BCD2BIN(ops->readb(M48T86_REG_MIN));
- tm->tm_hour = BCD2BIN(ops->readb(M48T86_REG_HOUR) & 0x3F);
- tm->tm_mday = BCD2BIN(ops->readb(M48T86_REG_DOM));
+ tm->tm_sec = BCD2BIN(ops->readbyte(M48T86_REG_SEC));
+ tm->tm_min = BCD2BIN(ops->readbyte(M48T86_REG_MIN));
+ tm->tm_hour = BCD2BIN(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
+ tm->tm_mday = BCD2BIN(ops->readbyte(M48T86_REG_DOM));
/* tm_mon is 0-11 */
- tm->tm_mon = BCD2BIN(ops->readb(M48T86_REG_MONTH)) - 1;
- tm->tm_year = BCD2BIN(ops->readb(M48T86_REG_YEAR)) + 100;
- tm->tm_wday = BCD2BIN(ops->readb(M48T86_REG_DOW));
+ tm->tm_mon = BCD2BIN(ops->readbyte(M48T86_REG_MONTH)) - 1;
+ tm->tm_year = BCD2BIN(ops->readbyte(M48T86_REG_YEAR)) + 100;
+ tm->tm_wday = BCD2BIN(ops->readbyte(M48T86_REG_DOW));
}
/* correct the hour if the clock is in 12h mode */
if (!(reg & M48T86_REG_B_H24))
- if (ops->readb(M48T86_REG_HOUR) & 0x80)
+ if (ops->readbyte(M48T86_REG_HOUR) & 0x80)
tm->tm_hour += 12;
return 0;
@@ -86,35 +86,35 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct platform_device *pdev = to_platform_device(dev);
struct m48t86_ops *ops = pdev->dev.platform_data;
- reg = ops->readb(M48T86_REG_B);
+ reg = ops->readbyte(M48T86_REG_B);
/* update flag and 24h mode */
reg |= M48T86_REG_B_SET | M48T86_REG_B_H24;
- ops->writeb(reg, M48T86_REG_B);
+ ops->writebyte(reg, M48T86_REG_B);
if (reg & M48T86_REG_B_DM) {
/* data (binary) mode */
- ops->writeb(tm->tm_sec, M48T86_REG_SEC);
- ops->writeb(tm->tm_min, M48T86_REG_MIN);
- ops->writeb(tm->tm_hour, M48T86_REG_HOUR);
- ops->writeb(tm->tm_mday, M48T86_REG_DOM);
- ops->writeb(tm->tm_mon + 1, M48T86_REG_MONTH);
- ops->writeb(tm->tm_year % 100, M48T86_REG_YEAR);
- ops->writeb(tm->tm_wday, M48T86_REG_DOW);
+ ops->writebyte(tm->tm_sec, M48T86_REG_SEC);
+ ops->writebyte(tm->tm_min, M48T86_REG_MIN);
+ ops->writebyte(tm->tm_hour, M48T86_REG_HOUR);
+ ops->writebyte(tm->tm_mday, M48T86_REG_DOM);
+ ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH);
+ ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR);
+ ops->writebyte(tm->tm_wday, M48T86_REG_DOW);
} else {
/* bcd mode */
- ops->writeb(BIN2BCD(tm->tm_sec), M48T86_REG_SEC);
- ops->writeb(BIN2BCD(tm->tm_min), M48T86_REG_MIN);
- ops->writeb(BIN2BCD(tm->tm_hour), M48T86_REG_HOUR);
- ops->writeb(BIN2BCD(tm->tm_mday), M48T86_REG_DOM);
- ops->writeb(BIN2BCD(tm->tm_mon + 1), M48T86_REG_MONTH);
- ops->writeb(BIN2BCD(tm->tm_year % 100), M48T86_REG_YEAR);
- ops->writeb(BIN2BCD(tm->tm_wday), M48T86_REG_DOW);
+ ops->writebyte(BIN2BCD(tm->tm_sec), M48T86_REG_SEC);
+ ops->writebyte(BIN2BCD(tm->tm_min), M48T86_REG_MIN);
+ ops->writebyte(BIN2BCD(tm->tm_hour), M48T86_REG_HOUR);
+ ops->writebyte(BIN2BCD(tm->tm_mday), M48T86_REG_DOM);
+ ops->writebyte(BIN2BCD(tm->tm_mon + 1), M48T86_REG_MONTH);
+ ops->writebyte(BIN2BCD(tm->tm_year % 100), M48T86_REG_YEAR);
+ ops->writebyte(BIN2BCD(tm->tm_wday), M48T86_REG_DOW);
}
/* update ended */
reg &= ~M48T86_REG_B_SET;
- ops->writeb(reg, M48T86_REG_B);
+ ops->writebyte(reg, M48T86_REG_B);
return 0;
}
@@ -125,12 +125,12 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
struct platform_device *pdev = to_platform_device(dev);
struct m48t86_ops *ops = pdev->dev.platform_data;
- reg = ops->readb(M48T86_REG_B);
+ reg = ops->readbyte(M48T86_REG_B);
seq_printf(seq, "mode\t\t: %s\n",
(reg & M48T86_REG_B_DM) ? "binary" : "bcd");
- reg = ops->readb(M48T86_REG_D);
+ reg = ops->readbyte(M48T86_REG_D);
seq_printf(seq, "battery\t\t: %s\n",
(reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
@@ -157,7 +157,7 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev)
platform_set_drvdata(dev, rtc);
/* read battery status */
- reg = ops->readb(M48T86_REG_D);
+ reg = ops->readbyte(M48T86_REG_D);
dev_info(&dev->dev, "battery %s\n",
(reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index a23ec54989f6..a997529f8926 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -178,9 +178,9 @@ static int sa1100_rtc_open(struct device *dev)
return 0;
fail_pi:
- free_irq(IRQ_RTCAlrm, NULL);
+ free_irq(IRQ_RTCAlrm, dev);
fail_ai:
- free_irq(IRQ_RTC1Hz, NULL);
+ free_irq(IRQ_RTC1Hz, dev);
fail_ui:
return ret;
}
@@ -247,7 +247,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
rtc_freq = arg;
return 0;
}
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -295,7 +295,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
{
- seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR);
+ seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR);
seq_printf(seq, "alarm_IRQ\t: %s\n",
(RTSR & RTSR_ALE) ? "yes" : "no" );
seq_printf(seq, "update_IRQ\t: %s\n",
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index e1f7e8e86daf..e1fa5fe7901f 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -71,7 +71,7 @@ static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
return 0;
default:
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
}
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 4d49fd501198..277596c302e3 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -270,7 +270,7 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
epoch = arg;
break;
default:
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
return 0;
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index a3bfebcf31ef..cfb1fff3787c 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -315,6 +315,11 @@ dasd_increase_state(struct dasd_device *device)
rc = dasd_state_basic_to_ready(device);
if (!rc &&
+ device->state == DASD_STATE_UNFMT &&
+ device->target > DASD_STATE_UNFMT)
+ rc = -EPERM;
+
+ if (!rc &&
device->state == DASD_STATE_READY &&
device->target >= DASD_STATE_ONLINE)
rc = dasd_state_ready_to_online(device);
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index c1c6f1381150..216bc4fba199 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -45,6 +45,7 @@ struct dasd_devmap {
unsigned int devindex;
unsigned short features;
struct dasd_device *device;
+ struct dasd_uid uid;
};
/*
@@ -716,6 +717,68 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *bu
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
+static ssize_t
+dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ int alias;
+
+ devmap = dasd_find_busid(dev->bus_id);
+ spin_lock(&dasd_devmap_lock);
+ if (!IS_ERR(devmap))
+ alias = devmap->uid.alias;
+ else
+ alias = 0;
+ spin_unlock(&dasd_devmap_lock);
+
+ return sprintf(buf, alias ? "1\n" : "0\n");
+}
+
+static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
+
+static ssize_t
+dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ char *vendor;
+
+ devmap = dasd_find_busid(dev->bus_id);
+ spin_lock(&dasd_devmap_lock);
+ if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
+ vendor = devmap->uid.vendor;
+ else
+ vendor = "";
+ spin_unlock(&dasd_devmap_lock);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
+}
+
+static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
+
+#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\
+ /* SSID */ 4 + 1 + /* unit addr */ 2 + 1)
+
+static ssize_t
+dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ char uid[UID_STRLEN];
+
+ devmap = dasd_find_busid(dev->bus_id);
+ spin_lock(&dasd_devmap_lock);
+ if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
+ snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
+ devmap->uid.vendor, devmap->uid.serial,
+ devmap->uid.ssid, devmap->uid.unit_addr);
+ else
+ uid[0] = 0;
+ spin_unlock(&dasd_devmap_lock);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", uid);
+}
+
+static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
+
/*
* extended error-reporting
*/
@@ -759,6 +822,9 @@ static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
+ &dev_attr_alias.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_uid.attr,
&dev_attr_use_diag.attr,
&dev_attr_eer_enabled.attr,
NULL,
@@ -768,6 +834,42 @@ static struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
+
+/*
+ * Return copy of the device unique identifier.
+ */
+int
+dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
+{
+ struct dasd_devmap *devmap;
+
+ devmap = dasd_find_busid(cdev->dev.bus_id);
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+ spin_lock(&dasd_devmap_lock);
+ *uid = devmap->uid;
+ spin_unlock(&dasd_devmap_lock);
+ return 0;
+}
+
+/*
+ * Register the given device unique identifier into devmap struct.
+ */
+int
+dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
+{
+ struct dasd_devmap *devmap;
+
+ devmap = dasd_find_busid(cdev->dev.bus_id);
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+ spin_lock(&dasd_devmap_lock);
+ devmap->uid = *uid;
+ spin_unlock(&dasd_devmap_lock);
+ return 0;
+}
+EXPORT_SYMBOL(dasd_set_uid);
+
/*
* Return value of the specified feature.
*/
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index ee09ef33d08d..7d5a6cee4bd8 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -446,6 +446,39 @@ dasd_eckd_cdl_reclen(int recid)
return LABEL_SIZE;
}
+/*
+ * Generate device unique id that specifies the physical device.
+ */
+static int
+dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
+{
+ struct dasd_eckd_private *private;
+ struct dasd_eckd_confdata *confdata;
+
+ private = (struct dasd_eckd_private *) device->private;
+ if (!private)
+ return -ENODEV;
+ confdata = &private->conf_data;
+ if (!confdata)
+ return -ENODEV;
+
+ memset(uid, 0, sizeof(struct dasd_uid));
+ strncpy(uid->vendor, confdata->ned1.HDA_manufacturer,
+ sizeof(uid->vendor) - 1);
+ EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
+ strncpy(uid->serial, confdata->ned1.HDA_location,
+ sizeof(uid->serial) - 1);
+ EBCASC(uid->serial, sizeof(uid->serial) - 1);
+ uid->ssid = confdata->neq.subsystemID;
+ if (confdata->ned2.sneq.flags == 0x40) {
+ uid->alias = 1;
+ uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
+ } else
+ uid->unit_addr = confdata->ned1.unit_addr;
+
+ return 0;
+}
+
static int
dasd_eckd_read_conf(struct dasd_device *device)
{
@@ -507,11 +540,15 @@ dasd_eckd_read_conf(struct dasd_device *device)
return 0;
}
-
+/*
+ * Check device characteristics.
+ * If the device is accessible using ECKD discipline, the device is enabled.
+ */
static int
dasd_eckd_check_characteristics(struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ struct dasd_uid uid;
void *rdc_data;
int rc;
@@ -536,6 +573,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
/* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data);
+ memset(rdc_data, 0, sizeof(rdc_data));
rc = read_dev_chars(device->cdev, &rdc_data, 64);
if (rc) {
DEV_MESSAGE(KERN_WARNING, device,
@@ -556,8 +594,17 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
/* Read Configuration Data */
rc = dasd_eckd_read_conf (device);
- return rc;
+ if (rc)
+ return rc;
+
+ /* Generate device unique id and register in devmap */
+ rc = dasd_eckd_generate_uid(device, &uid);
+ if (rc)
+ return rc;
+ rc = dasd_set_uid(device->cdev, &uid);
+
+ return rc;
}
static struct dasd_ccw_req *
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index ad8524bb7bb3..d5734e976e1c 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -228,26 +228,36 @@ struct dasd_eckd_confdata {
unsigned char HDA_manufacturer[3];
unsigned char HDA_location[2];
unsigned char HDA_seqno[12];
- __u16 ID;
+ __u8 ID;
+ __u8 unit_addr;
} __attribute__ ((packed)) ned1;
- struct {
+ union {
struct {
- unsigned char identifier:2;
- unsigned char token_id:1;
- unsigned char sno_valid:1;
- unsigned char subst_sno:1;
- unsigned char recNED:1;
- unsigned char emuNED:1;
- unsigned char reserved:1;
- } __attribute__ ((packed)) flags;
- __u8 descriptor;
- __u8 reserved[2];
- unsigned char dev_type[6];
- unsigned char dev_model[3];
- unsigned char DASD_manufacturer[3];
- unsigned char DASD_location[2];
- unsigned char DASD_seqno[12];
- __u16 ID;
+ struct {
+ unsigned char identifier:2;
+ unsigned char token_id:1;
+ unsigned char sno_valid:1;
+ unsigned char subst_sno:1;
+ unsigned char recNED:1;
+ unsigned char emuNED:1;
+ unsigned char reserved:1;
+ } __attribute__ ((packed)) flags;
+ __u8 descriptor;
+ __u8 reserved[2];
+ unsigned char dev_type[6];
+ unsigned char dev_model[3];
+ unsigned char DASD_manufacturer[3];
+ unsigned char DASD_location[2];
+ unsigned char DASD_seqno[12];
+ __u16 ID;
+ } __attribute__ ((packed)) ned;
+ struct {
+ unsigned char flags; /* byte 0 */
+ unsigned char res2[7]; /* byte 1- 7 */
+ unsigned char sua_flags; /* byte 8 */
+ __u8 base_unit_addr; /* byte 9 */
+ unsigned char res3[22]; /* byte 10-31 */
+ } __attribute__ ((packed)) sneq;
} __attribute__ ((packed)) ned2;
struct {
struct {
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 4293ba827523..d4b13e300a76 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -268,6 +268,16 @@ struct dasd_discipline {
extern struct dasd_discipline *dasd_diag_discipline_pointer;
+/*
+ * Unique identifier for dasd device.
+ */
+struct dasd_uid {
+ __u8 alias;
+ char vendor[4];
+ char serial[15];
+ __u16 ssid;
+ __u8 unit_addr;
+};
/*
* Notification numbers for extended error reporting notifications:
@@ -516,6 +526,8 @@ void dasd_devmap_exit(void);
struct dasd_device *dasd_create_device(struct ccw_device *);
void dasd_delete_device(struct dasd_device *);
+int dasd_get_uid(struct ccw_device *, struct dasd_uid *);
+int dasd_set_uid(struct ccw_device *, struct dasd_uid *);
int dasd_get_feature(struct ccw_device *, int);
int dasd_set_feature(struct ccw_device *, int, int);
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index c3915f60a3aa..d71ef1adea59 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -230,14 +230,16 @@ tape_3590_read_attmsg(struct tape_device *device)
* These functions are used to schedule follow-up actions from within an
* interrupt context (like unsolicited interrupts).
*/
+struct work_handler_data {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+};
+
static void
tape_3590_work_handler(void *data)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p = data;
+ struct work_handler_data *p = data;
switch (p->op) {
case TO_MSEN:
@@ -257,11 +259,7 @@ tape_3590_work_handler(void *data)
static int
tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p;
+ struct work_handler_data *p;
if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
@@ -316,7 +314,7 @@ tape_3590_bread(struct tape_device *device, struct request *req)
rq_for_each_bio(bio, req) {
bio_for_each_segment(bv, bio, i) {
- dst = kmap(bv->bv_page) + bv->bv_offset;
+ dst = page_address(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len;
off += TAPEBLOCK_HSEC_SIZE) {
ccw->flags = CCW_FLAG_CC;
@@ -1168,6 +1166,7 @@ tape_3590_setup_device(struct tape_device *device)
static void
tape_3590_cleanup_device(struct tape_device *device)
{
+ flush_scheduled_work();
tape_std_unassign(device);
kfree(device->discdata);
@@ -1234,6 +1233,7 @@ static struct tape_discipline tape_discipline_3590 = {
static struct ccw_device_id tape_3590_ids[] = {
{CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590},
+ {CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592},
{ /* end of list */ }
};
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h
index 2d311798edf4..1fc952359341 100644
--- a/drivers/s390/char/tape_std.h
+++ b/drivers/s390/char/tape_std.h
@@ -153,6 +153,7 @@ enum s390_tape_type {
tape_3480,
tape_3490,
tape_3590,
+ tape_3592,
};
#endif // _TAPE_STD_H
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 6412b2c3edd3..72187e54dcac 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -242,28 +242,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
if (sch->vpm == mask)
goto out_unreg;
- if ((sch->schib.scsw.actl & (SCSW_ACTL_CLEAR_PEND |
- SCSW_ACTL_HALT_PEND |
- SCSW_ACTL_START_PEND |
- SCSW_ACTL_RESUME_PEND)) &&
- (sch->schib.pmcw.lpum == mask)) {
- int cc = cio_cancel(sch);
-
- if (cc == -ENODEV)
- goto out_unreg;
-
- if (cc == -EINVAL) {
- cc = cio_clear(sch);
- if (cc == -ENODEV)
- goto out_unreg;
- /* Call handler. */
- if (sch->driver && sch->driver->termination)
- sch->driver->termination(&sch->dev);
- goto out_unlock;
- }
- } else if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
- (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
- (sch->schib.pmcw.lpum == mask)) {
+ if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
+ (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
+ (sch->schib.pmcw.lpum == mask) &&
+ (sch->vpm == 0)) {
int cc;
cc = cio_clear(sch);
@@ -653,13 +635,13 @@ __chp_add(struct subchannel_id schid, void *data)
if (sch->schib.pmcw.chpid[i] == chp->id) {
if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */
- spin_unlock(&sch->lock);
+ spin_unlock_irq(&sch->lock);
return -ENXIO;
}
break;
}
if (i==8) {
- spin_unlock(&sch->lock);
+ spin_unlock_irq(&sch->lock);
return 0;
}
sch->lpm = ((sch->schib.pmcw.pim &
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 74a257b23383..e210f89a2449 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -45,11 +45,11 @@ struct pgid {
union {
__u8 fc; /* SPID function code */
struct path_state ps; /* SNID path state */
- } inf;
+ } __attribute__ ((packed)) inf;
union {
__u32 cpu_addr : 16; /* CPU address */
struct extended_cssid ext_cssid;
- } pgid_high;
+ } __attribute__ ((packed)) pgid_high;
__u32 cpu_id : 24; /* CPU identification */
__u32 cpu_model : 16; /* CPU model */
__u32 tod_high; /* high word TOD clock */
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 180b3bf8b90d..49ec562d7f60 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -749,7 +749,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* Unit check but no sense data. Need basic sense. */
if (ccw_device_do_sense(cdev, irb) != 0)
goto call_handler_unsol;
- memcpy(irb, &cdev->private->irb, sizeof(struct irb));
+ memcpy(&cdev->private->irb, irb, sizeof(struct irb));
cdev->private->state = DEV_STATE_W4SENSE;
cdev->private->intparm = 0;
return;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 814f9258ce00..96f519281d92 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/timer.h>
+#include <linux/mempool.h>
#include <asm/ccwdev.h>
#include <asm/io.h>
@@ -80,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE];
static __u32 * volatile indicators;
static __u32 volatile spare_indicator;
static atomic_t spare_indicator_usecount;
+#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
+static mempool_t *qdio_mempool_scssc;
static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal;
@@ -1637,7 +1640,7 @@ next:
}
kfree(irq_ptr->qdr);
- kfree(irq_ptr);
+ free_page((unsigned long) irq_ptr);
}
static void
@@ -2304,7 +2307,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
QDIO_DBF_TEXT0(0,setup,"getssqd");
qdioac = 0;
- ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!ssqd_area) {
QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
"SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
@@ -2364,7 +2367,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
out:
qdio_check_subchannel_qebsm(irq_ptr, qdioac,
ssqd_area->sch_token);
- free_page ((unsigned long) ssqd_area);
+ mempool_free(ssqd_area, qdio_mempool_scssc);
irq_ptr->qdioac = qdioac;
}
@@ -2458,7 +2461,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
}
- scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!scssc_area) {
QDIO_PRINT_WARN("No memory for setting indicators on " \
"subchannel 0.%x.%x.\n",
@@ -2514,7 +2517,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long));
result = 0;
out:
- free_page ((unsigned long) scssc_area);
+ mempool_free(scssc_area, qdio_mempool_scssc);
return result;
}
@@ -2543,7 +2546,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
if (!irq_ptr->is_thinint_irq)
return -ENODEV;
- scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!scsscf_area) {
QDIO_PRINT_WARN("No memory for setting delay target on " \
"subchannel 0.%x.%x.\n",
@@ -2581,7 +2584,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long));
result = 0; /* not critical */
out:
- free_page ((unsigned long) scsscf_area);
+ mempool_free(scsscf_area, qdio_mempool_scssc);
return result;
}
@@ -2980,7 +2983,7 @@ qdio_allocate(struct qdio_initialize *init_data)
qdio_allocate_do_dbf(init_data);
/* create irq */
- irq_ptr = kzalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA);
+ irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
QDIO_DBF_TEXT0(0,setup,"irq_ptr:");
QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
@@ -2995,7 +2998,7 @@ qdio_allocate(struct qdio_initialize *init_data)
/* QDR must be in DMA area since CCW data address is only 32 bit */
irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) {
- kfree(irq_ptr);
+ free_page((unsigned long) irq_ptr);
QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
return -ENOMEM;
}
@@ -3780,6 +3783,16 @@ oom:
return -ENOMEM;
}
+static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size)
+{
+ return (void *) get_zeroed_page(gfp_mask|GFP_DMA);
+}
+
+static void qdio_mempool_free(void *element, void *size)
+{
+ free_page((unsigned long) element);
+}
+
static int __init
init_QDIO(void)
{
@@ -3809,6 +3822,10 @@ init_QDIO(void)
qdio_add_procfs_entry();
+ qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS,
+ qdio_mempool_alloc,
+ qdio_mempool_free, NULL);
+
if (tiqdio_check_chsc_availability())
QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n");
@@ -3824,6 +3841,7 @@ cleanup_QDIO(void)
qdio_remove_procfs_entry();
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
+ mempool_destroy(qdio_mempool_scssc);
printk("qdio: %s: module removed\n",version);
}
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 90d4d0ef3dd4..6775a837d646 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -2,7 +2,7 @@
# S/390 network devices
#
-ctc-objs := ctcmain.o ctctty.o ctcdbug.o
+ctc-objs := ctcmain.o ctcdbug.o
obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
@@ -10,6 +10,7 @@ obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
obj-$(CONFIG_CLAW) += claw.o cu3088.o
+obj-$(CONFIG_MPC) += ctcmpc.o fsm.o cu3088.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index af9f212314b3..20c8eb16f464 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -6,7 +6,7 @@
* Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <cornelia.huck@de.ibm.com>
*
* Documentation used:
* - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -65,7 +65,6 @@
#include <asm/idals.h>
-#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
@@ -479,10 +478,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
skb->dev = pskb->dev;
skb->protocol = pskb->protocol;
pskb->ip_summed = CHECKSUM_UNNECESSARY;
- if (ch->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_netif_rx(skb);
- else
- netif_rx_ni(skb);
+ netif_rx_ni(skb);
/**
* Successful rx; reset logflags
*/
@@ -557,8 +553,7 @@ ccw_unit_check(struct channel *ch, unsigned char sense)
DBF_TEXT(trace, 5, __FUNCTION__);
if (sense & SNS0_INTERVENTION_REQ) {
if (sense & 0x01) {
- if (ch->protocol != CTC_PROTO_LINUX_TTY)
- ctc_pr_debug("%s: Interface disc. or Sel. reset "
+ ctc_pr_debug("%s: Interface disc. or Sel. reset "
"(remote)\n", ch->id);
fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
} else {
@@ -1486,13 +1481,13 @@ ch_action_iofatal(fsm_instance * fi, int event, void *arg)
}
}
-static void
+static void
ch_action_reinit(fsm_instance *fi, int event, void *arg)
{
struct channel *ch = (struct channel *)arg;
struct net_device *dev = ch->netdev;
struct ctc_priv *privptr = dev->priv;
-
+
DBF_TEXT(trace, 4, __FUNCTION__);
ch_action_iofatal(fi, event, arg);
fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev);
@@ -1624,7 +1619,7 @@ less_than(char *id1, char *id2)
}
dev1 = simple_strtoul(id1, &id1, 16);
dev2 = simple_strtoul(id2, &id2, 16);
-
+
return (dev1 < dev2);
}
@@ -1895,7 +1890,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
irb->scsw.dstat);
return;
}
-
+
priv = ((struct ccwgroup_device *)cdev->dev.driver_data)
->dev.driver_data;
@@ -1909,7 +1904,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
"device %s\n", cdev->dev.bus_id);
return;
}
-
+
dev = (struct net_device *) (ch->netdev);
if (dev == NULL) {
ctc_pr_crit("ctc: ctc_irq_handler dev=NULL bus_id=%s, ch=0x%p\n",
@@ -2008,12 +2003,12 @@ dev_action_stop(fsm_instance * fi, int event, void *arg)
fsm_event(ch->fsm, CH_EVENT_STOP, ch);
}
}
-static void
+static void
dev_action_restart(fsm_instance *fi, int event, void *arg)
{
struct net_device *dev = (struct net_device *)arg;
struct ctc_priv *privptr = dev->priv;
-
+
DBF_TEXT(trace, 3, __FUNCTION__);
ctc_pr_debug("%s: Restarting\n", dev->name);
dev_action_stop(fi, event, arg);
@@ -2034,7 +2029,6 @@ static void
dev_action_chup(fsm_instance * fi, int event, void *arg)
{
struct net_device *dev = (struct net_device *) arg;
- struct ctc_priv *privptr = dev->priv;
DBF_TEXT(trace, 3, __FUNCTION__);
switch (fsm_getstate(fi)) {
@@ -2049,8 +2043,6 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
fsm_newstate(fi, DEV_STATE_RUNNING);
ctc_pr_info("%s: connected with remote side\n",
dev->name);
- if (privptr->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_setcarrier(dev, 1);
ctc_clear_busy(dev);
}
break;
@@ -2059,8 +2051,6 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
fsm_newstate(fi, DEV_STATE_RUNNING);
ctc_pr_info("%s: connected with remote side\n",
dev->name);
- if (privptr->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_setcarrier(dev, 1);
ctc_clear_busy(dev);
}
break;
@@ -2086,14 +2076,10 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
static void
dev_action_chdown(fsm_instance * fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *) arg;
- struct ctc_priv *privptr = dev->priv;
DBF_TEXT(trace, 3, __FUNCTION__);
switch (fsm_getstate(fi)) {
case DEV_STATE_RUNNING:
- if (privptr->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_setcarrier(dev, 0);
if (event == DEV_EVENT_TXDOWN)
fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
else
@@ -2193,7 +2179,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
DBF_TEXT(trace, 5, __FUNCTION__);
/* we need to acquire the lock for testing the state
- * otherwise we can have an IRQ changing the state to
+ * otherwise we can have an IRQ changing the state to
* TXIDLE after the test but before acquiring the lock.
*/
spin_lock_irqsave(&ch->collect_lock, saveflags);
@@ -2393,12 +2379,10 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
/**
* If channels are not running, try to restart them
- * and throw away packet.
+ * and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev);
- if (privptr->protocol == CTC_PROTO_LINUX_TTY)
- return -EBUSY;
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
@@ -2608,20 +2592,13 @@ ctc_netdev_unregister(struct net_device * dev)
if (!dev)
return;
privptr = (struct ctc_priv *) dev->priv;
- if (privptr->protocol != CTC_PROTO_LINUX_TTY)
- unregister_netdev(dev);
- else
- ctc_tty_unregister_netdev(dev);
+ unregister_netdev(dev);
}
static int
ctc_netdev_register(struct net_device * dev)
{
- struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
- if (privptr->protocol != CTC_PROTO_LINUX_TTY)
- return register_netdev(dev);
- else
- return ctc_tty_register_netdev(dev);
+ return register_netdev(dev);
}
static void
@@ -2667,7 +2644,9 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b
if (!priv)
return -ENODEV;
sscanf(buf, "%u", &value);
- if ((value < 0) || (value > CTC_PROTO_MAX))
+ if (!((value == CTC_PROTO_S390) ||
+ (value == CTC_PROTO_LINUX) ||
+ (value == CTC_PROTO_OS390)))
return -EINVAL;
priv->protocol = value;
@@ -2738,7 +2717,7 @@ ctc_remove_files(struct device *dev)
/**
* Add ctc specific attributes.
* Add ctc private data.
- *
+ *
* @param cgdev pointer to ccwgroup_device just added
*
* @returns 0 on success, !0 on failure.
@@ -2869,7 +2848,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
DBF_TEXT(setup, 3, buffer);
type = get_channel_type(&cgdev->cdev[0]->id);
-
+
snprintf(read_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id);
snprintf(write_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[1]->dev.bus_id);
@@ -2897,17 +2876,14 @@ ctc_new_device(struct ccwgroup_device *cgdev)
goto out;
}
- if (privptr->protocol == CTC_PROTO_LINUX_TTY)
- strlcpy(dev->name, "ctctty%d", IFNAMSIZ);
- else
- strlcpy(dev->name, "ctc%d", IFNAMSIZ);
+ strlcpy(dev->name, "ctc%d", IFNAMSIZ);
for (direction = READ; direction <= WRITE; direction++) {
privptr->channel[direction] =
channel_get(type, direction == READ ? read_id : write_id,
direction);
if (privptr->channel[direction] == NULL) {
- if (direction == WRITE)
+ if (direction == WRITE)
channel_free(privptr->channel[READ]);
ctc_free_netdevice(dev, 1);
@@ -2955,7 +2931,7 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
{
struct ctc_priv *priv;
struct net_device *ndev;
-
+
DBF_TEXT(setup, 3, __FUNCTION__);
pr_debug("%s() called\n", __FUNCTION__);
@@ -3046,7 +3022,6 @@ ctc_exit(void)
{
DBF_TEXT(setup, 3, __FUNCTION__);
unregister_cu3088_discipline(&ctc_group_driver);
- ctc_tty_cleanup();
ctc_unregister_dbf_views();
ctc_pr_info("CTC driver unloaded\n");
}
@@ -3073,10 +3048,8 @@ ctc_init(void)
ctc_pr_crit("ctc_init failed with ctc_register_dbf_views rc = %d\n", ret);
return ret;
}
- ctc_tty_init();
ret = register_cu3088_discipline(&ctc_group_driver);
if (ret) {
- ctc_tty_cleanup();
ctc_unregister_dbf_views();
}
return ret;
diff --git a/drivers/s390/net/ctcmain.h b/drivers/s390/net/ctcmain.h
index d2e835c0c134..7f305d119f3d 100644
--- a/drivers/s390/net/ctcmain.h
+++ b/drivers/s390/net/ctcmain.h
@@ -35,7 +35,9 @@
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
-#include "ctctty.h"
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
#include "fsm.h"
#include "cu3088.h"
@@ -50,9 +52,7 @@
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
-#define CTC_PROTO_LINUX_TTY 2
#define CTC_PROTO_OS390 3
-#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
@@ -257,15 +257,13 @@ static __inline__ void
ctc_clear_busy(struct net_device * dev)
{
clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
- if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
- netif_wake_queue(dev);
+ netif_wake_queue(dev);
}
static __inline__ int
ctc_test_and_set_busy(struct net_device * dev)
{
- if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
- netif_stop_queue(dev);
+ netif_stop_queue(dev);
return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
}
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
deleted file mode 100644
index 5cdcdbf92962..000000000000
--- a/drivers/s390/net/ctctty.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/*
- * CTC / ESCON network driver, tty interface.
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 <linux/config.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include <linux/devfs_fs_kernel.h>
-#include "ctctty.h"
-#include "ctcdbug.h"
-
-#define CTC_TTY_MAJOR 43
-#define CTC_TTY_MAX_DEVICES 64
-
-#define CTC_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
-#define CTC_ASYNC_INITIALIZED 0x80000000 /* port was initialized */
-#define CTC_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */
-#define CTC_ASYNC_CLOSING 0x08000000 /* Serial port is closing */
-#define CTC_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define CTC_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-#define CTC_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
-#define CTC_ASYNC_NETDEV_OPEN 0x0002 /* Underlying netdev is open */
-#define CTC_ASYNC_TX_LINESTAT 0x0004 /* Must send line status */
-#define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
-#define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */
-#define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
-
-/* Private data (similar to async_struct in <linux/serial.h>) */
-typedef struct {
- int magic;
- int flags; /* defined in tty.h */
- int mcr; /* Modem control register */
- int msr; /* Modem status register */
- int lsr; /* Line status register */
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- struct net_device *netdev;
- struct sk_buff_head tx_queue; /* transmit queue */
- struct sk_buff_head rx_queue; /* receive queue */
- struct tty_struct *tty; /* Pointer to corresponding tty */
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
- struct semaphore write_sem;
- struct tasklet_struct tasklet;
- struct timer_list stoptimer;
-} ctc_tty_info;
-
-/* Description of one CTC-tty */
-typedef struct {
- struct tty_driver *ctc_tty_device; /* tty-device */
- ctc_tty_info info[CTC_TTY_MAX_DEVICES]; /* Private data */
-} ctc_tty_driver;
-
-static ctc_tty_driver *driver;
-
-/* Leave this unchanged unless you know what you do! */
-#define MODEM_PARANOIA_CHECK
-#define MODEM_DO_RESTART
-
-#define CTC_TTY_NAME "ctctty"
-
-static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
-static int ctc_tty_shuttingdown = 0;
-
-static spinlock_t ctc_tty_lock;
-
-/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
- * to stuff incoming data directly into a tty's flip-buffer. If the
- * flip buffer is full, the packet gets queued up.
- *
- * Return:
- * 1 = Success
- * 0 = Failure, data has to be buffered and later processed by
- * ctc_tty_readmodem().
- */
-static int
-ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
-{
- int len;
- struct tty_struct *tty;
-
- DBF_TEXT(trace, 5, __FUNCTION__);
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- len = skb->len;
- tty_insert_flip_string(tty, skb->data, len);
- tty_flip_buffer_push(tty);
- kfree_skb(skb);
- return 1;
- }
- }
- return 0;
-}
-
-/* ctc_tty_readmodem() is called periodically from within timer-interrupt.
- * It tries getting received data from the receive queue an stuff it into
- * the tty's flip-buffer.
- */
-static int
-ctc_tty_readmodem(ctc_tty_info *info)
-{
- int ret = 1;
- struct tty_struct *tty;
-
- DBF_TEXT(trace, 5, __FUNCTION__);
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- struct sk_buff *skb;
-
- if ((skb = skb_dequeue(&info->rx_queue))) {
- int len = skb->len;
- tty_insert_flip_string(tty, skb->data, len);
- skb_pull(skb, len);
- tty_flip_buffer_push(tty);
- if (skb->len > 0)
- skb_queue_head(&info->rx_queue, skb);
- else {
- kfree_skb(skb);
- ret = !skb_queue_empty(&info->rx_queue);
- }
- }
- }
- }
- return ret;
-}
-
-void
-ctc_tty_setcarrier(struct net_device *netdev, int on)
-{
- int i;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if ((!driver) || ctc_tty_shuttingdown)
- return;
- for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
- if (driver->info[i].netdev == netdev) {
- ctc_tty_info *info = &driver->info[i];
- if (on)
- info->msr |= UART_MSR_DCD;
- else
- info->msr &= ~UART_MSR_DCD;
- if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
- tty_hangup(info->tty);
- }
-}
-
-void
-ctc_tty_netif_rx(struct sk_buff *skb)
-{
- int i;
- ctc_tty_info *info = NULL;
-
- DBF_TEXT(trace, 5, __FUNCTION__);
- if (!skb)
- return;
- if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
- dev_kfree_skb(skb);
- return;
- }
- for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
- if (driver->info[i].netdev == skb->dev) {
- info = &driver->info[i];
- break;
- }
- if (!info) {
- dev_kfree_skb(skb);
- return;
- }
- if (skb->len < 6) {
- dev_kfree_skb(skb);
- return;
- }
- if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
- dev_kfree_skb(skb);
- return;
- }
- skb_pull(skb, sizeof(__u32));
-
- i = *((int *)skb->data);
- skb_pull(skb, sizeof(info->mcr));
- if (i & UART_MCR_RTS) {
- info->msr |= UART_MSR_CTS;
- if (info->flags & CTC_ASYNC_CTS_FLOW)
- info->tty->hw_stopped = 0;
- } else {
- info->msr &= ~UART_MSR_CTS;
- if (info->flags & CTC_ASYNC_CTS_FLOW)
- info->tty->hw_stopped = 1;
- }
- if (i & UART_MCR_DTR)
- info->msr |= UART_MSR_DSR;
- else
- info->msr &= ~UART_MSR_DSR;
- if (skb->len <= 0) {
- kfree_skb(skb);
- return;
- }
- /* Try to deliver directly via tty-flip-buf if queue is empty */
- if (skb_queue_empty(&info->rx_queue))
- if (ctc_tty_try_read(info, skb))
- return;
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- skb_queue_tail(&info->rx_queue, skb);
- /* Schedule dequeuing */
- tasklet_schedule(&info->tasklet);
-}
-
-static int
-ctc_tty_tint(ctc_tty_info * info)
-{
- struct sk_buff *skb = skb_dequeue(&info->tx_queue);
- int stopped = (info->tty->hw_stopped || info->tty->stopped);
- int wake = 1;
- int rc;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (!info->netdev) {
- if (skb)
- kfree_skb(skb);
- return 0;
- }
- if (info->flags & CTC_ASYNC_TX_LINESTAT) {
- int skb_res = info->netdev->hard_header_len +
- sizeof(info->mcr) + sizeof(__u32);
- /* If we must update line status,
- * create an empty dummy skb and insert it.
- */
- if (skb)
- skb_queue_head(&info->tx_queue, skb);
-
- skb = dev_alloc_skb(skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "ctc_tty: Out of memory in %s%d tint\n",
- CTC_TTY_NAME, info->line);
- return 1;
- }
- skb_reserve(skb, skb_res);
- stopped = 0;
- wake = 0;
- }
- if (!skb)
- return 0;
- if (stopped) {
- skb_queue_head(&info->tx_queue, skb);
- return 1;
- }
-#if 0
- if (skb->len > 0)
- printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
- else
- printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
-#endif
- memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
- memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
- rc = info->netdev->hard_start_xmit(skb, info->netdev);
- if (rc) {
- skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
- if (skb->len > 0)
- skb_queue_head(&info->tx_queue, skb);
- else
- kfree_skb(skb);
- } else {
- struct tty_struct *tty = info->tty;
-
- info->flags &= ~CTC_ASYNC_TX_LINESTAT;
- if (tty) {
- tty_wakeup(tty);
- }
- }
- return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
-}
-
-/************************************************************
- *
- * Modem-functions
- *
- * mostly "stolen" from original Linux-serial.c and friends.
- *
- ************************************************************/
-
-static inline int
-ctc_tty_paranoia_check(ctc_tty_info * info, char *name, const char *routine)
-{
-#ifdef MODEM_PARANOIA_CHECK
- if (!info) {
- printk(KERN_WARNING "ctc_tty: null info_struct for %s in %s\n",
- name, routine);
- return 1;
- }
- if (info->magic != CTC_ASYNC_MAGIC) {
- printk(KERN_WARNING "ctc_tty: bad magic for info struct %s in %s\n",
- name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-static void
-ctc_tty_inject(ctc_tty_info *info, char c)
-{
- int skb_res;
- struct sk_buff *skb;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_shuttingdown)
- return;
- skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
- sizeof(__u32) + 1;
- skb = dev_alloc_skb(skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "ctc_tty: Out of memory in %s%d tx_inject\n",
- CTC_TTY_NAME, info->line);
- return;
- }
- skb_reserve(skb, skb_res);
- *(skb_put(skb, 1)) = c;
- skb_queue_head(&info->tx_queue, skb);
- tasklet_schedule(&info->tasklet);
-}
-
-static void
-ctc_tty_transmit_status(ctc_tty_info *info)
-{
- DBF_TEXT(trace, 5, __FUNCTION__);
- if (ctc_tty_shuttingdown)
- return;
- info->flags |= CTC_ASYNC_TX_LINESTAT;
- tasklet_schedule(&info->tasklet);
-}
-
-static void
-ctc_tty_change_speed(ctc_tty_info * info)
-{
- unsigned int cflag;
- unsigned int quot;
- int i;
-
- DBF_TEXT(trace, 3, __FUNCTION__);
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
-
- quot = i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (quot) {
- info->mcr |= UART_MCR_DTR;
- info->mcr |= UART_MCR_RTS;
- ctc_tty_transmit_status(info);
- } else {
- info->mcr &= ~UART_MCR_DTR;
- info->mcr &= ~UART_MCR_RTS;
- ctc_tty_transmit_status(info);
- return;
- }
-
- /* CTS flow control flag and modem status interrupts */
- if (cflag & CRTSCTS) {
- info->flags |= CTC_ASYNC_CTS_FLOW;
- } else
- info->flags &= ~CTC_ASYNC_CTS_FLOW;
- if (cflag & CLOCAL)
- info->flags &= ~CTC_ASYNC_CHECK_CD;
- else {
- info->flags |= CTC_ASYNC_CHECK_CD;
- }
-}
-
-static int
-ctc_tty_startup(ctc_tty_info * info)
-{
- DBF_TEXT(trace, 3, __FUNCTION__);
- if (info->flags & CTC_ASYNC_INITIALIZED)
- return 0;
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "starting up %s%d ...\n", CTC_TTY_NAME, info->line);
-#endif
- /*
- * Now, initialize the UART
- */
- info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- /*
- * and set the speed of the serial port
- */
- ctc_tty_change_speed(info);
-
- info->flags |= CTC_ASYNC_INITIALIZED;
- if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
- info->netdev->open(info->netdev);
- info->flags |= CTC_ASYNC_NETDEV_OPEN;
- return 0;
-}
-
-static void
-ctc_tty_stopdev(unsigned long data)
-{
- ctc_tty_info *info = (ctc_tty_info *)data;
-
- if ((!info) || (!info->netdev) ||
- (info->flags & CTC_ASYNC_INITIALIZED))
- return;
- info->netdev->stop(info->netdev);
- info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-ctc_tty_shutdown(ctc_tty_info * info)
-{
- DBF_TEXT(trace, 3, __FUNCTION__);
- if (!(info->flags & CTC_ASYNC_INITIALIZED))
- return;
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
-#endif
- info->msr &= ~UART_MSR_RI;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- mod_timer(&info->stoptimer, jiffies + (10 * HZ));
- skb_queue_purge(&info->tx_queue);
- skb_queue_purge(&info->rx_queue);
- info->flags &= ~CTC_ASYNC_INITIALIZED;
-}
-
-/* ctc_tty_write() is the main send-routine. It is called from the upper
- * levels within the kernel to perform sending data. Depending on the
- * online-flag it either directs output to the at-command-interpreter or
- * to the lower level. Additional tasks done here:
- * - If online, check for escape-sequence (+++)
- * - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes.
- * - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed.
- * - If dialing, abort dial.
- */
-static int
-ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count)
-{
- int c;
- int total = 0;
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- DBF_TEXT(trace, 5, __FUNCTION__);
- if (ctc_tty_shuttingdown)
- goto ex;
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write"))
- goto ex;
- if (!tty)
- goto ex;
- if (!info->netdev) {
- total = -ENODEV;
- goto ex;
- }
- while (1) {
- struct sk_buff *skb;
- int skb_res;
-
- c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE;
- if (c <= 0)
- break;
-
- skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
- + sizeof(__u32);
- skb = dev_alloc_skb(skb_res + c);
- if (!skb) {
- printk(KERN_WARNING
- "ctc_tty: Out of memory in %s%d write\n",
- CTC_TTY_NAME, info->line);
- break;
- }
- skb_reserve(skb, skb_res);
- memcpy(skb_put(skb, c), buf, c);
- skb_queue_tail(&info->tx_queue, skb);
- buf += c;
- total += c;
- count -= c;
- }
- if (!skb_queue_empty(&info->tx_queue)) {
- info->lsr &= ~UART_LSR_TEMT;
- tasklet_schedule(&info->tasklet);
- }
-ex:
- DBF_TEXT(trace, 6, __FUNCTION__);
- return total;
-}
-
-static int
-ctc_tty_write_room(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write_room"))
- return 0;
- return CTC_TTY_XMIT_SIZE;
-}
-
-static int
-ctc_tty_chars_in_buffer(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_chars_in_buffer"))
- return 0;
- return 0;
-}
-
-static void
-ctc_tty_flush_buffer(struct tty_struct *tty)
-{
- ctc_tty_info *info;
- unsigned long flags;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (!tty)
- goto ex;
- spin_lock_irqsave(&ctc_tty_lock, flags);
- info = (ctc_tty_info *) tty->driver_data;
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) {
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- goto ex;
- }
- skb_queue_purge(&info->tx_queue);
- info->lsr |= UART_LSR_TEMT;
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- wake_up_interruptible(&tty->write_wait);
- tty_wakeup(tty);
-ex:
- DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__);
- return;
-}
-
-static void
-ctc_tty_flush_chars(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_shuttingdown)
- return;
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars"))
- return;
- if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue))
- return;
- tasklet_schedule(&info->tasklet);
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-ctc_tty_throttle(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_throttle"))
- return;
- info->mcr &= ~UART_MCR_RTS;
- if (I_IXOFF(tty))
- ctc_tty_inject(info, STOP_CHAR(tty));
- ctc_tty_transmit_status(info);
-}
-
-static void
-ctc_tty_unthrottle(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_unthrottle"))
- return;
- info->mcr |= UART_MCR_RTS;
- if (I_IXOFF(tty))
- ctc_tty_inject(info, START_CHAR(tty));
- ctc_tty_transmit_status(info);
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*
- * ctc_tty_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows RS485 driver to be written in user space.
- */
-static int
-ctc_tty_get_lsr_info(ctc_tty_info * info, uint __user *value)
-{
- u_char status;
- uint result;
- ulong flags;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- spin_lock_irqsave(&ctc_tty_lock, flags);
- status = info->lsr;
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_user(result, value);
- return 0;
-}
-
-
-static int ctc_tty_tiocmget(struct tty_struct *tty, struct file *file)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
- u_char control,
- status;
- uint result;
- ulong flags;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
- return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- control = info->mcr;
- spin_lock_irqsave(&ctc_tty_lock, flags);
- status = info->msr;
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- return result;
-}
-
-static int
-ctc_tty_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
- return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR)
- info->mcr |= UART_MCR_DTR;
-
- if (clear & TIOCM_RTS)
- info->mcr &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR)
- info->mcr &= ~UART_MCR_DTR;
-
- if ((set | clear) & (TIOCM_RTS|TIOCM_DTR))
- ctc_tty_transmit_status(info);
- return 0;
-}
-
-static int
-ctc_tty_ioctl(struct tty_struct *tty, struct file *file,
- uint cmd, ulong arg)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
- int error;
- int retval;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
- return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
- case TIOCGSOFTCAR:
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME,
- info->line);
-#endif
- error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
- return error;
- case TIOCSSOFTCAR:
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME,
- info->line);
-#endif
- error = get_user(arg, (ulong __user *) arg);
- if (error)
- return error;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
- case TIOCSERGETLSR: /* Get line status register */
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
- info->line);
-#endif
- if (access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(uint)))
- return ctc_tty_get_lsr_info(info, (uint __user *) arg);
- else
- return -EFAULT;
- default:
-#ifdef CTC_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd,
- CTC_TTY_NAME, info->line);
-#endif
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void
-ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- ctc_tty_change_speed(info);
-
- /* Handle transition to B0 */
- if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
- info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
- ctc_tty_transmit_status(info);
- }
-
- /* Handle transition from B0 to other */
- if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
- info->mcr |= UART_MCR_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
- info->mcr |= UART_MCR_RTS;
- }
- ctc_tty_transmit_status(info);
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS))
- tty->hw_stopped = 0;
-}
-
-/*
- * ------------------------------------------------------------
- * ctc_tty_open() and friends
- * ------------------------------------------------------------
- */
-static int
-ctc_tty_block_til_ready(struct tty_struct *tty, struct file *filp, ctc_tty_info *info)
-{
- DECLARE_WAITQUEUE(wait, NULL);
- int do_clocal = 0;
- unsigned long flags;
- int retval;
-
- DBF_TEXT(trace, 4, __FUNCTION__);
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & CTC_ASYNC_CLOSING)) {
- if (info->flags & CTC_ASYNC_CLOSING)
- wait_event(info->close_wait,
- !(info->flags & CTC_ASYNC_CLOSING));
-#ifdef MODEM_DO_RESTART
- if (info->flags & CTC_ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
- return 0;
- }
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * ctc_tty_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_block_til_ready before block: %s%d, count = %d\n",
- CTC_TTY_NAME, info->line, info->count);
-#endif
- spin_lock_irqsave(&ctc_tty_lock, flags);
- if (!(tty_hung_up_p(filp)))
- info->count--;
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- info->blocked_open++;
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & CTC_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
- if (info->flags & CTC_ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & CTC_ASYNC_CLOSING) &&
- (do_clocal || (info->msr & UART_MSR_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_block_til_ready blocking: %s%d, count = %d\n",
- CTC_TTY_NAME, info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_block_til_ready after blocking: %s%d, count = %d\n",
- CTC_TTY_NAME, info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= CTC_ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int
-ctc_tty_open(struct tty_struct *tty, struct file *filp)
-{
- ctc_tty_info *info;
- unsigned long saveflags;
- int retval,
- line;
-
- DBF_TEXT(trace, 3, __FUNCTION__);
- line = tty->index;
- if (line < 0 || line > CTC_TTY_MAX_DEVICES)
- return -ENODEV;
- info = &driver->info[line];
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_open"))
- return -ENODEV;
- if (!info->netdev)
- return -ENODEV;
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_open %s, count = %d\n", tty->name,
- info->count);
-#endif
- spin_lock_irqsave(&ctc_tty_lock, saveflags);
- info->count++;
- tty->driver_data = info;
- info->tty = tty;
- spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
- /*
- * Start up serial port
- */
- retval = ctc_tty_startup(info);
- if (retval) {
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_open return after startup\n");
-#endif
- return retval;
- }
- retval = ctc_tty_block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n");
-#endif
- return retval;
- }
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_open %s successful...\n", tty->name);
-#endif
- return 0;
-}
-
-static void
-ctc_tty_close(struct tty_struct *tty, struct file *filp)
-{
- ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
- ulong flags;
- ulong timeout;
- DBF_TEXT(trace, 3, __FUNCTION__);
- if (!info || ctc_tty_paranoia_check(info, tty->name, "ctc_tty_close"))
- return;
- spin_lock_irqsave(&ctc_tty_lock, flags);
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n");
-#endif
- return;
- }
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
- if (--info->count < 0) {
- printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n",
- CTC_TTY_NAME, info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- local_irq_restore(flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n");
-#endif
- return;
- }
- info->flags |= CTC_ASYNC_CLOSING;
- tty->closing = 1;
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- if (info->flags & CTC_ASYNC_INITIALIZED) {
- tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies + HZ;
- while (!(info->lsr & UART_LSR_TEMT)) {
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
- msleep(500);
- spin_lock_irqsave(&ctc_tty_lock, flags);
- if (time_after(jiffies,timeout))
- break;
- }
- }
- ctc_tty_shutdown(info);
- if (tty->driver->flush_buffer) {
- skb_queue_purge(&info->tx_queue);
- info->lsr |= UART_LSR_TEMT;
- }
- tty_ldisc_flush(tty);
- info->tty = 0;
- tty->closing = 0;
- if (info->blocked_open) {
- msleep_interruptible(500);
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
- spin_unlock_irqrestore(&ctc_tty_lock, flags);
-#ifdef CTC_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "ctc_tty_close normal exit\n");
-#endif
-}
-
-/*
- * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void
-ctc_tty_hangup(struct tty_struct *tty)
-{
- ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
- unsigned long saveflags;
- DBF_TEXT(trace, 3, __FUNCTION__);
- if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_hangup"))
- return;
- ctc_tty_shutdown(info);
- info->count = 0;
- info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
- spin_lock_irqsave(&ctc_tty_lock, saveflags);
- info->tty = 0;
- spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
- wake_up_interruptible(&info->open_wait);
-}
-
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-static void
-ctc_tty_task(unsigned long arg)
-{
- ctc_tty_info *info = (void *)arg;
- unsigned long saveflags;
- int again;
-
- DBF_TEXT(trace, 3, __FUNCTION__);
- spin_lock_irqsave(&ctc_tty_lock, saveflags);
- if ((!ctc_tty_shuttingdown) && info) {
- again = ctc_tty_tint(info);
- if (!again)
- info->lsr |= UART_LSR_TEMT;
- again |= ctc_tty_readmodem(info);
- if (again) {
- tasklet_schedule(&info->tasklet);
- }
- }
- spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-}
-
-static struct tty_operations ctc_ops = {
- .open = ctc_tty_open,
- .close = ctc_tty_close,
- .write = ctc_tty_write,
- .flush_chars = ctc_tty_flush_chars,
- .write_room = ctc_tty_write_room,
- .chars_in_buffer = ctc_tty_chars_in_buffer,
- .flush_buffer = ctc_tty_flush_buffer,
- .ioctl = ctc_tty_ioctl,
- .throttle = ctc_tty_throttle,
- .unthrottle = ctc_tty_unthrottle,
- .set_termios = ctc_tty_set_termios,
- .hangup = ctc_tty_hangup,
- .tiocmget = ctc_tty_tiocmget,
- .tiocmset = ctc_tty_tiocmset,
-};
-
-int
-ctc_tty_init(void)
-{
- int i;
- ctc_tty_info *info;
- struct tty_driver *device;
-
- DBF_TEXT(trace, 2, __FUNCTION__);
- driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
- if (driver == NULL) {
- printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
- return -ENOMEM;
- }
- memset(driver, 0, sizeof(ctc_tty_driver));
- device = alloc_tty_driver(CTC_TTY_MAX_DEVICES);
- if (!device) {
- kfree(driver);
- printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
- return -ENOMEM;
- }
-
- device->devfs_name = "ctc/" CTC_TTY_NAME;
- device->name = CTC_TTY_NAME;
- device->major = CTC_TTY_MAJOR;
- device->minor_start = 0;
- device->type = TTY_DRIVER_TYPE_SERIAL;
- device->subtype = SERIAL_TYPE_NORMAL;
- device->init_termios = tty_std_termios;
- device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- device->flags = TTY_DRIVER_REAL_RAW;
- device->driver_name = "ctc_tty",
- tty_set_operations(device, &ctc_ops);
- if (tty_register_driver(device)) {
- printk(KERN_WARNING "ctc_tty: Couldn't register serial-device\n");
- put_tty_driver(device);
- kfree(driver);
- return -1;
- }
- driver->ctc_tty_device = device;
- for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
- info = &driver->info[i];
- init_MUTEX(&info->write_sem);
- tasklet_init(&info->tasklet, ctc_tty_task,
- (unsigned long) info);
- info->magic = CTC_ASYNC_MAGIC;
- info->line = i;
- info->tty = 0;
- info->count = 0;
- info->blocked_open = 0;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- skb_queue_head_init(&info->tx_queue);
- skb_queue_head_init(&info->rx_queue);
- init_timer(&info->stoptimer);
- info->stoptimer.function = ctc_tty_stopdev;
- info->stoptimer.data = (unsigned long)info;
- info->mcr = UART_MCR_RTS;
- }
- return 0;
-}
-
-int
-ctc_tty_register_netdev(struct net_device *dev) {
- int ttynum;
- char *err;
- char *p;
-
- DBF_TEXT(trace, 2, __FUNCTION__);
- if ((!dev) || (!dev->name)) {
- printk(KERN_WARNING
- "ctc_tty_register_netdev called "
- "with NULL dev or NULL dev-name\n");
- return -1;
- }
-
- /*
- * If the name is a format string the caller wants us to
- * do a name allocation : format string must end with %d
- */
- if (strchr(dev->name, '%'))
- {
- int err = dev_alloc_name(dev, dev->name); // dev->name is changed by this
- if (err < 0) {
- printk(KERN_DEBUG "dev_alloc returned error %d\n", err);
- return err;
- }
-
- }
-
- for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++);
- ttynum = simple_strtoul(p, &err, 0);
- if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) ||
- (err && *err)) {
- printk(KERN_WARNING
- "ctc_tty_register_netdev called "
- "with number in name '%s'\n", dev->name);
- return -1;
- }
- if (driver->info[ttynum].netdev) {
- printk(KERN_WARNING
- "ctc_tty_register_netdev called "
- "for already registered device '%s'\n",
- dev->name);
- return -1;
- }
- driver->info[ttynum].netdev = dev;
- return 0;
-}
-
-void
-ctc_tty_unregister_netdev(struct net_device *dev) {
- int i;
- unsigned long saveflags;
- ctc_tty_info *info = NULL;
-
- DBF_TEXT(trace, 2, __FUNCTION__);
- spin_lock_irqsave(&ctc_tty_lock, saveflags);
- for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
- if (driver->info[i].netdev == dev) {
- info = &driver->info[i];
- break;
- }
- if (info) {
- info->netdev = NULL;
- skb_queue_purge(&info->tx_queue);
- skb_queue_purge(&info->rx_queue);
- }
- spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
-}
-
-void
-ctc_tty_cleanup(void) {
- unsigned long saveflags;
-
- DBF_TEXT(trace, 2, __FUNCTION__);
- spin_lock_irqsave(&ctc_tty_lock, saveflags);
- ctc_tty_shuttingdown = 1;
- spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
- tty_unregister_driver(driver->ctc_tty_device);
- put_tty_driver(driver->ctc_tty_device);
- kfree(driver);
- driver = NULL;
-}
diff --git a/drivers/s390/net/ctctty.h b/drivers/s390/net/ctctty.h
deleted file mode 100644
index 7254dc006311..000000000000
--- a/drivers/s390/net/ctctty.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * CTC / ESCON network driver, tty interface.
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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.
- */
-
-#ifndef _CTCTTY_H_
-#define _CTCTTY_H_
-
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-extern int ctc_tty_register_netdev(struct net_device *);
-extern void ctc_tty_unregister_netdev(struct net_device *);
-extern void ctc_tty_netif_rx(struct sk_buff *);
-extern int ctc_tty_init(void);
-extern void ctc_tty_cleanup(void);
-extern void ctc_tty_setcarrier(struct net_device *, int);
-
-#endif
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index b12533104c1f..e965f03a7291 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -20,7 +20,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
@@ -77,7 +77,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
int len;
if (!(end = strchr(start, delim[i])))
- return count;
+ return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
strlcpy (bus_ids[i], start, len);
argv[i] = bus_ids[i];
@@ -94,7 +94,7 @@ static DRIVER_ATTR(group, 0200, NULL, group_write);
/* Register-unregister for ctc&lcs */
int
-register_cu3088_discipline(struct ccwgroup_driver *dcp)
+register_cu3088_discipline(struct ccwgroup_driver *dcp)
{
int rc;
@@ -109,7 +109,7 @@ register_cu3088_discipline(struct ccwgroup_driver *dcp)
rc = driver_create_file(&dcp->driver, &driver_attr_group);
if (rc)
ccwgroup_driver_unregister(dcp);
-
+
return rc;
}
@@ -137,7 +137,7 @@ static int __init
cu3088_init (void)
{
int rc;
-
+
cu3088_root_dev = s390_root_dev_register("cu3088");
if (IS_ERR(cu3088_root_dev))
return PTR_ERR(cu3088_root_dev);
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
index 6190be9dca99..e0c7deb98831 100644
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -1,4 +1,4 @@
-/*
+/*
* IUCV network driver
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -28,7 +28,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-
+
/* #define DEBUG */
#include <linux/module.h>
@@ -81,7 +81,7 @@ iucv_bus_match (struct device *dev, struct device_driver *drv)
struct bus_type iucv_bus = {
.name = "iucv",
.match = iucv_bus_match,
-};
+};
struct device *iucv_root;
@@ -297,7 +297,7 @@ MODULE_LICENSE("GPL");
/*
* Debugging stuff
*******************************************************************************/
-
+
#ifdef DEBUG
static int debuglevel = 0;
@@ -344,7 +344,7 @@ do { \
/*
* Internal functions
*******************************************************************************/
-
+
/**
* print start banner
*/
@@ -810,7 +810,7 @@ iucv_register_program (__u8 pgmname[16],
sizeof (new_handler->id.userid));
EBC_TOUPPER (new_handler->id.userid,
sizeof (new_handler->id.userid));
-
+
if (pgmmask) {
memcpy (new_handler->id.mask, pgmmask,
sizeof (new_handler->id.mask));
@@ -1229,7 +1229,7 @@ iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
/* parm->ipaudit has only 3 bytes */
*audit >>= 8;
}
-
+
release_param(parm);
iucv_debug(1, "b2f0_result = %ld", b2f0_result);
@@ -2330,14 +2330,14 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
temp_buff1[j] &= (h->id.mask)[j];
temp_buff2[j] &= (h->id.mask)[j];
}
-
+
iucv_dumpit("temp_buff1:",
temp_buff1, sizeof(temp_buff1));
iucv_dumpit("temp_buff2",
temp_buff2, sizeof(temp_buff2));
-
+
if (!memcmp (temp_buff1, temp_buff2, 24)) {
-
+
iucv_debug(2,
"found a matching handler");
break;
@@ -2368,7 +2368,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
-
+
case 0x02: /*connection complete */
if (messagesDisabled) {
iucv_setmask(~0);
@@ -2387,7 +2387,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
-
+
case 0x03: /* connection severed */
if (messagesDisabled) {
iucv_setmask(~0);
@@ -2398,13 +2398,13 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
interrupt->ConnectionSevered(
(iucv_ConnectionSevered *)int_buf,
h->pgm_data);
-
+
else
iucv_sever (int_buf->ippathid, no_listener);
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
-
+
case 0x04: /* connection quiesced */
if (messagesDisabled) {
iucv_setmask(~0);
@@ -2420,7 +2420,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
"ConnectionQuiesced not called");
}
break;
-
+
case 0x05: /* connection resumed */
if (messagesDisabled) {
iucv_setmask(~0);
@@ -2436,7 +2436,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
"ConnectionResumed not called");
}
break;
-
+
case 0x06: /* priority message complete */
case 0x07: /* nonpriority message complete */
if (h) {
@@ -2449,7 +2449,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
"MessageComplete not called");
}
break;
-
+
case 0x08: /* priority message pending */
case 0x09: /* nonpriority message pending */
if (h) {
@@ -2467,7 +2467,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
__FUNCTION__);
break;
} /* end switch */
-
+
iucv_debug(2, "exiting pathid %d, type %02X",
int_buf->ippathid, int_buf->iptype);
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
index 0c4644d3d2f3..5b6b1b7241c9 100644
--- a/drivers/s390/net/iucv.h
+++ b/drivers/s390/net/iucv.h
@@ -4,7 +4,7 @@
*
* S390 version
* Copyright (C) 2000 IBM Corporation
- * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
+ * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
* Xenia Tkatschow (xenia@us.ibm.com)
*
*
@@ -16,17 +16,17 @@
* CP Programming Services book, also available on the web
* thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
*
- * Definition of Return Codes
- * -All positive return codes including zero are reflected back
- * from CP except for iucv_register_program. The definition of each
- * return code can be found in CP Programming Services book.
- * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- * - Return Code of:
- * (-EINVAL) Invalid value
- * (-ENOMEM) storage allocation failed
+ * Definition of Return Codes
+ * -All positive return codes including zero are reflected back
+ * from CP except for iucv_register_program. The definition of each
+ * return code can be found in CP Programming Services book.
+ * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ * - Return Code of:
+ * (-EINVAL) Invalid value
+ * (-ENOMEM) storage allocation failed
* pgmask defined in iucv_register_program will be set depending on input
- * paramters.
- *
+ * paramters.
+ *
*/
#include <linux/types.h>
@@ -124,13 +124,13 @@ iucv_hex_dump(unsigned char *buf, size_t len)
#define iucv_handle_t void *
/* flags1:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPLOCAL - Indicates the connect can only be satisfied on the
- * local system
- * IPPRTY - Indicates a priority message
- * IPQUSCE - Indicates you do not want to receive messages on a
- * path until an iucv_resume is issued
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPLOCAL - Indicates the connect can only be satisfied on the
+ * local system
+ * IPPRTY - Indicates a priority message
+ * IPQUSCE - Indicates you do not want to receive messages on a
+ * path until an iucv_resume is issued
* IPRMDATA - Indicates that the message is in the parameter list
*/
#define IPLOCAL 0x01
@@ -154,14 +154,14 @@ iucv_hex_dump(unsigned char *buf, size_t len)
#define AllInterrupts 0xf8
/*
* Mapping of external interrupt buffers should be used with the corresponding
- * interrupt types.
- * Names: iucv_ConnectionPending -> connection pending
+ * interrupt types.
+ * Names: iucv_ConnectionPending -> connection pending
* iucv_ConnectionComplete -> connection complete
- * iucv_ConnectionSevered -> connection severed
- * iucv_ConnectionQuiesced -> connection quiesced
- * iucv_ConnectionResumed -> connection resumed
- * iucv_MessagePending -> message pending
- * iucv_MessageComplete -> message complete
+ * iucv_ConnectionSevered -> connection severed
+ * iucv_ConnectionQuiesced -> connection quiesced
+ * iucv_ConnectionResumed -> connection resumed
+ * iucv_MessagePending -> message pending
+ * iucv_MessageComplete -> message complete
*/
typedef struct {
u16 ippathid;
@@ -260,16 +260,16 @@ typedef struct {
uchar res2[3];
} iucv_MessageComplete;
-/*
- * iucv_interrupt_ops_t: Is a vector of functions that handle
- * IUCV interrupts.
- * Parameter list:
- * eib - is a pointer to a 40-byte area described
- * with one of the structures above.
- * pgm_data - this data is strictly for the
- * interrupt handler that is passed by
- * the application. This may be an address
- * or token.
+/*
+ * iucv_interrupt_ops_t: Is a vector of functions that handle
+ * IUCV interrupts.
+ * Parameter list:
+ * eib - is a pointer to a 40-byte area described
+ * with one of the structures above.
+ * pgm_data - this data is strictly for the
+ * interrupt handler that is passed by
+ * the application. This may be an address
+ * or token.
*/
typedef struct {
void (*ConnectionPending) (iucv_ConnectionPending * eib,
@@ -287,8 +287,8 @@ typedef struct {
} iucv_interrupt_ops_t;
/*
- *iucv_array_t : Defines buffer array.
- * Inside the array may be 31- bit addresses and 31-bit lengths.
+ *iucv_array_t : Defines buffer array.
+ * Inside the array may be 31- bit addresses and 31-bit lengths.
*/
typedef struct {
u32 address;
@@ -299,19 +299,19 @@ extern struct bus_type iucv_bus;
extern struct device *iucv_root;
/* -prototypes- */
-/*
- * Name: iucv_register_program
- * Purpose: Registers an application with IUCV
- * Input: prmname - user identification
+/*
+ * Name: iucv_register_program
+ * Purpose: Registers an application with IUCV
+ * Input: prmname - user identification
* userid - machine identification
* pgmmask - indicates which bits in the prmname and userid combined will be
* used to determine who is given control
- * ops - address of vector of interrupt handlers
- * pgm_data- application data passed to interrupt handlers
- * Output: NA
- * Return: address of handler
+ * ops - address of vector of interrupt handlers
+ * pgm_data- application data passed to interrupt handlers
+ * Output: NA
+ * Return: address of handler
* (0) - Error occurred, registration not completed.
- * NOTE: Exact cause of failure will be recorded in syslog.
+ * NOTE: Exact cause of failure will be recorded in syslog.
*/
iucv_handle_t iucv_register_program (uchar pgmname[16],
uchar userid[8],
@@ -319,13 +319,13 @@ iucv_handle_t iucv_register_program (uchar pgmname[16],
iucv_interrupt_ops_t * ops,
void *pgm_data);
-/*
- * Name: iucv_unregister_program
- * Purpose: Unregister application with IUCV
- * Input: address of handler
- * Output: NA
- * Return: (0) - Normal return
- * (-EINVAL) - Internal error, wild pointer
+/*
+ * Name: iucv_unregister_program
+ * Purpose: Unregister application with IUCV
+ * Input: address of handler
+ * Output: NA
+ * Return: (0) - Normal return
+ * (-EINVAL) - Internal error, wild pointer
*/
int iucv_unregister_program (iucv_handle_t handle);
@@ -333,7 +333,7 @@ int iucv_unregister_program (iucv_handle_t handle);
* Name: iucv_accept
* Purpose: This function is issued after the user receives a Connection Pending external
* interrupt and now wishes to complete the IUCV communication path.
- * Input: pathid - u16 , Path identification number
+ * Input: pathid - u16 , Path identification number
* msglim_reqstd - u16, The number of outstanding messages requested.
* user_data - uchar[16], Data specified by the iucv_connect function.
* flags1 - int, Contains options for this path.
@@ -358,34 +358,34 @@ int iucv_accept (u16 pathid,
void *pgm_data, int *flags1_out, u16 * msglim);
/*
- * Name: iucv_connect
+ * Name: iucv_connect
* Purpose: This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Input: pathid - u16 *, Path identification number
- * msglim_reqstd - u16, Number of outstanding messages requested
- * user_data - uchar[16], 16-byte user data
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ * Input: pathid - u16 *, Path identification number
+ * msglim_reqstd - u16, Number of outstanding messages requested
+ * user_data - uchar[16], 16-byte user data
* userid - uchar[8], User identification
- * system_name - uchar[8], 8-byte identifying the system name
+ * system_name - uchar[8], 8-byte identifying the system name
* flags1 - int, Contains options for this path.
* -IPPRTY - 0x20, Specifies if you want to send priority message.
* -IPRMDATA - 0x80, Specifies whether your program can handle a message
* in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
* established.
- * -IPLOCAL - 0X01, Allows an application to force the partner to be on
+ * -IPLOCAL - 0X01, Allows an application to force the partner to be on
* the local system. If local is specified then target class cannot be
- * specified.
+ * specified.
* flags1_out - int * Contains information about the path
* - IPPRTY - 0x20, Indicates you may send priority messages.
* msglim - * u16, Number of outstanding messages
- * handle - iucv_handle_t, Address of handler
- * pgm_data - void *, Application data passed to interrupt handlers
+ * handle - iucv_handle_t, Address of handler
+ * pgm_data - void *, Application data passed to interrupt handlers
* Output: return code from CP IUCV call
* rc - return code from iucv_declare_buffer
- * -EINVAL - Invalid handle passed by application
- * -EINVAL - Pathid address is NULL
- * add_pathid_result - Return code from internal function add_pathid
+ * -EINVAL - Invalid handle passed by application
+ * -EINVAL - Pathid address is NULL
+ * add_pathid_result - Return code from internal function add_pathid
*/
int
iucv_connect (u16 * pathid,
@@ -397,16 +397,16 @@ int
int *flags1_out,
u16 * msglim, iucv_handle_t handle, void *pgm_data);
-/*
- * Name: iucv_purge
- * Purpose: This function cancels a message that you have sent.
- * Input: pathid - Path identification number.
+/*
+ * Name: iucv_purge
+ * Purpose: This function cancels a message that you have sent.
+ * Input: pathid - Path identification number.
* msgid - Specifies the message ID of the message to be purged.
- * srccls - Specifies the source message class.
- * Output: audit - Contains information about asynchronous error
- * that may have affected the normal completion
- * of this message.
- * Return: Return code from CP IUCV call.
+ * srccls - Specifies the source message class.
+ * Output: audit - Contains information about asynchronous error
+ * that may have affected the normal completion
+ * of this message.
+ * Return: Return code from CP IUCV call.
*/
int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
/*
@@ -426,38 +426,38 @@ ulong iucv_query_maxconn (void);
*/
ulong iucv_query_bufsize (void);
-/*
- * Name: iucv_quiesce
- * Purpose: This function temporarily suspends incoming messages on an
- * IUCV path. You can later reactivate the path by invoking
- * the iucv_resume function.
- * Input: pathid - Path identification number
- * user_data - 16-bytes of user data
- * Output: NA
- * Return: Return code from CP IUCV call.
+/*
+ * Name: iucv_quiesce
+ * Purpose: This function temporarily suspends incoming messages on an
+ * IUCV path. You can later reactivate the path by invoking
+ * the iucv_resume function.
+ * Input: pathid - Path identification number
+ * user_data - 16-bytes of user data
+ * Output: NA
+ * Return: Return code from CP IUCV call.
*/
int iucv_quiesce (u16 pathid, uchar user_data[16]);
-/*
- * Name: iucv_receive
- * Purpose: This function receives messages that are being sent to you
+/*
+ * Name: iucv_receive
+ * Purpose: This function receives messages that are being sent to you
* over established paths. Data will be returned in buffer for length of
* buflen.
- * Input:
- * pathid - Path identification number.
- * buffer - Address of buffer to receive.
- * buflen - Length of buffer to receive.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output:
+ * Input:
+ * pathid - Path identification number.
+ * buffer - Address of buffer to receive.
+ * buflen - Length of buffer to receive.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * Output:
* flags1_out: int *, Contains information about this path.
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
+ * expected.
+ * IPPRTY - 0x20 Specifies if you want to send priority message.
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
* residual_buffer - address of buffer updated by the number
* of bytes you have received.
- * residual_length -
+ * residual_length -
* Contains one of the following values, if the receive buffer is:
* The same length as the message, this field is zero.
* Longer than the message, this field contains the number of
@@ -466,8 +466,8 @@ int iucv_quiesce (u16 pathid, uchar user_data[16]);
* count (that is, the number of bytes remaining in the
* message that does not fit into the buffer. In this
* case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - buffer address is pointing to NULL
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - buffer address is pointing to NULL
*/
int iucv_receive (u16 pathid,
u32 msgid,
@@ -477,16 +477,16 @@ int iucv_receive (u16 pathid,
int *flags1_out,
ulong * residual_buffer, ulong * residual_length);
- /*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
+ /*
+ * Name: iucv_receive_array
+ * Purpose: This function receives messages that are being sent to you
* over established paths. Data will be returned in first buffer for
* length of first buffer.
- * Input: pathid - Path identification number.
+ * Input: pathid - Path identification number.
* msgid - specifies the message ID.
* trgcls - Specifies target class.
- * buffer - Address of array of buffers.
- * buflen - Total length of buffers.
+ * buffer - Address of array of buffers.
+ * buflen - Total length of buffers.
* Output:
* flags1_out: int *, Contains information about this path.
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
@@ -504,8 +504,8 @@ int iucv_receive (u16 pathid,
* count (that is, the number of bytes remaining in the
* message that does not fit into the buffer. In this
* case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_receive_array (u16 pathid,
u32 msgid,
@@ -515,44 +515,44 @@ int iucv_receive_array (u16 pathid,
int *flags1_out,
ulong * residual_buffer, ulong * residual_length);
-/*
- * Name: iucv_reject
- * Purpose: The reject function refuses a specified message. Between the
- * time you are notified of a message and the time that you
- * complete the message, the message may be rejected.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output: NA
- * Return: Return code from CP IUCV call.
+/*
+ * Name: iucv_reject
+ * Purpose: The reject function refuses a specified message. Between the
+ * time you are notified of a message and the time that you
+ * complete the message, the message may be rejected.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
*/
int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
+/*
+ * Name: iucv_reply
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
* flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of reply buffer.
- * buflen - Length of reply buffer.
- * Output: residual_buffer - Address of buffer updated by the number
- * of bytes you have moved.
+ * IPPRTY- 0x20, Specifies if you want to send priority message.
+ * buffer - Address of reply buffer.
+ * buflen - Length of reply buffer.
+ * Output: residual_buffer - Address of buffer updated by the number
+ * of bytes you have moved.
* residual_length - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
* contains zero.
* If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
+ * the number of bytes remaining in the buffer.
* If the answer buffer is shorter than the reply, this field contains
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_reply (u16 pathid,
u32 msgid,
@@ -561,20 +561,20 @@ int iucv_reply (u16 pathid,
void *buffer, ulong buflen, ulong * residual_buffer,
ulong * residual_length);
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - Path identification number
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
+/*
+ * Name: iucv_reply_array
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * The array identifies a list of addresses and lengths of
+ * discontiguous buffers that contains the reply data.
+ * Input: pathid - Path identification number
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
* flags1 - Option for path.
* IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of array of reply buffers.
- * buflen - Total length of reply buffers.
+ * buffer - Address of array of reply buffers.
+ * buflen - Total length of reply buffers.
* Output: residual_buffer - Address of buffer which IUCV is currently working on.
* residual_length - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
@@ -585,8 +585,8 @@ int iucv_reply (u16 pathid,
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_reply_array (u16 pathid,
u32 msgid,
@@ -596,77 +596,77 @@ int iucv_reply_array (u16 pathid,
ulong buflen, ulong * residual_address,
ulong * residual_length);
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
+/*
+ * Name: iucv_reply_prmmsg
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Prmmsg signifies the data is moved into the
+ * parameter list.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter.
- * list.
- * Output: NA
- * Return: Return code from CP IUCV call.
+ * prmmsg - 8-bytes of data to be placed into the parameter.
+ * list.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
*/
int iucv_reply_prmmsg (u16 pathid,
u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
-/*
- * Name: iucv_resume
- * Purpose: This function restores communications over a quiesced path
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
+/*
+ * Name: iucv_resume
+ * Purpose: This function restores communications over a quiesced path
+ * Input: pathid - Path identification number.
+ * user_data - 16-bytes of user data.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
*/
int iucv_resume (u16 pathid, uchar user_data[16]);
-/*
- * Name: iucv_send
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer and this is a
- * one-way message and the receiver will not reply to the
- * message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
+/*
+ * Name: iucv_send
+ * Purpose: This function transmits data to another application.
+ * Data to be transmitted is in a buffer and this is a
+ * one-way message and the receiver will not reply to the
+ * message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * buffer - Address of send buffer.
+ * buflen - Length of send buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_send (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
+/*
+ * Name: iucv_send_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated witht the message.
* flags1 - Option for path.
- * IPPRTY- specifies if you want to send priority message.
- * buffer - Address of array of send buffers.
- * buflen - Total length of send buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * IPPRTY- specifies if you want to send priority message.
+ * buffer - Address of array of send buffers.
+ * buflen - Total length of send buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_send_array (u16 pathid,
u32 * msgid,
@@ -675,48 +675,48 @@ int iucv_send_array (u16 pathid,
u32 msgtag,
int flags1, iucv_array_t * buffer, ulong buflen);
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
+/*
+ * Name: iucv_send_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into parameter list.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
+ * prmmsg - 8-bytes of data to be placed into parameter list.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
*/
int iucv_send_prmmsg (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag associated with the message.
+/*
+ * Name: iucv_send2way
+ * Purpose: This function transmits data to another application.
+ * Data to be transmitted is in a buffer. The receiver
+ * of the send is expected to reply to the message and
+ * a buffer is provided into which IUCV moves the reply
+ * to this message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer or ansbuf address is NULL.
+ * buffer - Address of send buffer.
+ * buflen - Length of send buffer.
+ * ansbuf - Address of buffer into which IUCV moves the reply of
+ * this message.
+ * anslen - Address of length of buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer or ansbuf address is NULL.
*/
int iucv_send2way (u16 pathid,
u32 * msgid,
@@ -726,28 +726,28 @@ int iucv_send2way (u16 pathid,
int flags1,
void *buffer, ulong buflen, void *ansbuf, ulong anslen);
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
+/*
+ * Name: iucv_send2way_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which
+ * IUCV moves the reply to this message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Sddress of array of send buffers.
- * buflen - Total length of send buffers.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * buffer - Sddress of array of send buffers.
+ * buflen - Total length of send buffers.
+ * ansbuf - Address of array of buffer into which IUCV moves the reply
+ * of this message.
+ * anslen - Address of length reply buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_send2way_array (u16 pathid,
u32 * msgid,
@@ -758,27 +758,27 @@ int iucv_send2way_array (u16 pathid,
iucv_array_t * buffer,
ulong buflen, iucv_array_t * ansbuf, ulong anslen);
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - Rath identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
+/*
+ * Name: iucv_send2way_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message.
+ * Input: pathid - Rath identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed in parameter list.
- * ansbuf - Address of buffer into which IUCV moves the reply of
+ * prmmsg - 8-bytes of data to be placed in parameter list.
+ * ansbuf - Address of buffer into which IUCV moves the reply of
* this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
+ * anslen - Address of length of buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
*/
int iucv_send2way_prmmsg (u16 pathid,
u32 * msgid,
@@ -788,29 +788,29 @@ int iucv_send2way_prmmsg (u16 pathid,
ulong flags1,
uchar prmmsg[8], void *ansbuf, ulong anslen);
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
+/*
+ * Name: iucv_send2way_prmmsg_array
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message. The contents of ansbuf is the address of the
+ * array of addresses and lengths of discontiguous buffers
+ * that contain the reply.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter list.
+ * prmmsg - 8-bytes of data to be placed into the parameter list.
* ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length of reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Ansbuf address is NULL.
+ * of this message.
+ * anslen - Address of length of reply buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Ansbuf address is NULL.
*/
int iucv_send2way_prmmsg_array (u16 pathid,
u32 * msgid,
@@ -821,29 +821,29 @@ int iucv_send2way_prmmsg_array (u16 pathid,
uchar prmmsg[8],
iucv_array_t * ansbuf, ulong anslen);
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
+/*
+ * Name: iucv_setmask
+ * Purpose: This function enables or disables the following IUCV
+ * external interruptions: Nonpriority and priority message
+ * interrupts, nonpriority and priority reply interrupts.
* Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
+ * 0x80 - Nonpriority_MessagePendingInterruptsFlag
+ * 0x40 - Priority_MessagePendingInterruptsFlag
+ * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
+ * 0x10 - Priority_MessageCompletionInterruptsFlag
* 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: Return code from CP IUCV call.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
*/
int iucv_setmask (int SetMaskFlag);
-/*
- * Name: iucv_sever
- * Purpose: This function terminates an IUCV path.
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Interal error, wild pointer.
+/*
+ * Name: iucv_sever
+ * Purpose: This function terminates an IUCV path.
+ * Input: pathid - Path identification number.
+ * user_data - 16-bytes of user data.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Interal error, wild pointer.
*/
int iucv_sever (u16 pathid, uchar user_data[16]);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 5d6b7a57b02f..f94419b334f7 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -68,6 +68,7 @@ static void lcs_tasklet(unsigned long);
static void lcs_start_kernel_thread(struct lcs_card *card);
static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *);
static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *);
+static int lcs_recovery(void *ptr);
/**
* Debug Facility Stuff
@@ -429,12 +430,6 @@ lcs_setup_card(struct lcs_card *card)
card->tx_buffer = NULL;
card->tx_emitted = 0;
- /* Initialize kernel thread task used for LGW commands. */
- INIT_WORK(&card->kernel_thread_starter,
- (void *)lcs_start_kernel_thread,card);
- card->thread_start_mask = 0;
- card->thread_allowed_mask = 0;
- card->thread_running_mask = 0;
init_waitqueue_head(&card->wait_q);
spin_lock_init(&card->lock);
spin_lock_init(&card->ipm_lock);
@@ -675,8 +670,9 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, rc;
LCS_DBF_TEXT(5, trace, "rdybuff");
- BUG_ON(buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED);
+ if (buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED)
+ BUG();
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_READY;
index = buffer - channel->iob;
@@ -700,7 +696,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, prev, next;
LCS_DBF_TEXT(5, trace, "prcsbuff");
- BUG_ON(buffer->state != BUF_STATE_READY);
+ if (buffer->state != BUF_STATE_READY)
+ BUG();
buffer->state = BUF_STATE_PROCESSED;
index = buffer - channel->iob;
prev = (index - 1) & (LCS_NUM_BUFFS - 1);
@@ -732,8 +729,9 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
unsigned long flags;
LCS_DBF_TEXT(5, trace, "relbuff");
- BUG_ON(buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED);
+ if (buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED)
+ BUG();
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_EMPTY;
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1147,8 +1145,6 @@ list_modified:
list_add_tail(&ipm->list, &card->ipm_list);
}
spin_unlock_irqrestore(&card->ipm_lock, flags);
- if (card->state == DEV_STATE_UP)
- netif_wake_queue(card->dev);
}
/**
@@ -1231,17 +1227,17 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev)
if (ipm != NULL)
continue; /* Address already in list. */
ipm = (struct lcs_ipm_list *)
- kmalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
+ kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
if (ipm == NULL) {
PRINT_INFO("Not enough memory to add "
"new multicast entry!\n");
break;
}
- memset(ipm, 0, sizeof(struct lcs_ipm_list));
memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH);
ipm->ipm.ip_addr = im4->multiaddr;
ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED;
spin_lock_irqsave(&card->ipm_lock, flags);
+ LCS_DBF_HEX(2,trace,&ipm->ipm.ip_addr,4);
list_add(&ipm->list, &card->ipm_list);
spin_unlock_irqrestore(&card->ipm_lock, flags);
}
@@ -1269,7 +1265,15 @@ lcs_register_mc_addresses(void *data)
read_unlock(&in4_dev->mc_list_lock);
in_dev_put(in4_dev);
+ netif_carrier_off(card->dev);
+ netif_tx_disable(card->dev);
+ wait_event(card->write.wait_q,
+ (card->write.state != CH_STATE_RUNNING));
lcs_fix_multicast_list(card);
+ if (card->state == DEV_STATE_UP) {
+ netif_carrier_on(card->dev);
+ netif_wake_queue(card->dev);
+ }
out:
lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD);
return 0;
@@ -1286,7 +1290,7 @@ lcs_set_multicast_list(struct net_device *dev)
LCS_DBF_TEXT(4, trace, "setmulti");
card = (struct lcs_card *) dev->priv;
- if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD))
+ if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD))
schedule_work(&card->kernel_thread_starter);
}
@@ -1318,6 +1322,53 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
return PTR_ERR(irb);
}
+static int
+lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
+{
+ int dstat, cstat;
+ char *sense;
+
+ sense = (char *) irb->ecw;
+ cstat = irb->scsw.cstat;
+ dstat = irb->scsw.dstat;
+
+ if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
+ SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
+ SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
+ LCS_DBF_TEXT(2, trace, "CGENCHK");
+ return 1;
+ }
+ if (dstat & DEV_STAT_UNIT_CHECK) {
+ if (sense[LCS_SENSE_BYTE_1] &
+ LCS_SENSE_RESETTING_EVENT) {
+ LCS_DBF_TEXT(2, trace, "REVIND");
+ return 1;
+ }
+ if (sense[LCS_SENSE_BYTE_0] &
+ LCS_SENSE_CMD_REJECT) {
+ LCS_DBF_TEXT(2, trace, "CMDREJ");
+ return 0;
+ }
+ if ((!sense[LCS_SENSE_BYTE_0]) &&
+ (!sense[LCS_SENSE_BYTE_1]) &&
+ (!sense[LCS_SENSE_BYTE_2]) &&
+ (!sense[LCS_SENSE_BYTE_3])) {
+ LCS_DBF_TEXT(2, trace, "ZEROSEN");
+ return 0;
+ }
+ LCS_DBF_TEXT(2, trace, "DGENCHK");
+ return 1;
+ }
+ return 0;
+}
+
+void
+lcs_schedule_recovery(struct lcs_card *card)
+{
+ LCS_DBF_TEXT(2, trace, "startrec");
+ if (!lcs_set_thread_start_bit(card, LCS_RECOVERY_THREAD))
+ schedule_work(&card->kernel_thread_starter);
+}
/**
* IRQ Handler for LCS channels
@@ -1327,7 +1378,8 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
{
struct lcs_card *card;
struct lcs_channel *channel;
- int index;
+ int rc, index;
+ int cstat, dstat;
if (lcs_check_irb_error(cdev, irb))
return;
@@ -1338,17 +1390,30 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
else
channel = &card->write;
+ cstat = irb->scsw.cstat;
+ dstat = irb->scsw.dstat;
LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat);
LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl);
+ /* Check for channel and device errors presented */
+ rc = lcs_get_problem(cdev, irb);
+ if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) {
+ PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
+ cdev->dev.bus_id, dstat, cstat);
+ if (rc) {
+ lcs_schedule_recovery(card);
+ wake_up(&card->wait_q);
+ return;
+ }
+ }
/* How far in the ccw chain have we processed? */
if ((channel->state != CH_STATE_INIT) &&
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
- index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa)
+ index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa)
- channel->ccws;
if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) ||
- (irb->scsw.cstat | SCHN_STAT_PCI))
+ (irb->scsw.cstat & SCHN_STAT_PCI))
/* Bloody io subsystem tells us lies about cpa... */
index = (index - 1) & (LCS_NUM_BUFFS - 1);
while (channel->io_idx != index) {
@@ -1367,7 +1432,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED)
/* CCW execution stopped on a suspend bit. */
channel->state = CH_STATE_SUSPENDED;
-
if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
if (irb->scsw.cc != 0) {
ccw_device_halt(channel->ccwdev, (addr_t) channel);
@@ -1376,7 +1440,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* The channel has been stopped by halt_IO. */
channel->state = CH_STATE_HALTED;
}
-
if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
channel->state = CH_STATE_CLEARED;
}
@@ -1452,7 +1515,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
lcs_release_buffer(channel, buffer);
card = (struct lcs_card *)
((char *) channel - offsetof(struct lcs_card, write));
- if (netif_queue_stopped(card->dev))
+ if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev))
netif_wake_queue(card->dev);
spin_lock(&card->lock);
card->tx_emitted--;
@@ -1488,6 +1551,10 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
card->stats.tx_carrier_errors++;
return 0;
}
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
netif_stop_queue(card->dev);
spin_lock(&card->lock);
if (card->tx_buffer != NULL &&
@@ -1633,30 +1700,6 @@ lcs_detect(struct lcs_card *card)
}
/**
- * reset card
- */
-static int
-lcs_resetcard(struct lcs_card *card)
-{
- int retries;
-
- LCS_DBF_TEXT(2, trace, "rescard");
- for (retries = 0; retries < 10; retries++) {
- if (lcs_detect(card) == 0) {
- netif_wake_queue(card->dev);
- card->state = DEV_STATE_UP;
- PRINT_INFO("LCS device %s successfully restarted!\n",
- card->dev->name);
- return 0;
- }
- msleep(3000);
- }
- PRINT_ERR("Error in Reseting LCS card!\n");
- return -EIO;
-}
-
-
-/**
* LCS Stop card
*/
static int
@@ -1680,126 +1723,18 @@ lcs_stopcard(struct lcs_card *card)
}
/**
- * LGW initiated commands
- */
-static int
-lcs_lgw_startlan_thread(void *data)
-{
- struct lcs_card *card;
-
- card = (struct lcs_card *) data;
- daemonize("lgwstpln");
-
- if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD))
- return 0;
- LCS_DBF_TEXT(4, trace, "lgwstpln");
- if (card->dev)
- netif_stop_queue(card->dev);
- if (lcs_startlan(card) == 0) {
- netif_wake_queue(card->dev);
- card->state = DEV_STATE_UP;
- PRINT_INFO("LCS Startlan for device %s succeeded!\n",
- card->dev->name);
-
- } else
- PRINT_ERR("LCS Startlan for device %s failed!\n",
- card->dev->name);
- lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD);
- return 0;
-}
-
-/**
- * Send startup command initiated by Lan Gateway
- */
-static int
-lcs_lgw_startup_thread(void *data)
-{
- int rc;
-
- struct lcs_card *card;
-
- card = (struct lcs_card *) data;
- daemonize("lgwstaln");
-
- if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD))
- return 0;
- LCS_DBF_TEXT(4, trace, "lgwstaln");
- if (card->dev)
- netif_stop_queue(card->dev);
- rc = lcs_send_startup(card, LCS_INITIATOR_LGW);
- if (rc != 0) {
- PRINT_ERR("Startup for LCS device %s initiated " \
- "by LGW failed!\nReseting card ...\n",
- card->dev->name);
- /* do a card reset */
- rc = lcs_resetcard(card);
- if (rc == 0)
- goto Done;
- }
- rc = lcs_startlan(card);
- if (rc == 0) {
- netif_wake_queue(card->dev);
- card->state = DEV_STATE_UP;
- }
-Done:
- if (rc == 0)
- PRINT_INFO("LCS Startup for device %s succeeded!\n",
- card->dev->name);
- else
- PRINT_ERR("LCS Startup for device %s failed!\n",
- card->dev->name);
- lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD);
- return 0;
-}
-
-
-/**
- * send stoplan command initiated by Lan Gateway
- */
-static int
-lcs_lgw_stoplan_thread(void *data)
-{
- struct lcs_card *card;
- int rc;
-
- card = (struct lcs_card *) data;
- daemonize("lgwstop");
-
- if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD))
- return 0;
- LCS_DBF_TEXT(4, trace, "lgwstop");
- if (card->dev)
- netif_stop_queue(card->dev);
- if (lcs_send_stoplan(card, LCS_INITIATOR_LGW) == 0)
- PRINT_INFO("Stoplan for %s initiated by LGW succeeded!\n",
- card->dev->name);
- else
- PRINT_ERR("Stoplan %s initiated by LGW failed!\n",
- card->dev->name);
- /*Try to reset the card, stop it on failure */
- rc = lcs_resetcard(card);
- if (rc != 0)
- rc = lcs_stopcard(card);
- lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD);
- return rc;
-}
-
-/**
* Kernel Thread helper functions for LGW initiated commands
*/
static void
lcs_start_kernel_thread(struct lcs_card *card)
{
LCS_DBF_TEXT(5, trace, "krnthrd");
- if (lcs_do_start_thread(card, LCS_STARTUP_THREAD))
- kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD);
- if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD))
- kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD);
- if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD))
- kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD);
+ if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD))
+ kernel_thread(lcs_recovery, (void *) card, SIGCHLD);
#ifdef CONFIG_IP_MULTICAST
if (lcs_do_start_thread(card, LCS_SET_MC_THREAD))
- kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD);
+ kernel_thread(lcs_register_mc_addresses,
+ (void *) card, SIGCHLD);
#endif
}
@@ -1813,19 +1748,14 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
if (cmd->initiator == LCS_INITIATOR_LGW) {
switch(cmd->cmd_code) {
case LCS_CMD_STARTUP:
- if (!lcs_set_thread_start_bit(card,
- LCS_STARTUP_THREAD))
- schedule_work(&card->kernel_thread_starter);
- break;
case LCS_CMD_STARTLAN:
- if (!lcs_set_thread_start_bit(card,
- LCS_STARTLAN_THREAD))
- schedule_work(&card->kernel_thread_starter);
+ lcs_schedule_recovery(card);
break;
case LCS_CMD_STOPLAN:
- if (!lcs_set_thread_start_bit(card,
- LCS_STOPLAN_THREAD))
- schedule_work(&card->kernel_thread_starter);
+ PRINT_WARN("Stoplan for %s initiated by LGW.\n",
+ card->dev->name);
+ if (card->dev)
+ netif_carrier_off(card->dev);
break;
default:
PRINT_INFO("UNRECOGNIZED LGW COMMAND\n");
@@ -1941,8 +1871,11 @@ lcs_stop_device(struct net_device *dev)
LCS_DBF_TEXT(2, trace, "stopdev");
card = (struct lcs_card *) dev->priv;
- netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ netif_tx_disable(dev);
dev->flags &= ~IFF_UP;
+ wait_event(card->write.wait_q,
+ (card->write.state != CH_STATE_RUNNING));
rc = lcs_stopcard(card);
if (rc)
PRINT_ERR("Try it again!\n ");
@@ -1968,6 +1901,7 @@ lcs_open_device(struct net_device *dev)
} else {
dev->flags |= IFF_UP;
+ netif_carrier_on(dev);
netif_wake_queue(dev);
card->state = DEV_STATE_UP;
}
@@ -2059,10 +1993,31 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static ssize_t
+lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lcs_card *card = dev->driver_data;
+ char *tmp;
+ int i;
+
+ if (!card)
+ return -EINVAL;
+ if (card->state != DEV_STATE_UP)
+ return -EPERM;
+ i = simple_strtoul(buf, &tmp, 16);
+ if (i == 1)
+ lcs_schedule_recovery(card);
+ return count;
+}
+
+static DEVICE_ATTR(recover, 0200, NULL, lcs_dev_recover_store);
+
static struct attribute * lcs_attrs[] = {
&dev_attr_portno.attr,
&dev_attr_type.attr,
&dev_attr_lancmd_timeout.attr,
+ &dev_attr_recover.attr,
NULL,
};
@@ -2099,6 +2054,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
ccwgdev->dev.driver_data = card;
ccwgdev->cdev[0]->handler = lcs_irq;
ccwgdev->cdev[1]->handler = lcs_irq;
+ card->gdev = ccwgdev;
+ INIT_WORK(&card->kernel_thread_starter,
+ (void *) lcs_start_kernel_thread, card);
+ card->thread_start_mask = 0;
+ card->thread_allowed_mask = 0;
+ card->thread_running_mask = 0;
return 0;
}
@@ -2200,6 +2161,7 @@ netdev_out:
if (recover_state == DEV_STATE_RECOVER) {
lcs_set_multicast_list(card->dev);
card->dev->flags |= IFF_UP;
+ netif_carrier_on(card->dev);
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
} else {
@@ -2229,7 +2191,7 @@ out:
* lcs_shutdown_device, called when setting the group device offline.
*/
static int
-lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
+__lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
{
struct lcs_card *card;
enum lcs_dev_states recover_state;
@@ -2239,9 +2201,11 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
card = (struct lcs_card *)ccwgdev->dev.driver_data;
if (!card)
return -ENODEV;
- lcs_set_allowed_threads(card, 0);
- if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD))
- return -ERESTARTSYS;
+ if (recovery_mode == 0) {
+ lcs_set_allowed_threads(card, 0);
+ if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD))
+ return -ERESTARTSYS;
+ }
LCS_DBF_HEX(3, setup, &card, sizeof(void*));
recover_state = card->state;
@@ -2256,6 +2220,43 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
return 0;
}
+static int
+lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
+{
+ return __lcs_shutdown_device(ccwgdev, 0);
+}
+
+/**
+ * drive lcs recovery after startup and startlan initiated by Lan Gateway
+ */
+static int
+lcs_recovery(void *ptr)
+{
+ struct lcs_card *card;
+ struct ccwgroup_device *gdev;
+ int rc;
+
+ card = (struct lcs_card *) ptr;
+ daemonize("lcs_recover");
+
+ LCS_DBF_TEXT(4, trace, "recover1");
+ if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD))
+ return 0;
+ LCS_DBF_TEXT(4, trace, "recover2");
+ gdev = card->gdev;
+ PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id);
+ rc = __lcs_shutdown_device(gdev, 1);
+ rc = lcs_new_device(gdev);
+ if (!rc)
+ PRINT_INFO("Device %s successfully recovered!\n",
+ card->dev->name);
+ else
+ PRINT_INFO("Device %s could not be recovered!\n",
+ card->dev->name);
+ lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD);
+ return 0;
+}
+
/**
* lcs_remove_device, free buffers and card
*/
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
index 2fad5e40c2e4..93143932983b 100644
--- a/drivers/s390/net/lcs.h
+++ b/drivers/s390/net/lcs.h
@@ -73,13 +73,17 @@ do { \
/**
* LCS sense byte definitions
*/
+#define LCS_SENSE_BYTE_0 0
+#define LCS_SENSE_BYTE_1 1
+#define LCS_SENSE_BYTE_2 2
+#define LCS_SENSE_BYTE_3 3
#define LCS_SENSE_INTERFACE_DISCONNECT 0x01
#define LCS_SENSE_EQUIPMENT_CHECK 0x10
#define LCS_SENSE_BUS_OUT_CHECK 0x20
#define LCS_SENSE_INTERVENTION_REQUIRED 0x40
#define LCS_SENSE_CMD_REJECT 0x80
-#define LCS_SENSE_RESETTING_EVENT 0x0080
-#define LCS_SENSE_DEVICE_ONLINE 0x0020
+#define LCS_SENSE_RESETTING_EVENT 0x80
+#define LCS_SENSE_DEVICE_ONLINE 0x20
/**
* LCS packet type definitions
@@ -152,10 +156,9 @@ enum lcs_dev_states {
enum lcs_threads {
LCS_SET_MC_THREAD = 1,
- LCS_STARTLAN_THREAD = 2,
- LCS_STOPLAN_THREAD = 4,
- LCS_STARTUP_THREAD = 8,
+ LCS_RECOVERY_THREAD = 2,
};
+
/**
* LCS struct declarations
*/
@@ -286,6 +289,7 @@ struct lcs_card {
struct net_device_stats stats;
unsigned short (*lan_type_trans)(struct sk_buff *skb,
struct net_device *dev);
+ struct ccwgroup_device *gdev;
struct lcs_channel read;
struct lcs_channel write;
struct lcs_buffer *tx_buffer;
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 260a93c8c442..b452cc1afd55 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -30,7 +30,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-
+
#undef DEBUG
#include <linux/module.h>
@@ -65,7 +65,7 @@ MODULE_AUTHOR
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
-
+
#define PRINTK_HEADER " iucv: " /* for debugging */
static struct device_driver netiucv_driver = {
@@ -202,7 +202,7 @@ netiucv_printname(char *name)
*p = '\0';
return tmp;
}
-
+
/**
* States of the interface statemachine.
*/
@@ -244,7 +244,7 @@ static const char *dev_event_names[] = {
"Connection up",
"Connection down",
};
-
+
/**
* Events of the connection statemachine
*/
@@ -364,7 +364,7 @@ static const char *conn_state_names[] = {
"Connect error",
};
-
+
/**
* Debug Facility Stuff
*/
@@ -516,7 +516,7 @@ static void
fsm_action_nop(fsm_instance *fi, int event, void *arg)
{
}
-
+
/**
* Actions of the connection statemachine
*****************************************************************************/
@@ -993,7 +993,7 @@ static const fsm_node conn_fsm[] = {
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
-
+
/**
* Actions for interface - statemachine.
*****************************************************************************/
@@ -1182,7 +1182,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = xtime;
-
+
rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
0, nskb->data, nskb->len);
/* Shut up, gcc! nskb is always below 2G. */
@@ -1220,7 +1220,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
return rc;
}
-
+
/**
* Interface API for upper network layers
*****************************************************************************/
@@ -1291,7 +1291,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
/**
* If connection is not running, try to restart it
- * and throw away packet.
+ * and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev);
@@ -1538,7 +1538,7 @@ static ssize_t
maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.maxcqueue = 0;
return count;
@@ -1559,7 +1559,7 @@ static ssize_t
sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.doios_single = 0;
return count;
@@ -1580,7 +1580,7 @@ static ssize_t
mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
priv->conn->prof.doios_multi = 0;
return count;
@@ -1601,7 +1601,7 @@ static ssize_t
txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.txlen = 0;
return count;
@@ -1622,7 +1622,7 @@ static ssize_t
txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.tx_time = 0;
return count;
@@ -2000,7 +2000,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
}
PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
-
+
return count;
out_free_ndev:
@@ -2099,7 +2099,7 @@ static int __init
netiucv_init(void)
{
int ret;
-
+
ret = iucv_register_dbf_views();
if (ret) {
PRINT_WARN("netiucv_init failed, "
@@ -2128,7 +2128,7 @@ netiucv_init(void)
}
return ret;
}
-
+
module_init(netiucv_init);
module_exit(netiucv_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 4df0fcd7b10b..619f4a0c7160 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -376,7 +376,7 @@ struct qeth_hdr_osn {
__u8 reserved3[18];
__u32 ccid;
} __attribute__ ((packed));
-
+
struct qeth_hdr {
union {
struct qeth_hdr_layer2 l2;
@@ -825,7 +825,7 @@ struct qeth_card {
int use_hard_stop;
int (*orig_hard_header)(struct sk_buff *,struct net_device *,
unsigned short,void *,void *,unsigned);
- struct qeth_osn_info osn_info;
+ struct qeth_osn_info osn_info;
};
struct qeth_card_list_struct {
@@ -944,7 +944,7 @@ qeth_get_netdev_flags(struct qeth_card *card)
return 0;
switch (card->info.type) {
case QETH_CARD_TYPE_IQD:
- case QETH_CARD_TYPE_OSN:
+ case QETH_CARD_TYPE_OSN:
return IFF_NOARP;
#ifdef CONFIG_QETH_IPV6
default:
@@ -981,7 +981,7 @@ static inline int
qeth_get_max_mtu_for_card(int cardtype)
{
switch (cardtype) {
-
+
case QETH_CARD_TYPE_UNKNOWN:
case QETH_CARD_TYPE_OSAE:
case QETH_CARD_TYPE_OSN:
@@ -1097,9 +1097,9 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
int count = 0, rc = 0;
int in[4];
- rc = sscanf(buf, "%d.%d.%d.%d%n",
+ rc = sscanf(buf, "%d.%d.%d.%d%n",
&in[0], &in[1], &in[2], &in[3], &count);
- if (rc != 4 || count)
+ if (rc != 4 || count<=0)
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
@@ -1131,7 +1131,7 @@ qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
cnt = out = found = save_cnt = num2 = 0;
end = start = (char *) buf;
- in = (__u16 *) addr;
+ in = (__u16 *) addr;
memset(in, 0, 16);
while (end) {
end = strchr(end,':');
@@ -1139,7 +1139,7 @@ qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
end = (char *)buf + (strlen(buf));
out = 1;
}
- if ((end - start)) {
+ if ((end - start)) {
memset(num, 0, 5);
memcpy(num, start, end - start);
if (!qeth_isxdigit(num))
@@ -1241,5 +1241,5 @@ qeth_osn_register(unsigned char *read_dev_no,
extern void
qeth_osn_deregister(struct net_device *);
-
+
#endif /* __QETH_H__ */
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 44e226f211e7..0bab60a20309 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -81,7 +81,7 @@ void
qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
{
struct qeth_eddp_context_reference *ref;
-
+
QETH_DBF_TEXT(trace, 6, "eddprctx");
while (!list_empty(&buf->ctx_list)){
ref = list_entry(buf->ctx_list.next,
@@ -135,7 +135,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
"buffer!\n");
goto out;
}
- }
+ }
/* check if the whole next skb fits into current buffer */
if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
buf->next_element_to_fill)
@@ -148,7 +148,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
* and increment ctx's refcnt */
must_refcnt = 1;
continue;
- }
+ }
if (must_refcnt){
must_refcnt = 0;
if (qeth_eddp_buf_ref_context(buf, ctx)){
@@ -266,7 +266,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
int left_in_frag;
int copy_len;
u8 *src;
-
+
QETH_DBF_TEXT(trace, 5, "eddpcdtc");
if (skb_shinfo(eddp->skb)->nr_frags == 0) {
memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@@ -408,7 +408,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct tcphdr *tcph;
int data_len;
u32 hcsum;
-
+
QETH_DBF_TEXT(trace, 5, "eddpftcp");
eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
@@ -465,13 +465,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
eddp->th.tcp.h.seq += data_len;
}
}
-
+
static inline int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
struct qeth_eddp_data *eddp = NULL;
-
+
QETH_DBF_TEXT(trace, 5, "eddpficx");
/* create our segmentation headers and copy original headers */
if (skb->protocol == ETH_P_IP)
@@ -512,7 +512,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
int skbs_per_page;
-
+
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
@@ -588,7 +588,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
struct qeth_eddp_context *ctx = NULL;
-
+
QETH_DBF_TEXT(trace, 5, "creddpct");
if (skb->protocol == ETH_P_IP)
ctx = qeth_eddp_create_context_generic(card, skb,
diff --git a/drivers/s390/net/qeth_fs.h b/drivers/s390/net/qeth_fs.h
index e422b41c656e..61faf05517d6 100644
--- a/drivers/s390/net/qeth_fs.h
+++ b/drivers/s390/net/qeth_fs.h
@@ -42,7 +42,7 @@ qeth_create_device_attributes_osn(struct device *dev);
extern void
qeth_remove_device_attributes_osn(struct device *dev);
-
+
extern int
qeth_create_driver_attributes(void);
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index b3c6e7907790..9e671a48cd2f 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -513,7 +513,7 @@ __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
QETH_DBF_TEXT(setup, 3, "setoffl");
QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
-
+
if (card->dev && netif_carrier_ok(card->dev))
netif_carrier_off(card->dev);
recover_flag = card->state;
@@ -604,13 +604,13 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
list_for_each_entry(addr, &card->ip_list, entry) {
if (card->options.layer2) {
if ((addr->type == todo->type) &&
- (memcmp(&addr->mac, &todo->mac,
+ (memcmp(&addr->mac, &todo->mac,
OSA_ADDR_LEN) == 0)) {
found = 1;
break;
}
continue;
- }
+ }
if ((addr->proto == QETH_PROT_IPV4) &&
(todo->proto == QETH_PROT_IPV4) &&
(addr->type == todo->type) &&
@@ -694,13 +694,13 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
if (card->options.layer2) {
if ((tmp->type == addr->type) &&
(tmp->is_multicast == addr->is_multicast) &&
- (memcmp(&tmp->mac, &addr->mac,
+ (memcmp(&tmp->mac, &addr->mac,
OSA_ADDR_LEN) == 0)) {
found = 1;
break;
}
continue;
- }
+ }
if ((tmp->proto == QETH_PROT_IPV4) &&
(addr->proto == QETH_PROT_IPV4) &&
(tmp->type == addr->type) &&
@@ -1173,7 +1173,7 @@ qeth_determine_card_type(struct qeth_card *card)
"due to hardware limitations!\n");
card->qdio.no_out_queues = 1;
card->qdio.default_out_queue = 0;
- }
+ }
return 0;
}
i++;
@@ -1198,7 +1198,7 @@ qeth_probe_device(struct ccwgroup_device *gdev)
return -ENODEV;
QETH_DBF_TEXT_(setup, 2, "%s", gdev->dev.bus_id);
-
+
card = qeth_alloc_card();
if (!card) {
put_device(dev);
@@ -1220,7 +1220,7 @@ qeth_probe_device(struct ccwgroup_device *gdev)
put_device(dev);
qeth_free_card(card);
return rc;
- }
+ }
if ((rc = qeth_setup_card(card))){
QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
put_device(dev);
@@ -1843,7 +1843,7 @@ struct qeth_cmd_buffer *iob)
&card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
}
-
+
static int
qeth_send_control_data(struct qeth_card *card, int len,
struct qeth_cmd_buffer *iob,
@@ -1937,7 +1937,7 @@ qeth_osn_send_control_data(struct qeth_card *card, int len,
wake_up(&card->wait_q);
}
return rc;
-}
+}
static inline void
qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
@@ -1966,7 +1966,7 @@ qeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
return qeth_osn_send_control_data(card, s1, iob);
}
-
+
static int
qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
int (*reply_cb)
@@ -2579,7 +2579,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
skb->dev = card->dev;
if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr);
- else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
+ else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
qeth_rebuild_skb(card, skb, hdr);
else { /*in case of OSN*/
skb_push(skb, sizeof(struct qeth_hdr));
@@ -2763,7 +2763,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
index = i % QDIO_MAX_BUFFERS_PER_Q;
buffer = &card->qdio.in_q->bufs[index];
if (!((status & QDIO_STATUS_LOOK_FOR_ERROR) &&
- qeth_check_qdio_errors(buffer->buffer,
+ qeth_check_qdio_errors(buffer->buffer,
qdio_err, siga_err,"qinerr")))
qeth_process_inbound_buffer(card, buffer, index);
/* clear buffer and give back to hardware */
@@ -3187,7 +3187,7 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
if (card->qdio.state == QETH_QDIO_ALLOCATED)
return 0;
- card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q),
+ card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q),
GFP_KERNEL|GFP_DMA);
if (!card->qdio.in_q)
return - ENOMEM;
@@ -3476,7 +3476,7 @@ qeth_halt_channels(struct qeth_card *card)
rc3 = qeth_halt_channel(&card->data);
if (rc1)
return rc1;
- if (rc2)
+ if (rc2)
return rc2;
return rc3;
}
@@ -3491,7 +3491,7 @@ qeth_clear_channels(struct qeth_card *card)
rc3 = qeth_clear_channel(&card->data);
if (rc1)
return rc1;
- if (rc2)
+ if (rc2)
return rc2;
return rc3;
}
@@ -3798,10 +3798,10 @@ qeth_open(struct net_device *dev)
QETH_DBF_TEXT(trace,4,"nomacadr");
return -EPERM;
}
- card->dev->flags |= IFF_UP;
- netif_start_queue(dev);
card->data.state = CH_STATE_UP;
card->state = CARD_STATE_UP;
+ card->dev->flags |= IFF_UP;
+ netif_start_queue(dev);
if (!card->lan_online && netif_carrier_ok(dev))
netif_carrier_off(dev);
@@ -3817,7 +3817,7 @@ qeth_stop(struct net_device *dev)
card = (struct qeth_card *) dev->priv;
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
card->dev->flags &= ~IFF_UP;
if (card->state == CARD_STATE_UP)
card->state = CARD_STATE_SOFTSETUP;
@@ -3958,7 +3958,7 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
#endif
*hdr = (struct qeth_hdr *)
qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
- if (hdr == NULL)
+ if (*hdr == NULL)
return -EINVAL;
return 0;
}
@@ -4098,7 +4098,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
} else { /* passthrough */
if((skb->dev->type == ARPHRD_IEEE802_TR) &&
- !memcmp(skb->data + sizeof(struct qeth_hdr) +
+ !memcmp(skb->data + sizeof(struct qeth_hdr) +
sizeof(__u16), skb->dev->broadcast, 6)) {
hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
QETH_HDR_PASSTHRU;
@@ -4385,7 +4385,7 @@ out:
}
static inline int
-qeth_get_elements_no(struct qeth_card *card, void *hdr,
+qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
int elements_needed = 0;
@@ -4416,6 +4416,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
int tx_bytes = skb->len;
+ unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned short tso_size = skb_shinfo(skb)->tso_size;
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
@@ -4441,7 +4443,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
return 0;
}
cast_type = qeth_get_cast_type(card, skb);
- if ((cast_type == RTN_BROADCAST) &&
+ if ((cast_type == RTN_BROADCAST) &&
(card->info.broadcast_capable == 0)){
card->stats.tx_dropped++;
card->stats.tx_errors++;
@@ -4463,7 +4465,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
card->stats.tx_errors++;
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
- }
+ }
elements_needed++;
} else {
if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
@@ -4498,16 +4500,16 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes;
#ifdef CONFIG_QETH_PERF_STATS
- if (skb_shinfo(skb)->tso_size &&
+ if (tso_size &&
!(large_send == QETH_LARGE_SEND_NO)) {
- card->perf_stats.large_send_bytes += skb->len;
+ card->perf_stats.large_send_bytes += tx_bytes;
card->perf_stats.large_send_cnt++;
}
- if (skb_shinfo(skb)->nr_frags > 0){
+ if (nr_frags > 0){
card->perf_stats.sg_skbs_sent++;
/* nr_frags + skb->data */
card->perf_stats.sg_frags_sent +=
- skb_shinfo(skb)->nr_frags + 1;
+ nr_frags + 1;
}
#endif /* CONFIG_QETH_PERF_STATS */
}
@@ -5373,7 +5375,7 @@ qeth_layer2_send_setdelvlan_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
- "Continuing\n",cmd->data.setdelvlan.vlan_id,
+ "Continuing\n",cmd->data.setdelvlan.vlan_id,
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
QETH_DBF_TEXT_(trace, 2, "L2VL%4x", cmd->hdr.command);
QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card));
@@ -5393,7 +5395,7 @@ qeth_layer2_send_setdelvlan(struct qeth_card *card, __u16 i,
iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setdelvlan.vlan_id = i;
- return qeth_send_ipa_cmd(card, iob,
+ return qeth_send_ipa_cmd(card, iob,
qeth_layer2_send_setdelvlan_cb, NULL);
}
@@ -5457,7 +5459,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
* Examine hardware response to SET_PROMISC_MODE
*/
static int
-qeth_setadp_promisc_mode_cb(struct qeth_card *card,
+qeth_setadp_promisc_mode_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
@@ -5468,10 +5470,10 @@ qeth_setadp_promisc_mode_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
setparms = &(cmd->data.setadapterparms);
-
+
qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
- if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(trace,4,"prmrc%2.2x",cmd->hdr.return_code);
+ if (cmd->hdr.return_code) {
+ QETH_DBF_TEXT_(trace,4,"prmrc%2.2x",cmd->hdr.return_code);
setparms->data.mode = SET_PROMISC_MODE_OFF;
}
card->info.promisc_mode = setparms->data.mode;
@@ -5517,7 +5519,7 @@ qeth_set_multicast_list(struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
return ;
-
+
QETH_DBF_TEXT(trace, 3, "setmulti");
qeth_delete_mc_addresses(card);
if (card->options.layer2) {
@@ -5575,7 +5577,7 @@ qeth_osn_assist(struct net_device *dev,
struct qeth_cmd_buffer *iob;
struct qeth_card *card;
int rc;
-
+
QETH_DBF_TEXT(trace, 2, "osnsdmc");
if (!dev)
return -ENODEV;
@@ -5654,7 +5656,7 @@ qeth_osn_deregister(struct net_device * dev)
card->osn_info.data_cb = NULL;
return;
}
-
+
static void
qeth_delete_mc_addresses(struct qeth_card *card)
{
@@ -5818,7 +5820,7 @@ qeth_add_multicast_ipv6(struct qeth_card *card)
struct inet6_dev *in6_dev;
QETH_DBF_TEXT(trace,4,"chkmcv6");
- if (!qeth_is_supported(card, IPA_IPV6))
+ if (!qeth_is_supported(card, IPA_IPV6))
return ;
in6_dev = in6_dev_get(card->dev);
if (in6_dev == NULL)
@@ -6359,12 +6361,9 @@ qeth_netdev_init(struct net_device *dev)
dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
#endif
- dev->hard_header = card->orig_hard_header;
if (qeth_get_netdev_flags(card) & IFF_NOARP) {
dev->rebuild_header = NULL;
dev->hard_header = NULL;
- if (card->options.fake_ll)
- dev->hard_header = qeth_fake_header;
dev->header_cache_update = NULL;
dev->hard_header_cache = NULL;
}
@@ -6373,6 +6372,9 @@ qeth_netdev_init(struct net_device *dev)
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
card->dev->dev_id = card->info.unique_id & 0xffff;
#endif
+ if (card->options.fake_ll &&
+ (qeth_get_netdev_flags(card) & IFF_NOARP))
+ dev->hard_header = qeth_fake_header;
dev->hard_header_parse = NULL;
dev->set_mac_address = qeth_layer2_set_mac_address;
dev->flags |= qeth_get_netdev_flags(card);
@@ -6477,6 +6479,9 @@ retry:
/*network device will be recovered*/
if (card->dev) {
card->dev->hard_header = card->orig_hard_header;
+ if (card->options.fake_ll &&
+ (qeth_get_netdev_flags(card) & IFF_NOARP))
+ card->dev->hard_header = qeth_fake_header;
return 0;
}
/* at first set_online allocate netdev */
@@ -6584,7 +6589,7 @@ qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (!card->options.layer2 || card->info.guestlan ||
- !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
+ !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
memcpy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr,
OSA_ADDR_LEN);
@@ -7031,14 +7036,12 @@ qeth_softsetup_ipv6(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"softipv6");
- netif_stop_queue(card->dev);
rc = qeth_send_startlan(card, QETH_PROT_IPV6);
if (rc) {
PRINT_ERR("IPv6 startlan failed on %s\n",
QETH_CARD_IFNAME(card));
return rc;
}
- netif_wake_queue(card->dev);
rc = qeth_query_ipassists(card,QETH_PROT_IPV6);
if (rc) {
PRINT_ERR("IPv6 query ipassist failed on %s\n",
@@ -7352,7 +7355,8 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->options.large_send = type;
return 0;
}
- netif_stop_queue(card->dev);
+ if (card->state == CARD_STATE_UP)
+ netif_tx_disable(card->dev);
card->options.large_send = type;
switch (card->options.large_send) {
case QETH_LARGE_SEND_EDDP:
@@ -7374,7 +7378,8 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
break;
}
- netif_wake_queue(card->dev);
+ if (card->state == CARD_STATE_UP)
+ netif_wake_queue(card->dev);
return rc;
}
@@ -7427,7 +7432,7 @@ qeth_softsetup_card(struct qeth_card *card)
if ((rc = qeth_setrouting_v6(card)))
QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
out:
- netif_stop_queue(card->dev);
+ netif_tx_disable(card->dev);
return 0;
}
@@ -7567,7 +7572,7 @@ qeth_stop_card(struct qeth_card *card, int recovery_mode)
if (card->read.state == CH_STATE_UP &&
card->write.state == CH_STATE_UP &&
(card->state == CARD_STATE_UP)) {
- if (recovery_mode &&
+ if (recovery_mode &&
card->info.type != QETH_CARD_TYPE_OSN) {
qeth_stop(card->dev);
} else {
@@ -7736,10 +7741,8 @@ static int
qeth_register_netdev(struct qeth_card *card)
{
QETH_DBF_TEXT(setup, 3, "regnetd");
- if (card->dev->reg_state != NETREG_UNINITIALIZED) {
- qeth_netdev_init(card->dev);
+ if (card->dev->reg_state != NETREG_UNINITIALIZED)
return 0;
- }
/* sysfs magic */
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
return register_netdev(card->dev);
@@ -7750,7 +7753,7 @@ qeth_start_again(struct qeth_card *card, int recovery_mode)
{
QETH_DBF_TEXT(setup ,2, "startag");
- if (recovery_mode &&
+ if (recovery_mode &&
card->info.type != QETH_CARD_TYPE_OSN) {
qeth_open(card->dev);
} else {
@@ -8014,7 +8017,6 @@ static int (*qeth_old_arp_constructor) (struct neighbour *);
static struct neigh_ops arp_direct_ops_template = {
.family = AF_INET,
- .destructor = NULL,
.solicit = NULL,
.error_report = NULL,
.output = dev_queue_xmit,
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 011c41041029..0477c47471c5 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -445,7 +445,7 @@ enum qeth_ipa_arp_return_codes {
/* Helper functions */
#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \
(cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY))
-
+
/*****************************************************************************/
/* END OF IP Assist related definitions */
/*****************************************************************************/
@@ -490,7 +490,7 @@ extern unsigned char ULP_ENABLE[];
/* Layer 2 defintions */
#define QETH_PROT_LAYER2 0x08
#define QETH_PROT_TCPIP 0x03
-#define QETH_PROT_OSN2 0x0a
+#define QETH_PROT_OSN2 0x0a
#define QETH_ULP_ENABLE_PROT_TYPE(buffer) (buffer+0x50)
#define QETH_IPA_CMD_PROT_TYPE(buffer) (buffer+0x19)
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 360d782c7ada..66f2da14e6e3 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -36,7 +36,7 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
struct device *dev = NULL;
loff_t nr = 0;
-
+
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
if (*offset == 0)
return SEQ_START_TOKEN;
@@ -60,8 +60,8 @@ static void *
qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
struct device *prev, *next;
-
- if (it == SEQ_START_TOKEN)
+
+ if (it == SEQ_START_TOKEN)
prev = NULL;
else
prev = (struct device *) it;
@@ -180,7 +180,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
struct device *device;
struct qeth_card *card;
-
+
if (it == SEQ_START_TOKEN)
return 0;
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 882d419e4160..185a9cfbcbdc 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -785,7 +785,7 @@ qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, con
}
if (card->options.large_send == type)
return count;
- if ((rc = qeth_set_large_send(card, type)))
+ if ((rc = qeth_set_large_send(card, type)))
return rc;
return count;
}
@@ -1682,7 +1682,7 @@ qeth_create_device_attributes(struct device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
return sysfs_create_group(&dev->kobj,
&qeth_osn_device_attr_group);
-
+
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group)))
return ret;
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){
@@ -1713,7 +1713,7 @@ qeth_remove_device_attributes(struct device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
return sysfs_remove_group(&dev->kobj,
&qeth_osn_device_attr_group);
-
+
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index 1286ddea450b..24ef40ca9562 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -117,11 +117,11 @@ __qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
int fragno;
unsigned long addr;
int element, cnt, dlen;
-
+
fragno = skb_shinfo(skb)->nr_frags;
element = *next_element_to_fill;
dlen = 0;
-
+
if (is_tso)
buffer->element[element].flags =
SBAL_FLAGS_MIDDLE_FRAG;
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 3bf466603512..f99e55308b32 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
+#include <linux/time.h>
#include <asm/lowcore.h>
@@ -362,12 +363,19 @@ s390_revalidate_registers(struct mci *mci)
return kill_task;
}
+#define MAX_IPD_COUNT 29
+#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
+
/*
* machine check handler.
*/
void
s390_do_machine_check(struct pt_regs *regs)
{
+ static DEFINE_SPINLOCK(ipd_lock);
+ static unsigned long long last_ipd;
+ static int ipd_count;
+ unsigned long long tmp;
struct mci *mci;
struct mcck_struct *mcck;
int umode;
@@ -404,11 +412,27 @@ s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage("processing backup machine "
"check with damage.");
}
- if (!umode)
- s390_handle_damage("processing backup machine "
- "check in kernel mode.");
- mcck->kill_task = 1;
- mcck->mcck_code = *(unsigned long long *) mci;
+
+ /*
+ * Nullifying exigent condition, therefore we might
+ * retry this instruction.
+ */
+
+ spin_lock(&ipd_lock);
+
+ tmp = get_clock();
+
+ if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
+ ipd_count++;
+ else
+ ipd_count = 1;
+
+ last_ipd = tmp;
+
+ if (ipd_count == MAX_IPD_COUNT)
+ s390_handle_damage("too many ipd retries.");
+
+ spin_unlock(&ipd_lock);
}
else {
/* Processing damage -> stopping machine */
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 383a95f34a0d..239e108b8ed1 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -392,13 +392,16 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
return -ENOMEM;
}
- prom_getproperty(op.op_nodeid, str, tmp, len);
-
- tmp[len] = '\0';
+ cnt = prom_getproperty(op.op_nodeid, str, tmp, len);
+ if (cnt <= 0) {
+ error = -EINVAL;
+ } else {
+ tmp[len] = '\0';
- if (__copy_to_user(argp, &op, sizeof(op)) != 0
- || copy_to_user(op.op_buf, tmp, len) != 0)
- error = -EFAULT;
+ if (__copy_to_user(argp, &op, sizeof(op)) != 0 ||
+ copy_to_user(op.op_buf, tmp, len) != 0)
+ error = -EFAULT;
+ }
kfree(tmp);
kfree(str);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3e7302692dbe..a480a3742d47 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -446,7 +446,9 @@ config SCSI_DPT_I2O
config SCSI_ADVANSYS
tristate "AdvanSys SCSI support"
- depends on (ISA || EISA || PCI) && SCSI && BROKEN
+ depends on SCSI
+ depends on ISA || EISA || PCI
+ depends on BROKEN || X86_32
help
This is a driver for all SCSI host adapters manufactured by
AdvanSys. It is documented in the kernel source in
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 28b93057b607..2a419634b256 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -2051,7 +2051,7 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
#define ADV_VADDR_TO_U32 virt_to_bus
#define ADV_U32_TO_VADDR bus_to_virt
-#define AdvPortAddr ulong /* Virtual memory address size */
+#define AdvPortAddr void __iomem * /* Virtual memory address size */
/*
* Define Adv Library required memory access macros.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index cb30d9c1153d..0c9c2f400bf6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -219,6 +219,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahc->flags |= AHC_39BIT_ADDRESSING;
} else {
if (dma_set_mask(dev, DMA_32BIT_MASK)) {
+ ahc_free(ahc);
printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
return (-ENODEV);
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 5f586140e057..3adecef21783 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -2036,12 +2036,12 @@ ahc_pci_resume(struct ahc_softc *ahc)
* that the OS doesn't know about and rely on our chip
* reset handler to handle the rest.
*/
- ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
- ahc->bus_softc.pci_softc.devconfig);
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
- ahc->bus_softc.pci_softc.command);
- ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
- ahc->bus_softc.pci_softc.csize_lattime);
+ ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+ ahc->bus_softc.pci_softc.devconfig, /*bytes*/4);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+ ahc->bus_softc.pci_softc.command, /*bytes*/1);
+ ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
+ ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1);
if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
struct seeprom_descriptor sd;
u_int sxfrctl1;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 0a8ad37ae899..2e9be83a697f 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -739,7 +739,8 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
{
struct viosrp_adapter_info *req;
struct srp_event_struct *evt_struct;
-
+ dma_addr_t addr;
+
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
@@ -757,10 +758,10 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
req->common.length = sizeof(hostdata->madapter_info);
- req->buffer = dma_map_single(hostdata->dev,
- &hostdata->madapter_info,
- sizeof(hostdata->madapter_info),
- DMA_BIDIRECTIONAL);
+ req->buffer = addr = dma_map_single(hostdata->dev,
+ &hostdata->madapter_info,
+ sizeof(hostdata->madapter_info),
+ DMA_BIDIRECTIONAL);
if (dma_mapping_error(req->buffer)) {
printk(KERN_ERR
@@ -770,8 +771,13 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
return;
}
- if (ibmvscsi_send_srp_event(evt_struct, hostdata))
+ if (ibmvscsi_send_srp_event(evt_struct, hostdata)) {
printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+ dma_unmap_single(hostdata->dev,
+ addr,
+ sizeof(hostdata->madapter_info),
+ DMA_BIDIRECTIONAL);
+ }
};
/**
@@ -1259,6 +1265,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
{
struct viosrp_host_config *host_config;
struct srp_event_struct *evt_struct;
+ dma_addr_t addr;
int rc;
evt_struct = get_event_struct(&hostdata->pool);
@@ -1279,8 +1286,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
memset(host_config, 0x00, sizeof(*host_config));
host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
host_config->common.length = length;
- host_config->buffer = dma_map_single(hostdata->dev, buffer, length,
- DMA_BIDIRECTIONAL);
+ host_config->buffer = addr = dma_map_single(hostdata->dev, buffer,
+ length,
+ DMA_BIDIRECTIONAL);
if (dma_mapping_error(host_config->buffer)) {
printk(KERN_ERR
@@ -1291,11 +1299,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
init_completion(&evt_struct->comp);
rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
- if (rc == 0) {
+ if (rc == 0)
wait_for_completion(&evt_struct->comp);
- dma_unmap_single(hostdata->dev, host_config->buffer,
- length, DMA_BIDIRECTIONAL);
- }
+ dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
return rc;
}
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index bd147207f25d..de9ba7890b5a 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -864,6 +864,9 @@ static unsigned int ata_id_xfermask(const u16 *id)
/**
* ata_port_queue_task - Queue port_task
* @ap: The ata_port to queue port_task for
+ * @fn: workqueue function to be scheduled
+ * @data: data value to pass to workqueue function
+ * @delay: delay time for workqueue function
*
* Schedule @fn(@data) for execution after @delay jiffies using
* port_task. There is one port_task per port and it's the
@@ -2739,6 +2742,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
* ata_dev_init_params - Issue INIT DEV PARAMS command
* @ap: Port associated with device @dev
* @dev: Device to which command will be sent
+ * @heads: Number of heads (taskfile parameter)
+ * @sectors: Number of sectors (taskfile parameter)
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3638,6 +3643,8 @@ static void ata_pio_block(struct ata_port *ap)
ata_pio_sector(qc);
}
+
+ ata_altstatus(ap); /* flush */
}
static void ata_pio_error(struct ata_port *ap)
@@ -3754,11 +3761,14 @@ static void atapi_packet_task(void *_data)
spin_lock_irqsave(&ap->host_set->lock, flags);
ap->flags &= ~ATA_FLAG_NOINTR;
ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
+
if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
ap->ops->bmdma_start(qc); /* initiate bmdma */
spin_unlock_irqrestore(&ap->host_set->lock, flags);
} else {
ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
/* PIO commands are handled by polling */
ap->hsm_task_state = HSM_ST;
@@ -4287,6 +4297,8 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
{
if (ap->flags & ATA_FLAG_SUSPENDED) {
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
ap->flags &= ~ATA_FLAG_SUSPENDED;
ata_set_mode(ap);
}
@@ -4302,6 +4314,7 @@ int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
* ata_device_suspend - prepare a device for suspend
* @ap: port the device is connected to
* @dev: the device to suspend
+ * @state: target power management state
*
* Flush the cache on the drive, if appropriate, then issue a
* standbynow command.
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fad607b2e6f4..ee22173fce43 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -27,7 +27,6 @@ void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 8932b1be2b60..41cf5d3ea6ce 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -113,6 +113,7 @@ struct lpfc_nodelist {
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */
#define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */
+#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
/* Defines for list searchs */
#define NLP_SEARCH_MAPPED 0x1 /* search mapped */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4813beaaca8f..283b7d824c34 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -302,10 +302,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
goto fail_free_mbox;
- /*
- * set_slim mailbox command needs to execute first,
- * queue this command to be processed later.
- */
mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
mbox->context2 = ndlp;
@@ -781,25 +777,26 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (disc && phba->num_disc_nodes) {
/* Check to see if there are more PLOGIs to be sent */
lpfc_more_plogi(phba);
- }
- if (phba->num_disc_nodes == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ if (phba->num_disc_nodes == 0) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
- /* Check to see if more RSCNs came in while we were
- * processing this one.
- */
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
- } else {
- lpfc_els_handle_rscn(phba);
+ lpfc_can_disctmo(phba);
+ if (phba->fc_flag & FC_RSCN_MODE) {
+ /*
+ * Check to see if more RSCNs came in while
+ * we were processing this one.
+ */
+ if ((phba->fc_rscn_id_cnt == 0) &&
+ (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(phba->host->host_lock);
+ } else {
+ lpfc_els_handle_rscn(phba);
+ }
}
}
}
@@ -1263,7 +1260,7 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
- cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name));
+ cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_LOGO);
if (!elsiocb)
@@ -1451,22 +1448,23 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
* PLOGIs to be sent
*/
lpfc_more_plogi(phba);
- }
- if (phba->num_disc_nodes == 0) {
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
- /* Check to see if more RSCNs
- * came in while we were
- * processing this one.
- */
- if((phba->fc_rscn_id_cnt==0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- phba->fc_flag &= ~FC_RSCN_MODE;
- }
- else {
- lpfc_els_handle_rscn(phba);
+ if (phba->num_disc_nodes == 0) {
+ phba->fc_flag &= ~FC_NDISC_ACTIVE;
+ lpfc_can_disctmo(phba);
+ if (phba->fc_flag & FC_RSCN_MODE) {
+ /*
+ * Check to see if more RSCNs
+ * came in while we were
+ * processing this one.
+ */
+ if((phba->fc_rscn_id_cnt==0) &&
+ !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
+ phba->fc_flag &= ~FC_RSCN_MODE;
+ }
+ else {
+ lpfc_els_handle_rscn(phba);
+ }
}
}
}
@@ -1872,9 +1870,6 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (mbox) {
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
- /* set_slim mailbox command needs to execute first,
- * queue this command to be processed later.
- */
lpfc_unreg_rpi(phba, ndlp);
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
mbox->context2 = ndlp;
@@ -1920,6 +1915,7 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
uint8_t *pcmd;
uint16_t cmdsize;
int rc;
+ ELS_PKT *els_pkt_ptr;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
@@ -1958,6 +1954,23 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
pcmd += sizeof (uint32_t);
memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
break;
+ case ELS_CMD_PRLO:
+ cmdsize = sizeof (uint32_t) + sizeof (PRLO);
+ elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+ memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
+ sizeof (uint32_t) + sizeof (PRLO));
+ *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
+ els_pkt_ptr = (ELS_PKT *) pcmd;
+ els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
+ break;
default:
return 1;
}
@@ -2498,7 +2511,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
- if (phba->hba_state < LPFC_NS_QRY) {
+ if (phba->hba_state <= LPFC_NS_QRY) {
lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
newnode);
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 6721e679df62..adb086009ae0 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -311,8 +311,8 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
evtp->evt_arg2 = arg2;
evtp->evt = evt;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
spin_lock_irq(phba->host->host_lock);
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
if (phba->work_wait)
wake_up(phba->work_wait);
spin_unlock_irq(phba->host->host_lock);
@@ -1071,10 +1071,6 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
/* initialize static port data */
rport->maxframe_size = ndlp->nlp_maxframe;
rport->supported_classes = ndlp->nlp_class_sup;
- if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < MAX_FCP_TARGET)) {
- ndlp->nlp_sid = rport->scsi_target_id;
- }
rdata = rport->dd_data;
rdata->pnode = ndlp;
@@ -1087,6 +1083,10 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN)
fc_remote_port_rolechg(rport, rport_ids.roles);
+ if ((rport->scsi_target_id != -1) &&
+ (rport->scsi_target_id < MAX_FCP_TARGET)) {
+ ndlp->nlp_sid = rport->scsi_target_id;
+ }
return;
}
@@ -1238,6 +1238,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
evt_listp);
}
+ nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
nlp->nlp_type |= NLP_FC_NODE;
break;
case NLP_MAPPED_LIST:
@@ -1258,6 +1259,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
evt_listp);
}
+ nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
break;
case NLP_NPR_LIST:
nlp->nlp_flag |= list;
@@ -1402,6 +1404,8 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi)
return 1;
case CMD_ELS_REQUEST64_CR:
+ if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
+ return 1;
case CMD_XMIT_ELS_RSP64_CX:
if (iocb->context1 == (uint8_t *) ndlp)
return 1;
@@ -1901,10 +1905,8 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
*/
if (ndlp->nlp_flag & NLP_DELAY_TMO)
lpfc_cancel_retry_delay_tmo(phba, ndlp);
- } else {
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ } else
ndlp = NULL;
- }
} else {
flg = ndlp->nlp_flag & NLP_LIST_MASK;
if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST))
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 54d04188f7cc..eedf98801366 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -449,6 +449,7 @@ struct serv_parm { /* Structure is in Big Endian format */
#define ELS_CMD_RRQ 0x12000000
#define ELS_CMD_PRLI 0x20100014
#define ELS_CMD_PRLO 0x21100014
+#define ELS_CMD_PRLO_ACC 0x02100014
#define ELS_CMD_PDISC 0x50000000
#define ELS_CMD_FDISC 0x51000000
#define ELS_CMD_ADISC 0x52000000
@@ -484,6 +485,7 @@ struct serv_parm { /* Structure is in Big Endian format */
#define ELS_CMD_RRQ 0x12
#define ELS_CMD_PRLI 0x14001020
#define ELS_CMD_PRLO 0x14001021
+#define ELS_CMD_PRLO_ACC 0x14001002
#define ELS_CMD_PDISC 0x50
#define ELS_CMD_FDISC 0x51
#define ELS_CMD_ADISC 0x52
@@ -1539,6 +1541,7 @@ typedef struct {
#define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */
#define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */
+#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */
uint32_t link_speed;
#define LINK_SPEED_AUTO 0 /* Auto selection */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 66d5d003555d..908d0f27706f 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -294,15 +294,6 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
}
- /* This should turn on DELAYED ABTS for ELS timeouts */
- lpfc_set_slim(phba, pmb, 0x052198, 0x1);
- if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- phba->hba_state = LPFC_HBA_ERROR;
- mempool_free( pmb, phba->mbox_mem_pool);
- return -EIO;
- }
-
-
lpfc_read_config(phba, pmb);
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
lpfc_printf_log(phba,
@@ -804,7 +795,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
int max_speed;
char * ports;
char * bus;
- } m;
+ } m = {"<Unknown>", 0, "", ""};
pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
ports = (hdrtype == 0x80) ? "2-port " : "";
@@ -1627,7 +1618,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
error = lpfc_alloc_sysfs_attr(phba);
if (error)
- goto out_kthread_stop;
+ goto out_remove_host;
error = request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ,
LPFC_DRIVER_NAME, phba);
@@ -1644,8 +1635,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
error = lpfc_sli_hba_setup(phba);
- if (error)
+ if (error) {
+ error = -ENODEV;
goto out_free_irq;
+ }
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
spin_lock_irq(phba->host->host_lock);
@@ -1700,6 +1693,9 @@ out_free_irq:
free_irq(phba->pcidev->irq, phba);
out_free_sysfs_attr:
lpfc_free_sysfs_attr(phba);
+out_remove_host:
+ fc_remove_host(phba->host);
+ scsi_remove_host(phba->host);
out_kthread_stop:
kthread_stop(phba->worker_thread);
out_free_iocbq:
@@ -1721,12 +1717,14 @@ out_iounmap_slim:
out_idr_remove:
idr_remove(&lpfc_hba_index, phba->brd_no);
out_put_host:
+ phba->host = NULL;
scsi_host_put(host);
out_release_regions:
pci_release_regions(pdev);
out_disable_device:
pci_disable_device(pdev);
out:
+ pci_set_drvdata(pdev, NULL);
return error;
}
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index c585e2b2e589..e42f22aaf71b 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -200,6 +200,9 @@ lpfc_init_link(struct lpfc_hba * phba,
break;
}
+ /* Enable asynchronous ABTS responses from firmware */
+ mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT;
+
/* NEW_FEATURE
* Setting up the link speed
*/
@@ -292,36 +295,6 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
return;
}
-/***********************************************/
-
-/* command to write slim */
-/***********************************************/
-void
-lpfc_set_slim(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr,
- uint32_t value)
-{
- MAILBOX_t *mb;
-
- mb = &pmb->mb;
- memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
-
- /* addr = 0x090597 is AUTO ABTS disable for ELS commands */
- /* addr = 0x052198 is DELAYED ABTS enable for ELS commands */
-
- /*
- * Always turn on DELAYED ABTS for ELS timeouts
- */
- if ((addr == 0x052198) && (value == 0))
- value = 1;
-
- mb->un.varWords[0] = addr;
- mb->un.varWords[1] = value;
-
- mb->mbxCommand = MBX_SET_SLIM;
- mb->mbxOwner = OWN_HOST;
- return;
-}
-
/**********************************************/
/* lpfc_read_nv Issue a READ CONFIG */
/* mailbox command */
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 3d77bd999b70..27d60ad897cd 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -465,14 +465,18 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
static int
lpfc_rcv_logo(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb)
+ struct lpfc_iocbq *cmdiocb,
+ uint32_t els_cmd)
{
/* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */
/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
* PLOGIs during LOGO storms from a device.
*/
ndlp->nlp_flag |= NLP_LOGO_ACC;
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ if (els_cmd == ELS_CMD_PRLO)
+ lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ else
+ lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
if (!(ndlp->nlp_type & NLP_FABRIC) ||
(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
@@ -681,7 +685,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp, 1);
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -788,10 +792,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
if (lpfc_reg_login
(phba, irsp->un.elsreq64.remoteID,
(uint8_t *) sp, mbox, 0) == 0) {
- /* set_slim mailbox command needs to
- * execute first, queue this command to
- * be processed later.
- */
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl =
@@ -832,11 +832,17 @@ static uint32_t
lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
- /* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ return ndlp->nlp_state;
+ }
+ else {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(phba, ndlp, 1);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- return NLP_STE_FREED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
}
static uint32_t
@@ -851,7 +857,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
return ndlp->nlp_state;
@@ -905,7 +911,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
/* software abort outstanding ADISC */
lpfc_els_abort(phba, ndlp, 0);
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -932,7 +938,7 @@ lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
@@ -987,11 +993,17 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg,
uint32_t evt)
{
- /* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp, 1);
+ if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ return ndlp->nlp_state;
+ }
+ else {
+ /* software abort outstanding ADISC */
+ lpfc_els_abort(phba, ndlp, 1);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- return NLP_STE_FREED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
}
static uint32_t
@@ -1006,7 +1018,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
ndlp->nlp_flag |= NLP_NPR_ADISC;
spin_unlock_irq(phba->host->host_lock);
@@ -1048,7 +1060,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1073,7 +1085,7 @@ lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba,
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
@@ -1133,8 +1145,14 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg,
uint32_t evt)
{
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- return NLP_STE_FREED_NODE;
+ if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ return ndlp->nlp_state;
+ }
+ else {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
}
static uint32_t
@@ -1146,7 +1164,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
return ndlp->nlp_state;
}
@@ -1186,7 +1204,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
/* Software abort outstanding PRLI before sending acc */
lpfc_els_abort(phba, ndlp, 1);
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1214,7 +1232,7 @@ lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba,
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
@@ -1278,11 +1296,17 @@ static uint32_t
lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
- /* software abort outstanding PRLI */
- lpfc_els_abort(phba, ndlp, 1);
+ if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ return ndlp->nlp_state;
+ }
+ else {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(phba, ndlp, 1);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- return NLP_STE_FREED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
}
@@ -1313,7 +1337,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
return ndlp->nlp_state;
}
@@ -1351,7 +1375,7 @@ lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1375,7 +1399,7 @@ lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
@@ -1386,7 +1410,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
lpfc_disc_set_adisc(phba, ndlp);
return ndlp->nlp_state;
@@ -1424,7 +1448,7 @@ lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1456,7 +1480,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba,
spin_unlock_irq(phba->host->host_lock);
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
@@ -1469,7 +1493,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
ndlp->nlp_state = NLP_STE_NPR_NODE;
lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
lpfc_disc_set_adisc(phba, ndlp);
return ndlp->nlp_state;
@@ -1551,7 +1575,7 @@ lpfc_rcv_logo_npr_node(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_logo(phba, ndlp, cmdiocb);
+ lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1617,9 +1641,16 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
+ IOCB_t *irsp;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
+
+ irsp = &rspiocb->iocb;
+ if (irsp->ulpStatus) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
return ndlp->nlp_state;
}
@@ -1628,9 +1659,16 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
+ IOCB_t *irsp;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
+
+ irsp = &rspiocb->iocb;
+ if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
return ndlp->nlp_state;
}
@@ -1649,9 +1687,16 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
+ IOCB_t *irsp;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
+
+ irsp = &rspiocb->iocb;
+ if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
return ndlp->nlp_state;
}
@@ -1668,7 +1713,12 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
if (!mb->mbxStatus)
ndlp->nlp_rpi = mb->un.varWords[0];
-
+ else {
+ if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ return NLP_STE_FREED_NODE;
+ }
+ }
return ndlp->nlp_state;
}
@@ -1677,6 +1727,10 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg,
uint32_t evt)
{
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ return ndlp->nlp_state;
+ }
lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
return NLP_STE_FREED_NODE;
}
@@ -1687,7 +1741,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba,
uint32_t evt)
{
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
lpfc_cancel_retry_delay_tmo(phba, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f93799873721..7dc4c2e6bed2 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -629,8 +629,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
struct lpfc_iocbq *piocbq;
IOCB_t *piocb;
struct fcp_cmnd *fcp_cmnd;
- struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device;
- struct lpfc_rport_data *rdata = scsi_dev->hostdata;
+ struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
@@ -665,56 +664,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
piocb->ulpTimeout = lpfc_cmd->timeout;
}
- lpfc_cmd->rdata = rdata;
-
- switch (task_mgmt_cmd) {
- case FCP_LUN_RESET:
- /* Issue LUN Reset to TGT <num> LUN <num> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_FCP,
- "%d:0703 Issue LUN Reset to TGT %d LUN %d "
- "Data: x%x x%x\n",
- phba->brd_no,
- scsi_dev->id, scsi_dev->lun,
- ndlp->nlp_rpi, ndlp->nlp_flag);
-
- break;
- case FCP_ABORT_TASK_SET:
- /* Issue Abort Task Set to TGT <num> LUN <num> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_FCP,
- "%d:0701 Issue Abort Task Set to TGT %d LUN %d "
- "Data: x%x x%x\n",
- phba->brd_no,
- scsi_dev->id, scsi_dev->lun,
- ndlp->nlp_rpi, ndlp->nlp_flag);
-
- break;
- case FCP_TARGET_RESET:
- /* Issue Target Reset to TGT <num> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_FCP,
- "%d:0702 Issue Target Reset to TGT %d "
- "Data: x%x x%x\n",
- phba->brd_no,
- scsi_dev->id, ndlp->nlp_rpi,
- ndlp->nlp_flag);
- break;
- }
-
return (1);
}
static int
-lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
+lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
+ unsigned tgt_id, struct lpfc_rport_data *rdata)
{
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
+ lpfc_cmd->rdata = rdata;
ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
if (!ret)
return FAILED;
@@ -726,6 +687,13 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
if (!iocbqrsp)
return FAILED;
+ /* Issue Target Reset to TGT <num> */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+ "%d:0702 Issue Target Reset to TGT %d "
+ "Data: x%x x%x\n",
+ phba->brd_no, tgt_id, rdata->pnode->nlp_rpi,
+ rdata->pnode->nlp_flag);
+
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -1021,6 +989,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
lpfc_cmd->pCmd = cmnd;
lpfc_cmd->timeout = 60;
lpfc_cmd->scsi_hba = phba;
+ lpfc_cmd->rdata = rdata;
ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
if (!ret)
@@ -1033,6 +1002,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (iocbqrsp == NULL)
goto out_free_scsi_buf;
+ lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+ "%d:0703 Issue LUN Reset to TGT %d LUN %d "
+ "Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
+ cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
+
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -1104,7 +1078,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
int match;
int ret = FAILED, i, err_count = 0;
int cnt, loopcnt;
- unsigned int midlayer_id = 0;
struct lpfc_scsi_buf * lpfc_cmd;
lpfc_block_requests(phba);
@@ -1124,7 +1097,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* targets known to the driver. Should any target reset
* fail, this routine returns failure to the midlayer.
*/
- midlayer_id = cmnd->device->id;
for (i = 0; i < MAX_FCP_TARGET; i++) {
/* Search the mapped list for this target ID */
match = 0;
@@ -1137,9 +1109,8 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
if (!match)
continue;
- lpfc_cmd->pCmd->device->id = i;
- lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba);
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba,
+ i, ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 Bus Reset on target %d failed\n",
@@ -1158,7 +1129,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* the targets. Unfortunately, some targets do not abide by
* this forcing the driver to double check.
*/
- cmnd->device->id = midlayer_id;
cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST);
if (cnt)
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 4cf1366108b7..6b737568b831 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.4"
+#define LPFC_DRIVER_VERSION "8.1.6"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 80b68a2481b3..de35ffe2f79d 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4471,7 +4471,6 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
{
Scsi_Cmnd *scmd;
struct scsi_device *sdev;
- unsigned long flags = 0;
scb_t *scb;
int rval;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index c11e5ce6865e..bec1424eda85 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mbox.c
- * Version : v2.20.4.7 (Nov 14 2005)
+ * Version : v2.20.4.8 (Apr 11 2006)
*
* Authors:
* Atul Mukker <Atul.Mukker@lsil.com>
@@ -2278,6 +2278,7 @@ megaraid_mbox_dpc(unsigned long devp)
unsigned long flags;
uint8_t c;
int status;
+ uioc_t *kioc;
if (!adapter) return;
@@ -2320,6 +2321,9 @@ megaraid_mbox_dpc(unsigned long devp)
// remove from local clist
list_del_init(&scb->list);
+ kioc = (uioc_t *)scb->gp;
+ kioc->status = 0;
+
megaraid_mbox_mm_done(adapter, scb);
continue;
@@ -2636,6 +2640,7 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
int recovery_window;
int recovering;
int i;
+ uioc_t *kioc;
adapter = SCP2ADAPTER(scp);
raid_dev = ADAP2RAIDDEV(adapter);
@@ -2655,32 +2660,51 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
// Also, reset all the commands currently owned by the driver
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
-
list_del_init(&scb->list); // from pending list
- con_log(CL_ANN, (KERN_WARNING
- "megaraid: %ld:%d[%d:%d], reset from pending list\n",
- scp->serial_number, scb->sno,
- scb->dev_channel, scb->dev_target));
+ if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: IOCTL packet with %d[%d:%d] being reset\n",
+ scb->sno, scb->dev_channel, scb->dev_target));
- scp->result = (DID_RESET << 16);
- scp->scsi_done(scp);
+ scb->status = -1;
- megaraid_dealloc_scb(adapter, scb);
+ kioc = (uioc_t *)scb->gp;
+ kioc->status = -EFAULT;
+
+ megaraid_mbox_mm_done(adapter, scb);
+ } else {
+ if (scb->scp == scp) { // Found command
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: %ld:%d[%d:%d], reset from pending list\n",
+ scp->serial_number, scb->sno,
+ scb->dev_channel, scb->dev_target));
+ } else {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: IO packet with %d[%d:%d] being reset\n",
+ scb->sno, scb->dev_channel, scb->dev_target));
+ }
+
+ scb->scp->result = (DID_RESET << 16);
+ scb->scp->scsi_done(scb->scp);
+
+ megaraid_dealloc_scb(adapter, scb);
+ }
}
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
if (adapter->outstanding_cmds) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: %d outstanding commands. Max wait %d sec\n",
- adapter->outstanding_cmds, MBOX_RESET_WAIT));
+ adapter->outstanding_cmds,
+ (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT)));
}
recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
recovering = adapter->outstanding_cmds;
- for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) {
+ for (i = 0; i < recovery_window; i++) {
megaraid_ack_sequence(adapter);
@@ -2689,12 +2713,11 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
con_log(CL_ANN, (
"megaraid mbox: Wait for %d commands to complete:%d\n",
adapter->outstanding_cmds,
- MBOX_RESET_WAIT - i));
+ (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i));
}
// bailout if no recovery happended in reset time
- if ((i == MBOX_RESET_WAIT) &&
- (recovering == adapter->outstanding_cmds)) {
+ if (adapter->outstanding_cmds == 0) {
break;
}
@@ -2918,12 +2941,13 @@ mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
wmb();
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
- for (i = 0; i < 0xFFFFF; i++) {
+ for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) {
if (mbox->numstatus != 0xFF) break;
rmb();
+ udelay(MBOX_SYNC_DELAY_200);
}
- if (i == 0xFFFFF) {
+ if (i == MBOX_SYNC_WAIT_CNT) {
// We may need to re-calibrate the counter
con_log(CL_ANN, (KERN_CRIT
"megaraid: fast sync command timed out\n"));
@@ -3475,7 +3499,7 @@ megaraid_cmm_register(adapter_t *adapter)
adp.drvr_data = (unsigned long)adapter;
adp.pdev = adapter->pdev;
adp.issue_uioc = megaraid_mbox_mm_handler;
- adp.timeout = 300;
+ adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
adp.max_kioc = MBOX_MAX_USER_CMDS;
if ((rval = mraid_mm_register_adp(&adp)) != 0) {
@@ -3702,7 +3726,6 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
unsigned long flags;
kioc = (uioc_t *)scb->gp;
- kioc->status = 0;
mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
mbox64->mbox32.status = scb->status;
raw_mbox = (uint8_t *)&mbox64->mbox32;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 882fb1a0b575..868fb0ec93e7 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -21,8 +21,8 @@
#include "megaraid_ioctl.h"
-#define MEGARAID_VERSION "2.20.4.7"
-#define MEGARAID_EXT_VERSION "(Release Date: Mon Nov 14 12:27:22 EST 2005)"
+#define MEGARAID_VERSION "2.20.4.8"
+#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)"
/*
@@ -100,6 +100,9 @@
#define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox
#define MBOX_RESET_WAIT 180 // wait these many seconds in reset
#define MBOX_RESET_EXT_WAIT 120 // extended wait reset
+#define MBOX_SYNC_WAIT_CNT 0xFFFF // wait loop index for synchronous mode
+
+#define MBOX_SYNC_DELAY_200 200 // 200 micro-seconds
/*
* maximum transfer that can happen through the firmware commands issued
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 8f3ce0432295..e8f534fb336b 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -898,10 +898,8 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
- if (!adapter) {
- rval = -ENOMEM;
- goto memalloc_error;
- }
+ if (!adapter)
+ return -ENOMEM;
memset(adapter, 0, sizeof(mraid_mmadp_t));
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index fee843fab1c7..108910f512e4 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -982,6 +982,12 @@ static int device_check(ppa_struct *dev)
return -ENODEV;
}
+static int ppa_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+ return 0;
+}
+
static struct scsi_host_template ppa_template = {
.module = THIS_MODULE,
.proc_name = "ppa",
@@ -997,6 +1003,7 @@ static struct scsi_host_template ppa_template = {
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
.can_queue = 1,
+ .slave_alloc = ppa_adjust_queue,
};
/***************************************************************************
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 017729c59a49..584fe5d8e507 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -599,6 +599,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
* Either SUCCESS or FAILED.
*
* Note:
+* Only return FAILED if command not returned by firmware.
**************************************************************************/
int
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
@@ -609,11 +610,12 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
unsigned long flags;
+ int wait = 0;
if (!CMD_SP(cmd))
- return FAILED;
+ return SUCCESS;
- ret = FAILED;
+ ret = SUCCESS;
id = cmd->device->id;
lun = cmd->device->lun;
@@ -642,7 +644,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
} else {
DEBUG3(printk("%s(%ld): abort_command "
"mbx success.\n", __func__, ha->host_no));
- ret = SUCCESS;
+ wait = 1;
}
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -651,17 +653,18 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Wait for the command to be returned. */
- if (ret == SUCCESS) {
+ if (wait) {
if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"scsi(%ld:%d:%d): Abort handler timed out -- %lx "
"%x.\n", ha->host_no, id, lun, serial, ret);
+ ret = FAILED;
}
}
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no,
- id, lun, serial, ret);
+ "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
+ ha->host_no, id, lun, wait, serial, ret);
return ret;
}
@@ -1700,8 +1703,8 @@ qla2x00_free_device(scsi_qla_host_t *ha)
ha->flags.online = 0;
/* Detach interrupts */
- if (ha->pdev->irq)
- free_irq(ha->pdev->irq, ha);
+ if (ha->host->irq)
+ free_irq(ha->host->irq, ha);
/* release io space registers */
if (ha->iobase)
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index d5fdcb9a8842..f16f92a6ec0f 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -37,7 +37,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -50,6 +50,12 @@ enum {
MV_PCI_REG_BASE = 0,
MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
+ MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
+ MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
+ MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
+ MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
+ MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
+
MV_SATAHC0_REG_BASE = 0x20000,
MV_FLASH_CTL = 0x1046c,
MV_GPIO_PORT_CTL = 0x104f0,
@@ -302,9 +308,6 @@ struct mv_port_priv {
dma_addr_t crpb_dma;
struct mv_sg *sg_tbl;
dma_addr_t sg_tbl_dma;
-
- unsigned req_producer; /* cp of req_in_ptr */
- unsigned rsp_consumer; /* cp of rsp_out_ptr */
u32 pp_flags;
};
@@ -937,8 +940,6 @@ static int mv_port_start(struct ata_port *ap)
writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
- pp->req_producer = pp->rsp_consumer = 0;
-
/* Don't turn on EDMA here...do it before DMA commands only. Else
* we'll be unable to send non-data, PIO, etc due to restricted access
* to shadow regs.
@@ -1022,16 +1023,16 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
}
}
-static inline unsigned mv_inc_q_index(unsigned *index)
+static inline unsigned mv_inc_q_index(unsigned index)
{
- *index = (*index + 1) & MV_MAX_Q_DEPTH_MASK;
- return *index;
+ return (index + 1) & MV_MAX_Q_DEPTH_MASK;
}
static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last)
{
- *cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
+ u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
(last ? CRQB_CMD_LAST : 0);
+ *cmdw = cpu_to_le16(tmp);
}
/**
@@ -1053,15 +1054,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
u16 *cw;
struct ata_taskfile *tf;
u16 flags = 0;
+ unsigned in_index;
if (ATA_PROT_DMA != qc->tf.protocol)
return;
- /* the req producer index should be the same as we remember it */
- WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
- EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- pp->req_producer);
-
/* Fill in command request block
*/
if (!(qc->tf.flags & ATA_TFLAG_WRITE))
@@ -1069,13 +1066,17 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
- pp->crqb[pp->req_producer].sg_addr =
+ /* get current queue index from hardware */
+ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ pp->crqb[in_index].sg_addr =
cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
- pp->crqb[pp->req_producer].sg_addr_hi =
+ pp->crqb[in_index].sg_addr_hi =
cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
- pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags);
+ pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
- cw = &pp->crqb[pp->req_producer].ata_cmd[0];
+ cw = &pp->crqb[in_index].ata_cmd[0];
tf = &qc->tf;
/* Sadly, the CRQB cannot accomodate all registers--there are
@@ -1144,16 +1145,12 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
struct mv_port_priv *pp = ap->private_data;
struct mv_crqb_iie *crqb;
struct ata_taskfile *tf;
+ unsigned in_index;
u32 flags = 0;
if (ATA_PROT_DMA != qc->tf.protocol)
return;
- /* the req producer index should be the same as we remember it */
- WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
- EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- pp->req_producer);
-
/* Fill in Gen IIE command request block
*/
if (!(qc->tf.flags & ATA_TFLAG_WRITE))
@@ -1162,7 +1159,11 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
- crqb = (struct mv_crqb_iie *) &pp->crqb[pp->req_producer];
+ /* get current queue index from hardware */
+ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
crqb->flags = cpu_to_le32(flags);
@@ -1210,6 +1211,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
{
void __iomem *port_mmio = mv_ap_base(qc->ap);
struct mv_port_priv *pp = qc->ap->private_data;
+ unsigned in_index;
u32 in_ptr;
if (ATA_PROT_DMA != qc->tf.protocol) {
@@ -1221,23 +1223,20 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
- in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+ in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+ in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
- /* the req producer index should be the same as we remember it */
- WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- pp->req_producer);
/* until we do queuing, the queue should be empty at this point */
- WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
- EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+ WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
- mv_inc_q_index(&pp->req_producer); /* now incr producer index */
+ in_index = mv_inc_q_index(in_index); /* now incr producer index */
mv_start_dma(port_mmio, pp);
/* and write the request in pointer to kick the EDMA to life */
in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
- in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT;
+ in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
return 0;
@@ -1260,28 +1259,26 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
+ unsigned out_index;
u32 out_ptr;
u8 ata_status;
- out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
-
- /* the response consumer index should be the same as we remember it */
- WARN_ON(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- pp->rsp_consumer);
+ out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+ out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
- ata_status = pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT;
+ ata_status = le16_to_cpu(pp->crpb[out_index].flags)
+ >> CRPB_FLAG_STATUS_SHIFT;
/* increment our consumer index... */
- pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
+ out_index = mv_inc_q_index(out_index);
/* and, until we do NCQ, there should only be 1 CRPB waiting */
- WARN_ON(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
- EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
- pp->rsp_consumer);
+ WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
+ >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
/* write out our inc'd consumer index so EDMA knows we're caught up */
out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
- out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT;
+ out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
/* Return ATA status register for completed CRPB */
@@ -1291,6 +1288,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
/**
* mv_err_intr - Handle error interrupts on the port
* @ap: ATA channel to manipulate
+ * @reset_allowed: bool: 0 == don't trigger from reset here
*
* In most cases, just clear the interrupt and move on. However,
* some cases require an eDMA reset, which is done right before
@@ -1301,7 +1299,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap)
+static void mv_err_intr(struct ata_port *ap, int reset_allowed)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, serr = 0;
@@ -1323,9 +1321,8 @@ static void mv_err_intr(struct ata_port *ap)
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
/* check for fatal here and recover if needed */
- if (EDMA_ERR_FATAL & edma_err_cause) {
+ if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
mv_stop_and_reset(ap);
- }
}
/**
@@ -1374,12 +1371,12 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
struct ata_port *ap = host_set->ports[port];
struct mv_port_priv *pp = ap->private_data;
- hard_port = port & MV_PORT_MASK; /* range 0-3 */
+ hard_port = mv_hardport_from_port(port); /* range 0..3 */
handled = 0; /* ensure ata_status is set if handled++ */
/* Note that DEV_IRQ might happen spuriously during EDMA,
- * and should be ignored in such cases. We could mask it,
- * but it's pretty rare and may not be worth the overhead.
+ * and should be ignored in such cases.
+ * The cause of this is still under investigation.
*/
if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
/* EDMA: check for response queue interrupt */
@@ -1393,6 +1390,11 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
ata_status = readb((void __iomem *)
ap->ioaddr.status_addr);
handled = 1;
+ /* ignore spurious intr if drive still BUSY */
+ if (ata_status & ATA_BUSY) {
+ ata_status = 0;
+ handled = 0;
+ }
}
}
@@ -1406,7 +1408,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
shift++; /* skip bit 8 in the HC Main IRQ reg */
}
if ((PORT0_ERR << shift) & relevant) {
- mv_err_intr(ap);
+ mv_err_intr(ap, 1);
err_mask |= AC_ERR_OTHER;
handled = 1;
}
@@ -1448,6 +1450,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
struct ata_host_set *host_set = dev_instance;
unsigned int hc, handled = 0, n_hcs;
void __iomem *mmio = host_set->mmio_base;
+ struct mv_host_priv *hpriv;
u32 irq_stat;
irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
@@ -1469,6 +1472,17 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
handled++;
}
}
+
+ hpriv = host_set->private_data;
+ if (IS_60XX(hpriv)) {
+ /* deal with the interrupt coalescing bits */
+ if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
+ }
+ }
+
if (PCI_ERR & irq_stat) {
printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
readl(mmio + PCI_IRQ_CAUSE_OFS));
@@ -1867,7 +1881,8 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
if (IS_60XX(hpriv)) {
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
- ifctl |= (1 << 12) | (1 << 7);
+ ifctl |= (1 << 7); /* enable gen2i speed */
+ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
}
@@ -2020,6 +2035,7 @@ static void mv_phy_reset(struct ata_port *ap)
static void mv_eng_timeout(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
+ unsigned long flags;
printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
DPRINTK("All regs @ start of eng_timeout\n");
@@ -2031,11 +2047,16 @@ static void mv_eng_timeout(struct ata_port *ap)
ap->host_set->mmio_base, ap, qc, qc->scsicmd,
&qc->scsicmd->cmnd);
- mv_err_intr(ap);
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ mv_err_intr(ap, 0);
mv_stop_and_reset(ap);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
- qc->err_mask |= AC_ERR_TIMEOUT;
- ata_eh_qc_complete(qc);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ata_eh_qc_complete(qc);
+ }
}
/**
@@ -2229,7 +2250,8 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
void __iomem *port_mmio = mv_port_base(mmio, port);
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
- ifctl |= (1 << 12);
+ ifctl |= (1 << 7); /* enable gen2i speed */
+ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
}
@@ -2330,6 +2352,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
return rc;
}
+ pci_set_master(pdev);
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index f7264fd611c2..cb9082fd7e2f 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -454,7 +454,7 @@ static int sil24_softreset(struct ata_port *ap, int verbose,
*/
msleep(10);
- prb->ctrl = PRB_CTRL_SRST;
+ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
prb->fis[1] = 0; /* no PM yet */
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
@@ -551,9 +551,9 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
if (qc->tf.flags & ATA_TFLAG_WRITE)
- prb->ctrl = PRB_CTRL_PACKET_WRITE;
+ prb->ctrl = cpu_to_le16(PRB_CTRL_PACKET_WRITE);
else
- prb->ctrl = PRB_CTRL_PACKET_READ;
+ prb->ctrl = cpu_to_le16(PRB_CTRL_PACKET_READ);
} else
prb->ctrl = 0;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index c750d3399a97..62f8cb7b3d2b 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -56,6 +56,8 @@ static struct {
{"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */
{"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */
{"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */
+ {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */
+ {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */
{"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */
{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */
{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */
@@ -163,6 +165,7 @@ static struct {
{"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
{"HP", "C1557A", NULL, BLIST_FORCELUN},
{"HP", "C3323-300", "4269", BLIST_NOTQ},
+ {"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7b0f9a3810d2..faee4757c03a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -367,7 +367,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
int nsegs, unsigned bufflen, gfp_t gfp)
{
struct request_queue *q = rq->q;
- int nr_pages = (bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned int data_len = 0, len, bytes, off;
struct page *page;
struct bio *bio = NULL;
@@ -1067,16 +1067,29 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
break;
case NOT_READY:
/*
- * If the device is in the process of becoming ready,
- * retry.
+ * If the device is in the process of becoming
+ * ready, or has a temporary blockage, retry.
*/
- if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) {
- scsi_requeue_command(q, cmd);
- return;
+ if (sshdr.asc == 0x04) {
+ switch (sshdr.ascq) {
+ case 0x01: /* becoming ready */
+ case 0x04: /* format in progress */
+ case 0x05: /* rebuild in progress */
+ case 0x06: /* recalculation in progress */
+ case 0x07: /* operation in progress */
+ case 0x08: /* Long write in progress */
+ case 0x09: /* self test in progress */
+ scsi_requeue_command(q, cmd);
+ return;
+ default:
+ break;
+ }
}
- if (!(req->flags & REQ_QUIET))
+ if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "Device not ready.\n");
+ "Device not ready: ");
+ scsi_print_sense_hdr("", &sshdr);
+ }
scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 8b6d65e21bae..f3b16066387c 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -955,7 +955,8 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
- if (rphy->scsi_target_id == -1)
+ if (rphy->identify.device_type != SAS_END_DEVICE ||
+ rphy->scsi_target_id == -1)
continue;
if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
@@ -977,7 +978,6 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
#define SETUP_TEMPLATE(attrb, field, perm, test) \
i->private_##attrb[count] = class_device_attr_##field; \
i->private_##attrb[count].attr.mode = perm; \
- i->private_##attrb[count].store = NULL; \
i->attrb[count] = &i->private_##attrb[count]; \
if (test) \
count++
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 3274ab76c8d3..255886a9ac55 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -75,7 +75,7 @@ param_setup(char *str)
else if(!strncmp(pos, "id:", 3)) {
if(slot == -1) {
printk(KERN_WARNING "sim710: Must specify slot for id parameter\n");
- } else if(slot > MAX_SLOTS) {
+ } else if(slot >= MAX_SLOTS) {
printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val);
} else {
id_array[slot] = val;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index d40e7c871c36..56cb49006116 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4054,7 +4054,7 @@ static int st_probe(struct device *dev)
}
sdev_printk(KERN_WARNING, SDp,
- "Attached scsi tape %s", tape_name(tpnt));
+ "Attached scsi tape %s\n", tape_name(tpnt));
printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n",
tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
queue_dma_alignment(SDp->request_queue) + 1);
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 674b15c78f68..bbf78aaf9e01 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value)
#define serial_inp(up, offset) serial_in(up, offset)
#define serial_outp(up, offset, value) serial_out(up, offset, value)
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_outp(up, UART_DLL, value & 0xff);
+ serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+ if (up->port.iotype == UPIO_AU)
+ return __raw_readl(up->port.membase + 0x28);
+ else
+ return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ if (up->port.iotype == UPIO_AU)
+ __raw_writel(value, up->port.membase + 0x28);
+ else
+ _serial_dl_write(up, value);
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
/*
* For the 16C950
@@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up)
*/
static int size_fifo(struct uart_8250_port *up)
{
- unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
+ unsigned char old_fcr, old_mcr, old_lcr;
+ unsigned short old_dl;
int count;
old_lcr = serial_inp(up, UART_LCR);
@@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up)
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_MCR, UART_MCR_LOOP);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- old_dll = serial_inp(up, UART_DLL);
- old_dlm = serial_inp(up, UART_DLM);
- serial_outp(up, UART_DLL, 0x01);
- serial_outp(up, UART_DLM, 0x00);
+ old_dl = serial_dl_read(up);
+ serial_dl_write(up, 0x0001);
serial_outp(up, UART_LCR, 0x03);
for (count = 0; count < 256; count++)
serial_outp(up, UART_TX, count);
@@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up)
serial_outp(up, UART_FCR, old_fcr);
serial_outp(up, UART_MCR, old_mcr);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- serial_outp(up, UART_DLL, old_dll);
- serial_outp(up, UART_DLM, old_dlm);
+ serial_dl_write(up, old_dl);
serial_outp(up, UART_LCR, old_lcr);
return count;
@@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_outp(up, UART_LCR, 0xE0);
- quot = serial_inp(up, UART_DLM) << 8;
- quot += serial_inp(up, UART_DLL);
+ quot = serial_dl_read(up);
quot <<= 3;
status1 = serial_in(up, 0x04); /* EXCR1 */
@@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
- serial_outp(up, UART_DLL, quot & 0xff);
- serial_outp(up, UART_DLM, quot >> 8);
+ serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
@@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_dl_write(up, quot);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -1906,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
int ret = 0;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -1938,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -2200,10 +2235,17 @@ static void
serial8250_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
+ unsigned long flags;
unsigned int ier;
+ int locked = 1;
touch_nmi_watchdog();
+ if (oops_in_progress) {
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ } else
+ spin_lock_irqsave(&up->port.lock, flags);
+
/*
* First save the IER then disable the interrupts
*/
@@ -2221,8 +2263,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
* and restore the IER
*/
wait_for_xmitr(up, BOTH_EMPTY);
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, ier | UART_IER_THRI);
+ serial_out(up, UART_IER, ier);
+
+ if (locked)
+ spin_unlock_irqrestore(&up->port.lock, flags);
}
static int serial8250_console_setup(struct console *co, char *options)
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c
index 3d1bfd07208d..58015fd14be9 100644
--- a/drivers/serial/8250_au1x00.c
+++ b/drivers/serial/8250_au1x00.c
@@ -30,13 +30,12 @@
{ \
.iobase = _base, \
.membase = (void __iomem *)_base,\
- .mapbase = _base, \
+ .mapbase = CPHYSADDR(_base), \
.irq = _irq, \
.uartclk = 0, /* filled */ \
.regshift = 2, \
.iotype = UPIO_AU, \
- .flags = UPF_SKIP_TEST | \
- UPF_IOREMAP, \
+ .flags = UPF_SKIP_TEST \
}
static struct plat_serial8250_port au1x00_data[] = {
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 73c8a088c160..3b35cb779539 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -5,11 +5,20 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
*
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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.
+ *
*/
#ifndef CPM_UART_H
#define CPM_UART_H
#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/fs_uart_pd.h>
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
@@ -26,14 +35,14 @@
#define FLAG_SMC 0x00000002
#define FLAG_CONSOLE 0x00000001
-#define UART_SMC1 0
-#define UART_SMC2 1
-#define UART_SCC1 2
-#define UART_SCC2 3
-#define UART_SCC3 4
-#define UART_SCC4 5
+#define UART_SMC1 fsid_smc1_uart
+#define UART_SMC2 fsid_smc2_uart
+#define UART_SCC1 fsid_scc1_uart
+#define UART_SCC2 fsid_scc2_uart
+#define UART_SCC3 fsid_scc3_uart
+#define UART_SCC4 fsid_scc4_uart
-#define UART_NR 6
+#define UART_NR fs_uart_nr
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
@@ -64,6 +73,7 @@ struct uart_cpm_port {
uint dp_addr;
void *mem_addr;
dma_addr_t dma_addr;
+ u32 mem_size;
/* helpers */
int baud;
int bits;
@@ -90,4 +100,38 @@ void scc2_lineif(struct uart_cpm_port *pinfo);
void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo);
+/*
+ virtual to phys transtalion
+*/
+static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
+{
+ int offset;
+ u32 val = (u32)addr;
+ /* sane check */
+ if (likely((val >= (u32)pinfo->mem_addr)) &&
+ (val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
+ offset = val - (u32)pinfo->mem_addr;
+ return pinfo->dma_addr+offset;
+ }
+ /* something nasty happened */
+ BUG();
+ return 0;
+}
+
+static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
+{
+ int offset;
+ u32 val = addr;
+ /* sane check */
+ if (likely((val >= pinfo->dma_addr) &&
+ (val<(pinfo->dma_addr + pinfo->mem_size)))) {
+ offset = val - (u32)pinfo->dma_addr;
+ return (void*)(pinfo->mem_addr+offset);
+ }
+ /* something nasty happened */
+ BUG();
+ return 0;
+}
+
+
#endif /* CPM_UART_H */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index b7bf4c698a47..5cba59ad7dc5 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -12,7 +12,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
- * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
+ * (C) 2005-2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,6 +42,7 @@
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
+#include <linux/fs_uart_pd.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -60,7 +62,7 @@
/* Track which ports are configured as uarts */
int cpm_uart_port_map[UART_NR];
/* How many ports did we config as uarts */
-int cpm_uart_nr;
+int cpm_uart_nr = 0;
/**************************************************************/
@@ -71,18 +73,51 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
-static inline unsigned long cpu2cpm_addr(void *addr)
+
+/* Place-holder for board-specific stuff */
+struct platform_device* __attribute__ ((weak)) __init
+early_uart_get_pdev(int index)
+{
+ return NULL;
+}
+
+
+static void cpm_uart_count(void)
{
- if ((unsigned long)addr >= CPM_ADDR)
- return (unsigned long)addr;
- return virt_to_bus(addr);
+ cpm_uart_nr = 0;
+#ifdef CONFIG_SERIAL_CPM_SMC1
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SMC2
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC1
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC2
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC3
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC4
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
+#endif
}
-static inline void *cpm2cpu_addr(unsigned long addr)
+/* Get UART number by its id */
+static int cpm_uart_id2nr(int id)
{
- if (addr >= CPM_ADDR)
- return (void *)addr;
- return bus_to_virt(addr);
+ int i;
+ if (id < UART_NR) {
+ for (i=0; i<UART_NR; i++) {
+ if (cpm_uart_port_map[i] == id)
+ return i;
+ }
+ }
+
+ /* not found or invalid argument */
+ return -1;
}
/*
@@ -258,7 +293,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
}
/* get pointer */
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
/* loop through the buffer */
while (i-- > 0) {
@@ -438,7 +473,11 @@ static void cpm_uart_shutdown(struct uart_port *port)
}
/* Shut them really down and reinit buffer descriptors */
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ if (IS_SMC(pinfo))
+ cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ else
+ cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX);
+
cpm_uart_initbd(pinfo);
}
}
@@ -601,7 +640,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- p = cpm2cpu_addr(bdp->cbd_bufaddr);
+ p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*p++ = port->x_char;
bdp->cbd_datlen = 1;
@@ -628,7 +667,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
count = 0;
- p = cpm2cpu_addr(bdp->cbd_bufaddr);
+ p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -677,12 +716,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr;
bdp = pinfo->rx_cur = pinfo->rx_bd_base;
for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
mem_addr += pinfo->rx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
/* Set the physical address of the host memory
@@ -692,12 +731,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
bdp = pinfo->tx_cur = pinfo->tx_bd_base;
for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_INTRPT;
mem_addr += pinfo->tx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
}
@@ -829,14 +868,6 @@ static int cpm_uart_request_port(struct uart_port *port)
if (pinfo->flags & FLAG_CONSOLE)
return 0;
- /*
- * Setup any port IO, connect any baud rate generators,
- * etc. This is expected to be handled by board
- * dependant code
- */
- if (pinfo->set_lineif)
- pinfo->set_lineif(pinfo);
-
if (IS_SMC(pinfo)) {
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -988,6 +1019,58 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
},
};
+int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
+{
+ struct resource *r;
+ struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
+ int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */
+ struct uart_cpm_port *pinfo;
+ int line;
+ u32 mem, pram;
+
+ line = cpm_uart_id2nr(idx);
+ if(line < 0) {
+ printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+ return -1;
+ }
+
+ pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx];
+
+ pinfo->brg = pdata->brg;
+
+ if (!is_con) {
+ pinfo->port.line = line;
+ pinfo->port.flags = UPF_BOOT_AUTOCONF;
+ }
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")))
+ return -EINVAL;
+ mem = r->start;
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram")))
+ return -EINVAL;
+ pram = r->start;
+
+ if(idx > fsid_smc2_uart) {
+ pinfo->sccp = (scc_t *)mem;
+ pinfo->sccup = (scc_uart_t *)pram;
+ } else {
+ pinfo->smcp = (smc_t *)mem;
+ pinfo->smcup = (smc_uart_t *)pram;
+ }
+ pinfo->tx_nrfifos = pdata->tx_num_fifo;
+ pinfo->tx_fifosize = pdata->tx_buf_size;
+
+ pinfo->rx_nrfifos = pdata->rx_num_fifo;
+ pinfo->rx_fifosize = pdata->rx_buf_size;
+
+ pinfo->port.uartclk = pdata->uart_clk;
+ pinfo->port.mapbase = (unsigned long)mem;
+ pinfo->port.irq = platform_get_irq(pdev, 0);
+
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
* Print a string to the serial port trying not to disturb
@@ -1027,7 +1110,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = *s;
@@ -1044,7 +1127,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
while ((bdp->cbd_sc & BD_SC_READY) != 0)
;
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = 13;
bdp->cbd_datlen = 1;
@@ -1067,9 +1150,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
pinfo->tx_cur = (volatile cbd_t *) bdp;
}
-/*
- * Setup console. Be careful is called early !
- */
+
static int __init cpm_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
@@ -1080,9 +1161,29 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
int flow = 'n';
int ret;
+ struct fs_uart_platform_info *pdata;
+ struct platform_device* pdev = early_uart_get_pdev(co->index);
+
+ if (!pdev) {
+ pr_info("cpm_uart: console: compat mode\n");
+ /* compatibility - will be cleaned up */
+ cpm_uart_init_portdesc();
+ }
+
port =
(struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]];
pinfo = (struct uart_cpm_port *)port;
+ if (!pdev) {
+ if (pinfo->set_lineif)
+ pinfo->set_lineif(pinfo);
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (pdata)
+ if (pdata->init_ioports)
+ pdata->init_ioports();
+
+ cpm_uart_drv_get_platform_data(pdev, 1);
+ }
pinfo->flags |= FLAG_CONSOLE;
@@ -1097,14 +1198,6 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
baud = 9600;
}
- /*
- * Setup any port IO, connect any baud rate generators,
- * etc. This is expected to be handled by board
- * dependant code
- */
- if (pinfo->set_lineif)
- pinfo->set_lineif(pinfo);
-
if (IS_SMC(pinfo)) {
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -1143,11 +1236,8 @@ static struct console cpm_scc_uart_console = {
int __init cpm_uart_console_init(void)
{
- int ret = cpm_uart_init_portdesc();
-
- if (!ret)
- register_console(&cpm_scc_uart_console);
- return ret;
+ register_console(&cpm_scc_uart_console);
+ return 0;
}
console_initcall(cpm_uart_console_init);
@@ -1165,44 +1255,129 @@ static struct uart_driver cpm_reg = {
.minor = SERIAL_CPM_MINOR,
.cons = CPM_UART_CONSOLE,
};
-
-static int __init cpm_uart_init(void)
+static int cpm_uart_drv_probe(struct device *dev)
{
- int ret, i;
-
- printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n");
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_uart_platform_info *pdata;
+ int ret = -ENODEV;
-#ifndef CONFIG_SERIAL_CPM_CONSOLE
- ret = cpm_uart_init_portdesc();
- if (ret)
+ if(!pdev) {
+ printk(KERN_ERR"CPM UART: platform data missing!\n");
return ret;
-#endif
+ }
- cpm_reg.nr = cpm_uart_nr;
- ret = uart_register_driver(&cpm_reg);
+ pdata = pdev->dev.platform_data;
+ pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
- if (ret)
+ if ((ret = cpm_uart_drv_get_platform_data(pdev, 0)))
return ret;
- for (i = 0; i < cpm_uart_nr; i++) {
- int con = cpm_uart_port_map[i];
- cpm_uart_ports[con].port.line = i;
- cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
- uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
- }
+ if (pdata->init_ioports)
+ pdata->init_ioports();
- return ret;
+ ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
+
+ return ret;
}
-static void __exit cpm_uart_exit(void)
+static int cpm_uart_drv_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
+
+ pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n",
+ cpm_uart_id2nr(pdata->fs_no));
+
+ uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
+ return 0;
+}
+
+static struct device_driver cpm_smc_uart_driver = {
+ .name = "fsl-cpm-smc:uart",
+ .bus = &platform_bus_type,
+ .probe = cpm_uart_drv_probe,
+ .remove = cpm_uart_drv_remove,
+};
+
+static struct device_driver cpm_scc_uart_driver = {
+ .name = "fsl-cpm-scc:uart",
+ .bus = &platform_bus_type,
+ .probe = cpm_uart_drv_probe,
+ .remove = cpm_uart_drv_remove,
+};
+
+/*
+ This is supposed to match uart devices on platform bus,
+ */
+static int match_is_uart (struct device* dev, void* data)
{
+ struct platform_device* pdev = container_of(dev, struct platform_device, dev);
+ int ret = 0;
+ /* this was setfunc as uart */
+ if(strstr(pdev->name,":uart")) {
+ ret = 1;
+ }
+ return ret;
+}
+
+
+static int cpm_uart_init(void) {
+
+ int ret;
int i;
+ struct device *dev;
+ printk(KERN_INFO "Serial: CPM driver $Revision: 0.02 $\n");
+
+ /* lookup the bus for uart devices */
+ dev = bus_find_device(&platform_bus_type, NULL, 0, match_is_uart);
+
+ /* There are devices on the bus - all should be OK */
+ if (dev) {
+ cpm_uart_count();
+ cpm_reg.nr = cpm_uart_nr;
+
+ if (!(ret = uart_register_driver(&cpm_reg))) {
+ if ((ret = driver_register(&cpm_smc_uart_driver))) {
+ uart_unregister_driver(&cpm_reg);
+ return ret;
+ }
+ if ((ret = driver_register(&cpm_scc_uart_driver))) {
+ driver_unregister(&cpm_scc_uart_driver);
+ uart_unregister_driver(&cpm_reg);
+ }
+ }
+ } else {
+ /* No capable platform devices found - falling back to legacy mode */
+ pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n");
+ pr_info(
+ "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n");
+#ifndef CONFIG_SERIAL_CPM_CONSOLE
+ ret = cpm_uart_init_portdesc();
+ if (ret)
+ return ret;
+#endif
+
+ cpm_reg.nr = cpm_uart_nr;
+ ret = uart_register_driver(&cpm_reg);
+
+ if (ret)
+ return ret;
+
+ for (i = 0; i < cpm_uart_nr; i++) {
+ int con = cpm_uart_port_map[i];
+ cpm_uart_ports[con].port.line = i;
+ cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
+ uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
+ }
- for (i = 0; i < cpm_uart_nr; i++) {
- int con = cpm_uart_port_map[i];
- uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port);
}
+ return ret;
+}
+static void __exit cpm_uart_exit(void)
+{
+ driver_unregister(&cpm_scc_uart_driver);
+ driver_unregister(&cpm_smc_uart_driver);
uart_unregister_driver(&cpm_reg);
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index d789ee55cbb7..17406a05ce1f 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -8,6 +8,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
+ * (C) 2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -81,58 +83,11 @@ void cpm_line_cr_cmd(int line, int cmd)
void smc1_lineif(struct uart_cpm_port *pinfo)
{
- volatile cpm8xx_t *cp = cpmp;
-
- (void)cp; /* fix warning */
-#if defined (CONFIG_MPC885ADS)
- /* Enable SMC1 transceivers */
- {
- cp->cp_pepar |= 0x000000c0;
- cp->cp_pedir &= ~0x000000c0;
- cp->cp_peso &= ~0x00000040;
- cp->cp_peso |= 0x00000080;
- }
-#elif defined (CONFIG_MPC86XADS)
- unsigned int iobits = 0x000000c0;
-
- if (!pinfo->is_portb) {
- cp->cp_pbpar |= iobits;
- cp->cp_pbdir &= ~iobits;
- cp->cp_pbodr &= ~iobits;
- } else {
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
- }
-#endif
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
- volatile cpm8xx_t *cp = cpmp;
-
- (void)cp; /* fix warning */
-#if defined (CONFIG_MPC885ADS)
- cp->cp_pepar |= 0x00000c00;
- cp->cp_pedir &= ~0x00000c00;
- cp->cp_peso &= ~0x00000400;
- cp->cp_peso |= 0x00000800;
-#elif defined (CONFIG_MPC86XADS)
- unsigned int iobits = 0x00000c00;
-
- if (!pinfo->is_portb) {
- cp->cp_pbpar |= iobits;
- cp->cp_pbdir &= ~iobits;
- cp->cp_pbodr &= ~iobits;
- } else {
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
- }
-
-#endif
-
pinfo->brg = 2;
}
@@ -191,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
- dma_addr = 0;
+ dma_addr = (u32)mem_addr;
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -204,8 +159,9 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
}
pinfo->dp_addr = dp_offset;
- pinfo->mem_addr = mem_addr;
- pinfo->dma_addr = dma_addr;
+ pinfo->mem_addr = mem_addr; /* virtual address*/
+ pinfo->dma_addr = dma_addr; /* physical address*/
+ pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index fd9e53ed3feb..cdba128250a9 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -8,6 +8,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
+ * (C) 2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -142,14 +144,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
* be supported in a sane fashion.
*/
#ifndef CONFIG_STX_GP3
-#ifdef CONFIG_MPC8560_ADS
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
- io->iop_ppard |= 0x00000018;
- io->iop_psord &= ~0x00000008; /* Rx */
- io->iop_psord &= ~0x00000010; /* Tx */
- io->iop_pdird &= ~0x00000008; /* Rx */
- io->iop_pdird |= 0x00000010; /* Tx */
-#else
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
@@ -157,7 +151,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
#endif
-#endif
cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
@@ -218,8 +211,10 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
- if (is_con)
+ if (is_con) {
mem_addr = alloc_bootmem(memsz);
+ dma_addr = virt_to_bus(mem_addr);
+ }
else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -234,6 +229,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
+ pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index c3b7a6673e9c..d202eb4f3848 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -45,6 +45,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
+#include <asm/arch/imx-uart.h>
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_IMX_MAJOR 204
@@ -73,7 +74,8 @@ struct imx_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status;
- int txirq,rxirq,rtsirq;
+ int txirq,rxirq,rtsirq;
+ int have_rtscts:1;
};
/*
@@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios,
ucr2 = UCR2_SRST | UCR2_IRTS;
if (termios->c_cflag & CRTSCTS) {
- ucr2 &= ~UCR2_IRTS;
- ucr2 |= UCR2_CTSC;
+ if( sport->have_rtscts ) {
+ ucr2 &= ~UCR2_IRTS;
+ ucr2 |= UCR2_CTSC;
+ } else {
+ termios->c_cflag &= ~CRTSCTS;
+ }
}
if (termios->c_cflag & CSTOPB)
@@ -719,27 +725,6 @@ static void __init imx_init_ports(void)
imx_ports[i].timer.function = imx_timeout;
imx_ports[i].timer.data = (unsigned long)&imx_ports[i];
}
-
- imx_gpio_mode(PC9_PF_UART1_CTS);
- imx_gpio_mode(PC10_PF_UART1_RTS);
- imx_gpio_mode(PC11_PF_UART1_TXD);
- imx_gpio_mode(PC12_PF_UART1_RXD);
- imx_gpio_mode(PB28_PF_UART2_CTS);
- imx_gpio_mode(PB29_PF_UART2_RTS);
-
- imx_gpio_mode(PB30_PF_UART2_TXD);
- imx_gpio_mode(PB31_PF_UART2_RXD);
-
-#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart
- * is implemented.
- */
- imx_gpio_mode(PD7_AF_UART2_DTR);
- imx_gpio_mode(PD8_AF_UART2_DCD);
- imx_gpio_mode(PD9_AF_UART2_RI);
- imx_gpio_mode(PD10_AF_UART2_DSR);
-#endif
-
-
}
#ifdef CONFIG_SERIAL_IMX_CONSOLE
@@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev)
static int serial_imx_probe(struct platform_device *dev)
{
+ struct imxuart_platform_data *pdata;
+
imx_ports[dev->id].port.dev = &dev->dev;
+
+ pdata = (struct imxuart_platform_data *)dev->dev.platform_data;
+ if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+ imx_ports[dev->id].have_rtscts = 1;
+
uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);
platform_set_drvdata(dev, &imx_ports[dev->id]);
return 0;
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index f5aac92fb798..53c2465bad2d 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1365,7 +1365,7 @@ static inline void s3c2410_serial_exit(void)
#endif /* CONFIG_CPU_S3C2410 */
-#ifdef CONFIG_CPU_S3C2440
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
static int s3c2440_serial_setsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index fcd7744c4253..17839e753e4c 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
static struct uart_state *uart_get(struct uart_driver *drv, int line)
{
struct uart_state *state;
+ int ret = 0;
- mutex_lock(&port_mutex);
state = drv->state + line;
if (mutex_lock_interruptible(&state->mutex)) {
- state = ERR_PTR(-ERESTARTSYS);
- goto out;
+ ret = -ERESTARTSYS;
+ goto err;
}
state->count++;
- if (!state->port) {
- state->count--;
- mutex_unlock(&state->mutex);
- state = ERR_PTR(-ENXIO);
- goto out;
+ if (!state->port || state->port->flags & UPF_DEAD) {
+ ret = -ENXIO;
+ goto err_unlock;
}
if (!state->info) {
@@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
tasklet_init(&state->info->tlet, uart_tasklet_action,
(unsigned long)state);
} else {
- state->count--;
- mutex_unlock(&state->mutex);
- state = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto err_unlock;
}
}
-
- out:
- mutex_unlock(&port_mutex);
return state;
+
+ err_unlock:
+ state->count--;
+ mutex_unlock(&state->mutex);
+ err:
+ return ERR_PTR(ret);
}
/*
@@ -1907,9 +1907,12 @@ uart_set_options(struct uart_port *port, struct console *co,
static void uart_change_pm(struct uart_state *state, int pm_state)
{
struct uart_port *port = state->port;
- if (port->ops->pm)
- port->ops->pm(port, pm_state, state->pm_state);
- state->pm_state = pm_state;
+
+ if (state->pm_state != pm_state) {
+ if (port->ops->pm)
+ port->ops->pm(port, pm_state, state->pm_state);
+ state->pm_state = pm_state;
+ }
}
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
@@ -2085,45 +2088,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
}
}
-/*
- * This reverses the effects of uart_configure_port, hanging up the
- * port before removal.
- */
-static void
-uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
-{
- struct uart_port *port = state->port;
- struct uart_info *info = state->info;
-
- if (info && info->tty)
- tty_vhangup(info->tty);
-
- mutex_lock(&state->mutex);
-
- state->info = NULL;
-
- /*
- * Free the port IO and memory resources, if any.
- */
- if (port->type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- /*
- * Indicate that there isn't a port here anymore.
- */
- port->type = PORT_UNKNOWN;
-
- /*
- * Kill the tasklet, and free resources.
- */
- if (info) {
- tasklet_kill(&info->tlet);
- kfree(info);
- }
-
- mutex_unlock(&state->mutex);
-}
-
static struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
@@ -2270,6 +2234,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state = drv->state + port->line;
mutex_lock(&port_mutex);
+ mutex_lock(&state->mutex);
if (state->port) {
ret = -EINVAL;
goto out;
@@ -2304,7 +2269,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
port->cons && !(port->cons->flags & CON_ENABLED))
register_console(port->cons);
+ /*
+ * Ensure UPF_DEAD is not set.
+ */
+ port->flags &= ~UPF_DEAD;
+
out:
+ mutex_unlock(&state->mutex);
mutex_unlock(&port_mutex);
return ret;
@@ -2322,6 +2293,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct uart_info *info;
BUG_ON(in_interrupt());
@@ -2332,11 +2304,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
mutex_lock(&port_mutex);
/*
+ * Mark the port "dead" - this prevents any opens from
+ * succeeding while we shut down the port.
+ */
+ mutex_lock(&state->mutex);
+ port->flags |= UPF_DEAD;
+ mutex_unlock(&state->mutex);
+
+ /*
* Remove the devices from devfs
*/
tty_unregister_device(drv->tty_driver, port->line);
- uart_unconfigure_port(drv, state);
+ info = state->info;
+ if (info && info->tty)
+ tty_vhangup(info->tty);
+
+ /*
+ * All users of this port should now be disconnected from
+ * this driver, and the port shut down. We should be the
+ * only thread fiddling with this port from now on.
+ */
+ state->info = NULL;
+
+ /*
+ * Free the port IO and memory resources, if any.
+ */
+ if (port->type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ /*
+ * Indicate that there isn't a port here anymore.
+ */
+ port->type = PORT_UNKNOWN;
+
+ /*
+ * Kill the tasklet, and free resources.
+ */
+ if (info) {
+ tasklet_kill(&info->tlet);
+ kfree(info);
+ }
+
state->port = NULL;
mutex_unlock(&port_mutex);
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index aa521b8e0d4e..776d4ff06084 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -145,14 +145,15 @@ lh7a40xuart_rx_chars (struct uart_port* port)
{
struct tty_struct* tty = port->info->tty;
int cbRxMax = 256; /* (Gross) limit on receive */
- unsigned int data, flag;/* Received data and status */
+ unsigned int data; /* Received data and status */
+ unsigned int flag;
while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
data = UR (port, UART_R_DATA);
flag = TTY_NORMAL;
++port->icount.rx;
- if (unlikely(data & RxError)) { /* Quick check, short-circuit */
+ if (unlikely(data & RxError)) {
if (data & RxBreak) {
data &= ~(RxFramingError | RxParityError);
++port->icount.brk;
@@ -303,7 +304,7 @@ static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
/* Note, kernel appears to be setting DTR and RTS on console. */
/* *** FIXME: this deserves more work. There's some work in
- tracing all of the IO pins. */
+ tracing all of the IO pins. */
#if 0
if( port->mapbase == UART1_PHYS) {
gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
@@ -662,9 +663,13 @@ static int __init lh7a40xuart_init(void)
if (ret == 0) {
int i;
- for (i = 0; i < DEV_NR; i++)
+ for (i = 0; i < DEV_NR; i++) {
+ /* UART3, when used, requires GPIO pin reallocation */
+ if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
+ GPIO_PINMUX |= 1<<3;
uart_add_one_port (&lh7a40x_reg,
&lh7a40x_ports[i].port);
+ }
}
return ret;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 1c4396c2962d..2b4f96541b8e 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1730,3 +1730,4 @@ static void __exit sunsu_exit(void)
module_init(sunsu_probe);
module_exit(sunsu_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 0b49ff78efc1..501316b198e5 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -678,7 +678,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
/* Track PCI-device specific data */
pci_set_drvdata(pdev, idd);
down_write(&ioc3_devices_rwsem);
- list_add(&idd->list, &ioc3_devices);
+ list_add_tail(&idd->list, &ioc3_devices);
idd->id = ioc3_counter++;
up_write(&ioc3_devices_rwsem);
diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c
index 67140a5804f5..cdeff909403e 100644
--- a/drivers/sn/ioc4.c
+++ b/drivers/sn/ioc4.c
@@ -310,7 +310,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
pci_set_drvdata(idd->idd_pdev, idd);
mutex_lock(&ioc4_mutex);
- list_add(&idd->idd_list, &ioc4_devices);
+ list_add_tail(&idd->idd_list, &ioc4_devices);
/* Add this IOC4 to all submodules */
list_for_each_entry(is, &ioc4_submodules, is_list) {
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7a75faeb0526..23334c8bc4c7 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -75,11 +75,45 @@ config SPI_BUTTERFLY
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_MPC83xx
+ tristate "Freescale MPC83xx SPI controller"
+ depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This enables using the Freescale MPC83xx SPI controller in master
+ mode.
+
+ Note, this driver uniquely supports the SPI controller on the MPC83xx
+ family of PowerPC processors. The MPC83xx uses a simple set of shift
+ registers for data (opposed to the CPM based descriptor model).
+
+config SPI_PXA2XX
+ tristate "PXA2xx SSP SPI master"
+ depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
+ help
+ This enables using a PXA2xx SSP port as a SPI master controller.
+ The driver can be configured to use any SSP port and additional
+ documentation can be found a Documentation/spi/pxa2xx.
+
+config SPI_S3C24XX_GPIO
+ tristate "Samsung S3C24XX series SPI by GPIO"
+ depends on SPI_MASTER && ARCH_S3C2410 && SPI_BITBANG && EXPERIMENTAL
+ help
+ SPI driver for Samsung S3C24XX series ARM SoCs using
+ GPIO lines to provide the SPI bus. This can be used where
+ the inbuilt hardware cannot provide the transfer mode, or
+ where the board is using non hardware connected pins.
#
# Add new SPI master controllers in alphabetical order above this line
#
+config SPI_S3C24XX
+ tristate "Samsung S3C24XX series SPI"
+ depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ help
+ SPI driver for Samsung S3C24XX series ARM SoCs
+
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c2c87e845abf..8f4cb67997b3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -13,6 +13,10 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
+obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
+obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
+obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
new file mode 100644
index 000000000000..29aec77f98be
--- /dev/null
+++ b/drivers/spi/pxa2xx_spi.c
@@ -0,0 +1,1486 @@
+/*
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/delay.h>
+#include <asm/dma.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx_spi.h>
+
+MODULE_AUTHOR("Stephen Street");
+MODULE_DESCRIPTION("PXA2xx SSP SPI Contoller");
+MODULE_LICENSE("GPL");
+
+#define MAX_BUSES 3
+
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
+static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
+
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+
+#define START_STATE ((void*)0)
+#define RUNNING_STATE ((void*)1)
+#define DONE_STATE ((void*)2)
+#define ERROR_STATE ((void*)-1)
+
+#define QUEUE_RUNNING 0
+#define QUEUE_STOPPED 1
+
+struct driver_data {
+ /* Driver model hookup */
+ struct platform_device *pdev;
+
+ /* SPI framework hookup */
+ enum pxa_ssp_type ssp_type;
+ struct spi_master *master;
+
+ /* PXA hookup */
+ struct pxa2xx_spi_master *master_info;
+
+ /* DMA setup stuff */
+ int rx_channel;
+ int tx_channel;
+ u32 *null_dma_buf;
+
+ /* SSP register addresses */
+ void *ioaddr;
+ u32 ssdr_physical;
+
+ /* SSP masks*/
+ u32 dma_cr1;
+ u32 int_cr1;
+ u32 clear_sr;
+ u32 mask_sr;
+
+ /* Driver message queue */
+ struct workqueue_struct *workqueue;
+ struct work_struct pump_messages;
+ spinlock_t lock;
+ struct list_head queue;
+ int busy;
+ int run;
+
+ /* Message Transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* Current message transfer state info */
+ struct spi_message* cur_msg;
+ struct spi_transfer* cur_transfer;
+ struct chip_data *cur_chip;
+ size_t len;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ int dma_mapped;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+ size_t rx_map_len;
+ size_t tx_map_len;
+ u8 n_bytes;
+ u32 dma_width;
+ int cs_change;
+ void (*write)(struct driver_data *drv_data);
+ void (*read)(struct driver_data *drv_data);
+ irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+ void (*cs_control)(u32 command);
+};
+
+struct chip_data {
+ u32 cr0;
+ u32 cr1;
+ u32 to;
+ u32 psp;
+ u32 timeout;
+ u8 n_bytes;
+ u32 dma_width;
+ u32 dma_burst_size;
+ u32 threshold;
+ u32 dma_threshold;
+ u8 enable_dma;
+ u8 bits_per_word;
+ u32 speed_hz;
+ void (*write)(struct driver_data *drv_data);
+ void (*read)(struct driver_data *drv_data);
+ void (*cs_control)(u32 command);
+};
+
+static void pump_messages(void *data);
+
+static int flush(struct driver_data *drv_data)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ void *reg = drv_data->ioaddr;
+
+ do {
+ while (read_SSSR(reg) & SSSR_RNE) {
+ read_SSDR(reg);
+ }
+ } while ((read_SSSR(reg) & SSSR_BSY) && limit--);
+ write_SSSR(SSSR_ROR, reg);
+
+ return limit;
+}
+
+static void restore_state(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ /* Clear status and disable clock */
+ write_SSSR(drv_data->clear_sr, reg);
+ write_SSCR0(drv_data->cur_chip->cr0 & ~SSCR0_SSE, reg);
+
+ /* Load the registers */
+ write_SSCR1(drv_data->cur_chip->cr1, reg);
+ write_SSCR0(drv_data->cur_chip->cr0, reg);
+ if (drv_data->ssp_type != PXA25x_SSP) {
+ write_SSTO(0, reg);
+ write_SSPSP(drv_data->cur_chip->psp, reg);
+ }
+}
+
+static void null_cs_control(u32 command)
+{
+}
+
+static void null_writer(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+ u8 n_bytes = drv_data->n_bytes;
+
+ while ((read_SSSR(reg) & SSSR_TNF)
+ && (drv_data->tx < drv_data->tx_end)) {
+ write_SSDR(0, reg);
+ drv_data->tx += n_bytes;
+ }
+}
+
+static void null_reader(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+ u8 n_bytes = drv_data->n_bytes;
+
+ while ((read_SSSR(reg) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ read_SSDR(reg);
+ drv_data->rx += n_bytes;
+ }
+}
+
+static void u8_writer(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_TNF)
+ && (drv_data->tx < drv_data->tx_end)) {
+ write_SSDR(*(u8 *)(drv_data->tx), reg);
+ ++drv_data->tx;
+ }
+}
+
+static void u8_reader(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u8 *)(drv_data->rx) = read_SSDR(reg);
+ ++drv_data->rx;
+ }
+}
+
+static void u16_writer(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_TNF)
+ && (drv_data->tx < drv_data->tx_end)) {
+ write_SSDR(*(u16 *)(drv_data->tx), reg);
+ drv_data->tx += 2;
+ }
+}
+
+static void u16_reader(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u16 *)(drv_data->rx) = read_SSDR(reg);
+ drv_data->rx += 2;
+ }
+}
+static void u32_writer(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_TNF)
+ && (drv_data->tx < drv_data->tx_end)) {
+ write_SSDR(*(u32 *)(drv_data->tx), reg);
+ drv_data->tx += 4;
+ }
+}
+
+static void u32_reader(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+
+ while ((read_SSSR(reg) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u32 *)(drv_data->rx) = read_SSDR(reg);
+ drv_data->rx += 4;
+ }
+}
+
+static void *next_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct spi_transfer *trans = drv_data->cur_transfer;
+
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ drv_data->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer,
+ transfer_list);
+ return RUNNING_STATE;
+ } else
+ return DONE_STATE;
+}
+
+static int map_dma_buffers(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct device *dev = &msg->spi->dev;
+
+ if (!drv_data->cur_chip->enable_dma)
+ return 0;
+
+ if (msg->is_dma_mapped)
+ return drv_data->rx_dma && drv_data->tx_dma;
+
+ if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
+ return 0;
+
+ /* Modify setup if rx buffer is null */
+ if (drv_data->rx == NULL) {
+ *drv_data->null_dma_buf = 0;
+ drv_data->rx = drv_data->null_dma_buf;
+ drv_data->rx_map_len = 4;
+ } else
+ drv_data->rx_map_len = drv_data->len;
+
+
+ /* Modify setup if tx buffer is null */
+ if (drv_data->tx == NULL) {
+ *drv_data->null_dma_buf = 0;
+ drv_data->tx = drv_data->null_dma_buf;
+ drv_data->tx_map_len = 4;
+ } else
+ drv_data->tx_map_len = drv_data->len;
+
+ /* Stream map the rx buffer */
+ drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
+ drv_data->rx_map_len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(drv_data->rx_dma))
+ return 0;
+
+ /* Stream map the tx buffer */
+ drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
+ drv_data->tx_map_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(drv_data->tx_dma)) {
+ dma_unmap_single(dev, drv_data->rx_dma,
+ drv_data->rx_map_len, DMA_FROM_DEVICE);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void unmap_dma_buffers(struct driver_data *drv_data)
+{
+ struct device *dev;
+
+ if (!drv_data->dma_mapped)
+ return;
+
+ if (!drv_data->cur_msg->is_dma_mapped) {
+ dev = &drv_data->cur_msg->spi->dev;
+ dma_unmap_single(dev, drv_data->rx_dma,
+ drv_data->rx_map_len, DMA_FROM_DEVICE);
+ dma_unmap_single(dev, drv_data->tx_dma,
+ drv_data->tx_map_len, DMA_TO_DEVICE);
+ }
+
+ drv_data->dma_mapped = 0;
+}
+
+/* caller already set message->status; dma and pio irqs are blocked */
+static void giveback(struct driver_data *drv_data)
+{
+ struct spi_transfer* last_transfer;
+ unsigned long flags;
+ struct spi_message *msg;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ msg = drv_data->cur_msg;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ last_transfer = list_entry(msg->transfers.prev,
+ struct spi_transfer,
+ transfer_list);
+
+ if (!last_transfer->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+ msg->state = NULL;
+ if (msg->complete)
+ msg->complete(msg->context);
+}
+
+static int wait_ssp_rx_stall(void *ioaddr)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ while ((read_SSSR(ioaddr) & SSSR_BSY) && limit--)
+ cpu_relax();
+
+ return limit;
+}
+
+static int wait_dma_channel_stop(int channel)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ while (!(DCSR(channel) & DCSR_STOPSTATE) && limit--)
+ cpu_relax();
+
+ return limit;
+}
+
+static void dma_handler(int channel, void *data, struct pt_regs *regs)
+{
+ struct driver_data *drv_data = data;
+ struct spi_message *msg = drv_data->cur_msg;
+ void *reg = drv_data->ioaddr;
+ u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+ u32 trailing_sssr = 0;
+
+ if (irq_status & DCSR_BUSERR) {
+
+ /* Disable interrupts, clear status and reset DMA */
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: flush fail\n");
+
+ unmap_dma_buffers(drv_data);
+
+ if (channel == drv_data->tx_channel)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: bad bus address on "
+ "tx channel %d, source %x target = %x\n",
+ channel, DSADR(channel), DTADR(channel));
+ else
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: bad bus address on "
+ "rx channel %d, source %x target = %x\n",
+ channel, DSADR(channel), DTADR(channel));
+
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+ }
+
+ /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
+ if ((drv_data->ssp_type == PXA25x_SSP)
+ && (channel == drv_data->tx_channel)
+ && (irq_status & DCSR_ENDINTR)) {
+
+ /* Wait for rx to stall */
+ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: ssp rx stall failed\n");
+
+ /* Clear and disable interrupts on SSP and DMA channels*/
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: dma rx channel stop failed\n");
+
+ unmap_dma_buffers(drv_data);
+
+ /* Read trailing bytes */
+ /* Calculate number of trailing bytes, read them */
+ trailing_sssr = read_SSSR(reg);
+ if ((trailing_sssr & 0xf008) != 0xf000) {
+ drv_data->rx = drv_data->rx_end -
+ (((trailing_sssr >> 12) & 0x0f) + 1);
+ drv_data->read(drv_data);
+ }
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ * handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+ }
+}
+
+static irqreturn_t dma_transfer(struct driver_data *drv_data)
+{
+ u32 irq_status;
+ u32 trailing_sssr = 0;
+ struct spi_message *msg = drv_data->cur_msg;
+ void *reg = drv_data->ioaddr;
+
+ irq_status = read_SSSR(reg) & drv_data->mask_sr;
+ if (irq_status & SSSR_ROR) {
+ /* Clear and disable interrupts on SSP and DMA channels*/
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ unmap_dma_buffers(drv_data);
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer: flush fail\n");
+
+ dev_warn(&drv_data->pdev->dev, "dma_transfer: fifo overun\n");
+
+ drv_data->cur_msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Check for false positive timeout */
+ if ((irq_status & SSSR_TINT) && DCSR(drv_data->tx_channel) & DCSR_RUN) {
+ write_SSSR(SSSR_TINT, reg);
+ return IRQ_HANDLED;
+ }
+
+ if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
+
+ /* Clear and disable interrupts on SSP and DMA channels*/
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer: dma rx channel stop failed\n");
+
+ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer: ssp rx stall failed\n");
+
+ unmap_dma_buffers(drv_data);
+
+ /* Calculate number of trailing bytes, read them */
+ trailing_sssr = read_SSSR(reg);
+ if ((trailing_sssr & 0xf008) != 0xf000) {
+ drv_data->rx = drv_data->rx_end -
+ (((trailing_sssr >> 12) & 0x0f) + 1);
+ drv_data->read(drv_data);
+ }
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ * handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Opps problem detected */
+ return IRQ_NONE;
+}
+
+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ void *reg = drv_data->ioaddr;
+ unsigned long limit = loops_per_jiffy << 1;
+ u32 irq_status;
+ u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
+ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
+
+ while ((irq_status = read_SSSR(reg) & irq_mask)) {
+
+ if (irq_status & SSSR_ROR) {
+
+ /* Clear and disable interrupts */
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "interrupt_transfer: flush fail\n");
+
+ /* Stop the SSP */
+
+ dev_warn(&drv_data->pdev->dev,
+ "interrupt_transfer: fifo overun\n");
+
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Look for false positive timeout */
+ if ((irq_status & SSSR_TINT)
+ && (drv_data->rx < drv_data->rx_end))
+ write_SSSR(SSSR_TINT, reg);
+
+ /* Pump data */
+ drv_data->read(drv_data);
+ drv_data->write(drv_data);
+
+ if (drv_data->tx == drv_data->tx_end) {
+ /* Disable tx interrupt */
+ write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
+ irq_mask = drv_data->mask_sr & ~SSSR_TFS;
+
+ /* PXA25x_SSP has no timeout, read trailing bytes */
+ if (drv_data->ssp_type == PXA25x_SSP) {
+ while ((read_SSSR(reg) & SSSR_BSY) && limit--)
+ drv_data->read(drv_data);
+
+ if (limit == 0)
+ dev_err(&drv_data->pdev->dev,
+ "interrupt_transfer: "
+ "trailing byte read failed\n");
+ }
+ }
+
+ if ((irq_status & SSSR_TINT)
+ || (drv_data->rx == drv_data->rx_end)) {
+
+ /* Clear timeout */
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+
+ /* Update total byte transfered */
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ * handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+ }
+ }
+
+ /* We did something */
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct driver_data *drv_data = (struct driver_data *)dev_id;
+ void *reg = drv_data->ioaddr;
+
+ if (!drv_data->cur_msg) {
+
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+
+ dev_err(&drv_data->pdev->dev, "bad message state "
+ "in interrupt handler");
+
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+
+ return drv_data->transfer_handler(drv_data);
+}
+
+static void pump_transfers(unsigned long data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct chip_data *chip = NULL;
+ void *reg = drv_data->ioaddr;
+ u32 clk_div = 0;
+ u8 bits = 0;
+ u32 speed = 0;
+ u32 cr0;
+
+ /* Get current state information */
+ message = drv_data->cur_msg;
+ transfer = drv_data->cur_transfer;
+ chip = drv_data->cur_chip;
+
+ /* Handle for abort */
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+ giveback(drv_data);
+ return;
+ }
+
+ /* Handle end of message */
+ if (message->state == DONE_STATE) {
+ message->status = 0;
+ giveback(drv_data);
+ return;
+ }
+
+ /* Delay if requested at end of transfer*/
+ if (message->state == RUNNING_STATE) {
+ previous = list_entry(transfer->transfer_list.prev,
+ struct spi_transfer,
+ transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ }
+
+ /* Setup the transfer state based on the type of transfer */
+ if (flush(drv_data) == 0) {
+ dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
+ message->status = -EIO;
+ giveback(drv_data);
+ return;
+ }
+ drv_data->n_bytes = chip->n_bytes;
+ drv_data->dma_width = chip->dma_width;
+ drv_data->cs_control = chip->cs_control;
+ drv_data->tx = (void *)transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + transfer->len;
+ drv_data->rx = transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + transfer->len;
+ drv_data->rx_dma = transfer->rx_dma;
+ drv_data->tx_dma = transfer->tx_dma;
+ drv_data->len = transfer->len;
+ drv_data->write = drv_data->tx ? chip->write : null_writer;
+ drv_data->read = drv_data->rx ? chip->read : null_reader;
+ drv_data->cs_change = transfer->cs_change;
+
+ /* Change speed and bit per word on a per transfer */
+ if (transfer->speed_hz || transfer->bits_per_word) {
+
+ /* Disable clock */
+ write_SSCR0(chip->cr0 & ~SSCR0_SSE, reg);
+ cr0 = chip->cr0;
+ bits = chip->bits_per_word;
+ speed = chip->speed_hz;
+
+ if (transfer->speed_hz)
+ speed = transfer->speed_hz;
+
+ if (transfer->bits_per_word)
+ bits = transfer->bits_per_word;
+
+ if (reg == SSP1_VIRT)
+ clk_div = SSP1_SerClkDiv(speed);
+ else if (reg == SSP2_VIRT)
+ clk_div = SSP2_SerClkDiv(speed);
+ else if (reg == SSP3_VIRT)
+ clk_div = SSP3_SerClkDiv(speed);
+
+ if (bits <= 8) {
+ drv_data->n_bytes = 1;
+ drv_data->dma_width = DCMD_WIDTH1;
+ drv_data->read = drv_data->read != null_reader ?
+ u8_reader : null_reader;
+ drv_data->write = drv_data->write != null_writer ?
+ u8_writer : null_writer;
+ } else if (bits <= 16) {
+ drv_data->n_bytes = 2;
+ drv_data->dma_width = DCMD_WIDTH2;
+ drv_data->read = drv_data->read != null_reader ?
+ u16_reader : null_reader;
+ drv_data->write = drv_data->write != null_writer ?
+ u16_writer : null_writer;
+ } else if (bits <= 32) {
+ drv_data->n_bytes = 4;
+ drv_data->dma_width = DCMD_WIDTH4;
+ drv_data->read = drv_data->read != null_reader ?
+ u32_reader : null_reader;
+ drv_data->write = drv_data->write != null_writer ?
+ u32_writer : null_writer;
+ }
+
+ cr0 = clk_div
+ | SSCR0_Motorola
+ | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
+ | SSCR0_SSE
+ | (bits > 16 ? SSCR0_EDSS : 0);
+
+ /* Start it back up */
+ write_SSCR0(cr0, reg);
+ }
+
+ message->state = RUNNING_STATE;
+
+ /* Try to map dma buffer and do a dma transfer if successful */
+ if ((drv_data->dma_mapped = map_dma_buffers(drv_data))) {
+
+ /* Ensure we have the correct interrupt handler */
+ drv_data->transfer_handler = dma_transfer;
+
+ /* Setup rx DMA Channel */
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
+ DTADR(drv_data->rx_channel) = drv_data->rx_dma;
+ if (drv_data->rx == drv_data->null_dma_buf)
+ /* No target address increment */
+ DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
+ | drv_data->dma_width
+ | chip->dma_burst_size
+ | drv_data->len;
+ else
+ DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
+ | DCMD_FLOWSRC
+ | drv_data->dma_width
+ | chip->dma_burst_size
+ | drv_data->len;
+
+ /* Setup tx DMA Channel */
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DSADR(drv_data->tx_channel) = drv_data->tx_dma;
+ DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
+ if (drv_data->tx == drv_data->null_dma_buf)
+ /* No source address increment */
+ DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
+ | drv_data->dma_width
+ | chip->dma_burst_size
+ | drv_data->len;
+ else
+ DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
+ | DCMD_FLOWTRG
+ | drv_data->dma_width
+ | chip->dma_burst_size
+ | drv_data->len;
+
+ /* Enable dma end irqs on SSP to detect end of transfer */
+ if (drv_data->ssp_type == PXA25x_SSP)
+ DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
+
+ /* Fix me, need to handle cs polarity */
+ drv_data->cs_control(PXA2XX_CS_ASSERT);
+
+ /* Go baby, go */
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->rx_channel) |= DCSR_RUN;
+ DCSR(drv_data->tx_channel) |= DCSR_RUN;
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(chip->timeout, reg);
+ write_SSCR1(chip->cr1
+ | chip->dma_threshold
+ | drv_data->dma_cr1,
+ reg);
+ } else {
+ /* Ensure we have the correct interrupt handler */
+ drv_data->transfer_handler = interrupt_transfer;
+
+ /* Fix me, need to handle cs polarity */
+ drv_data->cs_control(PXA2XX_CS_ASSERT);
+
+ /* Go baby, go */
+ write_SSSR(drv_data->clear_sr, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(chip->timeout, reg);
+ write_SSCR1(chip->cr1
+ | chip->threshold
+ | drv_data->int_cr1,
+ reg);
+ }
+}
+
+static void pump_messages(void *data)
+{
+ struct driver_data *drv_data = data;
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+ drv_data->busy = 0;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Make sure we are not already running a message */
+ if (drv_data->cur_msg) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Extract head of queue */
+ drv_data->cur_msg = list_entry(drv_data->queue.next,
+ struct spi_message, queue);
+ list_del_init(&drv_data->cur_msg->queue);
+
+ /* Initial message state*/
+ drv_data->cur_msg->state = START_STATE;
+ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+ struct spi_transfer,
+ transfer_list);
+
+ /* Setup the SSP using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ restore_state(drv_data);
+
+ /* Mark as busy and launch transfers */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ drv_data->busy = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+static int transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ list_add_tail(&msg->queue, &drv_data->queue);
+
+ if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return 0;
+}
+
+static int setup(struct spi_device *spi)
+{
+ struct pxa2xx_spi_chip *chip_info = NULL;
+ struct chip_data *chip;
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ unsigned int clk_div;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (drv_data->ssp_type != PXA25x_SSP
+ && (spi->bits_per_word < 4 || spi->bits_per_word > 32))
+ return -EINVAL;
+ else if (spi->bits_per_word < 4 || spi->bits_per_word > 16)
+ return -EINVAL;
+
+ /* Only alloc (or use chip_info) on first setup */
+ chip = spi_get_ctldata(spi);
+ if (chip == NULL) {
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->cs_control = null_cs_control;
+ chip->enable_dma = 0;
+ chip->timeout = SSP_TIMEOUT(1000);
+ chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
+ chip->dma_burst_size = drv_data->master_info->enable_dma ?
+ DCMD_BURST8 : 0;
+
+ chip_info = spi->controller_data;
+ }
+
+ /* chip_info isn't always needed */
+ if (chip_info) {
+ if (chip_info->cs_control)
+ chip->cs_control = chip_info->cs_control;
+
+ chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs);
+
+ chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold)
+ | SSCR1_TxTresh(chip_info->tx_threshold);
+
+ chip->enable_dma = chip_info->dma_burst_size != 0
+ && drv_data->master_info->enable_dma;
+ chip->dma_threshold = 0;
+
+ if (chip->enable_dma) {
+ if (chip_info->dma_burst_size <= 8) {
+ chip->dma_threshold = SSCR1_RxTresh(8)
+ | SSCR1_TxTresh(8);
+ chip->dma_burst_size = DCMD_BURST8;
+ } else if (chip_info->dma_burst_size <= 16) {
+ chip->dma_threshold = SSCR1_RxTresh(16)
+ | SSCR1_TxTresh(16);
+ chip->dma_burst_size = DCMD_BURST16;
+ } else {
+ chip->dma_threshold = SSCR1_RxTresh(32)
+ | SSCR1_TxTresh(32);
+ chip->dma_burst_size = DCMD_BURST32;
+ }
+ }
+
+
+ if (chip_info->enable_loopback)
+ chip->cr1 = SSCR1_LBM;
+ }
+
+ if (drv_data->ioaddr == SSP1_VIRT)
+ clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
+ else if (drv_data->ioaddr == SSP2_VIRT)
+ clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
+ else if (drv_data->ioaddr == SSP3_VIRT)
+ clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
+ else
+ return -ENODEV;
+ chip->speed_hz = spi->max_speed_hz;
+
+ chip->cr0 = clk_div
+ | SSCR0_Motorola
+ | SSCR0_DataSize(spi->bits_per_word > 16 ?
+ spi->bits_per_word - 16 : spi->bits_per_word)
+ | SSCR0_SSE
+ | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
+ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4)
+ | (((spi->mode & SPI_CPOL) != 0) << 3);
+
+ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
+ if (drv_data->ssp_type != PXA25x_SSP)
+ dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+ spi->bits_per_word,
+ (CLOCK_SPEED_HZ)
+ / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ spi->mode & 0x3);
+ else
+ dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+ spi->bits_per_word,
+ (CLOCK_SPEED_HZ/2)
+ / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ spi->mode & 0x3);
+
+ if (spi->bits_per_word <= 8) {
+ chip->n_bytes = 1;
+ chip->dma_width = DCMD_WIDTH1;
+ chip->read = u8_reader;
+ chip->write = u8_writer;
+ } else if (spi->bits_per_word <= 16) {
+ chip->n_bytes = 2;
+ chip->dma_width = DCMD_WIDTH2;
+ chip->read = u16_reader;
+ chip->write = u16_writer;
+ } else if (spi->bits_per_word <= 32) {
+ chip->cr0 |= SSCR0_EDSS;
+ chip->n_bytes = 4;
+ chip->dma_width = DCMD_WIDTH4;
+ chip->read = u32_reader;
+ chip->write = u32_writer;
+ } else {
+ dev_err(&spi->dev, "invalid wordsize\n");
+ kfree(chip);
+ return -ENODEV;
+ }
+ chip->bits_per_word = spi->bits_per_word;
+
+ spi_set_ctldata(spi, chip);
+
+ return 0;
+}
+
+static void cleanup(const struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+
+ kfree(chip);
+}
+
+static int init_queue(struct driver_data *drv_data)
+{
+ INIT_LIST_HEAD(&drv_data->queue);
+ spin_lock_init(&drv_data->lock);
+
+ drv_data->run = QUEUE_STOPPED;
+ drv_data->busy = 0;
+
+ tasklet_init(&drv_data->pump_transfers,
+ pump_transfers, (unsigned long)drv_data);
+
+ INIT_WORK(&drv_data->pump_messages, pump_messages, drv_data);
+ drv_data->workqueue = create_singlethread_workqueue(
+ drv_data->master->cdev.dev->bus_id);
+ if (drv_data->workqueue == NULL)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int start_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -EBUSY;
+ }
+
+ drv_data->run = QUEUE_RUNNING;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+ return 0;
+}
+
+static int stop_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+ unsigned limit = 500;
+ int status = 0;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /* This is a bit lame, but is optimized for the common execution path.
+ * A wait_queue on the drv_data->busy could be used, but then the common
+ * execution path (pump_messages) would be required to call wake_up or
+ * friends on every SPI message. Do this instead */
+ drv_data->run = QUEUE_STOPPED;
+ while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&drv_data->lock, flags);
+ }
+
+ if (!list_empty(&drv_data->queue) || drv_data->busy)
+ status = -EBUSY;
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return status;
+}
+
+static int destroy_queue(struct driver_data *drv_data)
+{
+ int status;
+
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ destroy_workqueue(drv_data->workqueue);
+
+ return 0;
+}
+
+static int pxa2xx_spi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pxa2xx_spi_master *platform_info;
+ struct spi_master *master;
+ struct driver_data *drv_data = 0;
+ struct resource *memory_resource;
+ int irq;
+ int status = 0;
+
+ platform_info = dev->platform_data;
+
+ if (platform_info->ssp_type == SSP_UNDEFINED) {
+ dev_err(&pdev->dev, "undefined SSP\n");
+ return -ENODEV;
+ }
+
+ /* Allocate master with space for drv_data and null dma buffer */
+ master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+ if (!master) {
+ dev_err(&pdev->dev, "can not alloc spi_master\n");
+ return -ENOMEM;
+ }
+ drv_data = spi_master_get_devdata(master);
+ drv_data->master = master;
+ drv_data->master_info = platform_info;
+ drv_data->pdev = pdev;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->cleanup = cleanup;
+ master->setup = setup;
+ master->transfer = transfer;
+
+ drv_data->ssp_type = platform_info->ssp_type;
+ drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
+ sizeof(struct driver_data)), 8);
+
+ /* Setup register addresses */
+ memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!memory_resource) {
+ dev_err(&pdev->dev, "memory resources not defined\n");
+ status = -ENODEV;
+ goto out_error_master_alloc;
+ }
+
+ drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
+ drv_data->ssdr_physical = memory_resource->start + 0x00000010;
+ if (platform_info->ssp_type == PXA25x_SSP) {
+ drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
+ drv_data->dma_cr1 = 0;
+ drv_data->clear_sr = SSSR_ROR;
+ drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
+ } else {
+ drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
+ drv_data->dma_cr1 = SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE;
+ drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
+ drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
+ }
+
+ /* Attach to IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "irq resource not defined\n");
+ status = -ENODEV;
+ goto out_error_master_alloc;
+ }
+
+ status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can not get IRQ\n");
+ goto out_error_master_alloc;
+ }
+
+ /* Setup DMA if requested */
+ drv_data->tx_channel = -1;
+ drv_data->rx_channel = -1;
+ if (platform_info->enable_dma) {
+
+ /* Get two DMA channels (rx and tx) */
+ drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
+ DMA_PRIO_HIGH,
+ dma_handler,
+ drv_data);
+ if (drv_data->rx_channel < 0) {
+ dev_err(dev, "problem (%d) requesting rx channel\n",
+ drv_data->rx_channel);
+ status = -ENODEV;
+ goto out_error_irq_alloc;
+ }
+ drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
+ DMA_PRIO_MEDIUM,
+ dma_handler,
+ drv_data);
+ if (drv_data->tx_channel < 0) {
+ dev_err(dev, "problem (%d) requesting tx channel\n",
+ drv_data->tx_channel);
+ status = -ENODEV;
+ goto out_error_dma_alloc;
+ }
+
+ if (drv_data->ioaddr == SSP1_VIRT) {
+ DRCMRRXSSDR = DRCMR_MAPVLD
+ | drv_data->rx_channel;
+ DRCMRTXSSDR = DRCMR_MAPVLD
+ | drv_data->tx_channel;
+ } else if (drv_data->ioaddr == SSP2_VIRT) {
+ DRCMRRXSS2DR = DRCMR_MAPVLD
+ | drv_data->rx_channel;
+ DRCMRTXSS2DR = DRCMR_MAPVLD
+ | drv_data->tx_channel;
+ } else if (drv_data->ioaddr == SSP3_VIRT) {
+ DRCMRRXSS3DR = DRCMR_MAPVLD
+ | drv_data->rx_channel;
+ DRCMRTXSS3DR = DRCMR_MAPVLD
+ | drv_data->tx_channel;
+ } else {
+ dev_err(dev, "bad SSP type\n");
+ goto out_error_dma_alloc;
+ }
+ }
+
+ /* Enable SOC clock */
+ pxa_set_cken(platform_info->clock_enable, 1);
+
+ /* Load default SSP configuration */
+ write_SSCR0(0, drv_data->ioaddr);
+ write_SSCR1(SSCR1_RxTresh(4) | SSCR1_TxTresh(12), drv_data->ioaddr);
+ write_SSCR0(SSCR0_SerClkDiv(2)
+ | SSCR0_Motorola
+ | SSCR0_DataSize(8),
+ drv_data->ioaddr);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, drv_data->ioaddr);
+ write_SSPSP(0, drv_data->ioaddr);
+
+ /* Initial and start queue */
+ status = init_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem initializing queue\n");
+ goto out_error_clock_enabled;
+ }
+ status = start_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem starting queue\n");
+ goto out_error_clock_enabled;
+ }
+
+ /* Register with the SPI framework */
+ platform_set_drvdata(pdev, drv_data);
+ status = spi_register_master(master);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem registering spi master\n");
+ goto out_error_queue_alloc;
+ }
+
+ return status;
+
+out_error_queue_alloc:
+ destroy_queue(drv_data);
+
+out_error_clock_enabled:
+ pxa_set_cken(platform_info->clock_enable, 0);
+
+out_error_dma_alloc:
+ if (drv_data->tx_channel != -1)
+ pxa_free_dma(drv_data->tx_channel);
+ if (drv_data->rx_channel != -1)
+ pxa_free_dma(drv_data->rx_channel);
+
+out_error_irq_alloc:
+ free_irq(irq, drv_data);
+
+out_error_master_alloc:
+ spi_master_put(master);
+ return status;
+}
+
+static int pxa2xx_spi_remove(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int irq;
+ int status = 0;
+
+ if (!drv_data)
+ return 0;
+
+ /* Remove the queue */
+ status = destroy_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ /* Disable the SSP at the peripheral and SOC level */
+ write_SSCR0(0, drv_data->ioaddr);
+ pxa_set_cken(drv_data->master_info->clock_enable, 0);
+
+ /* Release DMA */
+ if (drv_data->master_info->enable_dma) {
+ if (drv_data->ioaddr == SSP1_VIRT) {
+ DRCMRRXSSDR = 0;
+ DRCMRTXSSDR = 0;
+ } else if (drv_data->ioaddr == SSP2_VIRT) {
+ DRCMRRXSS2DR = 0;
+ DRCMRTXSS2DR = 0;
+ } else if (drv_data->ioaddr == SSP3_VIRT) {
+ DRCMRRXSS3DR = 0;
+ DRCMRTXSS3DR = 0;
+ }
+ pxa_free_dma(drv_data->tx_channel);
+ pxa_free_dma(drv_data->rx_channel);
+ }
+
+ /* Release IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0)
+ free_irq(irq, drv_data);
+
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(drv_data->master);
+
+ /* Prevent double remove */
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static void pxa2xx_spi_shutdown(struct platform_device *pdev)
+{
+ int status = 0;
+
+ if ((status = pxa2xx_spi_remove(pdev)) != 0)
+ dev_err(&pdev->dev, "shutdown failed with %d\n", status);
+}
+
+#ifdef CONFIG_PM
+static int suspend_devices(struct device *dev, void *pm_message)
+{
+ pm_message_t *state = pm_message;
+
+ if (dev->power.power_state.event != state->event) {
+ dev_warn(dev, "pm state does not match request\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ /* Check all childern for current power state */
+ if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
+ dev_warn(&pdev->dev, "suspend aborted\n");
+ return -1;
+ }
+
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+ write_SSCR0(0, drv_data->ioaddr);
+ pxa_set_cken(drv_data->master_info->clock_enable, 0);
+
+ return 0;
+}
+
+static int pxa2xx_spi_resume(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ /* Enable the SSP clock */
+ pxa_set_cken(drv_data->master_info->clock_enable, 1);
+
+ /* Start the queue running */
+ status = start_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+ return status;
+ }
+
+ return 0;
+}
+#else
+#define pxa2xx_spi_suspend NULL
+#define pxa2xx_spi_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver driver = {
+ .driver = {
+ .name = "pxa2xx-spi",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = pxa2xx_spi_probe,
+ .remove = __devexit_p(pxa2xx_spi_remove),
+ .shutdown = pxa2xx_spi_shutdown,
+ .suspend = pxa2xx_spi_suspend,
+ .resume = pxa2xx_spi_resume,
+};
+
+static int __init pxa2xx_spi_init(void)
+{
+ platform_driver_register(&driver);
+
+ return 0;
+}
+module_init(pxa2xx_spi_init);
+
+static void __exit pxa2xx_spi_exit(void)
+{
+ platform_driver_unregister(&driver);
+}
+module_exit(pxa2xx_spi_exit);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 94f5e8ed83a7..1cea4a6799fe 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -338,18 +338,18 @@ static struct class spi_master_class = {
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
* @size: how much driver-private data to preallocate; the pointer to this
- * memory is in the class_data field of the returned class_device,
+ * memory is in the class_data field of the returned class_device,
* accessible with spi_master_get_devdata().
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers. It's how they allocate
- * an spi_master structure, prior to calling spi_add_master().
+ * an spi_master structure, prior to calling spi_register_master().
*
* This must be called from context that can sleep. It returns the SPI
* master structure on success, else NULL.
*
* The caller is responsible for assigning the bus number and initializing
- * the master's methods before calling spi_add_master(); and (after errors
+ * the master's methods before calling spi_register_master(); and (after errors
* adding the device) calling spi_master_put() to prevent a memory leak.
*/
struct spi_master * __init_or_module
@@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master);
int __init_or_module
spi_register_master(struct spi_master *master)
{
- static atomic_t dyn_bus_id = ATOMIC_INIT(0);
+ static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1);
struct device *dev = master->cdev.dev;
int status = -ENODEV;
int dynamic = 0;
@@ -404,7 +404,7 @@ spi_register_master(struct spi_master *master)
return -ENODEV;
/* convention: dynamically assigned bus IDs count down from the max */
- if (master->bus_num == 0) {
+ if (master->bus_num < 0) {
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = 1;
}
@@ -522,7 +522,8 @@ int spi_sync(struct spi_device *spi, struct spi_message *message)
}
EXPORT_SYMBOL_GPL(spi_sync);
-#define SPI_BUFSIZ (SMP_CACHE_BYTES)
+/* portable code must never pass more than 32 bytes */
+#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
static u8 *buf;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index f037e5593269..dd2f950b21a7 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -138,6 +138,45 @@ static unsigned bitbang_txrx_32(
return t->len - count;
}
+int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct spi_bitbang_cs *cs = spi->controller_state;
+ u8 bits_per_word;
+ u32 hz;
+
+ if (t) {
+ bits_per_word = t->bits_per_word;
+ hz = t->speed_hz;
+ } else {
+ bits_per_word = 0;
+ hz = 0;
+ }
+
+ /* spi_transfer level calls that work per-word */
+ if (!bits_per_word)
+ bits_per_word = spi->bits_per_word;
+ if (bits_per_word <= 8)
+ cs->txrx_bufs = bitbang_txrx_8;
+ else if (bits_per_word <= 16)
+ cs->txrx_bufs = bitbang_txrx_16;
+ else if (bits_per_word <= 32)
+ cs->txrx_bufs = bitbang_txrx_32;
+ else
+ return -EINVAL;
+
+ /* nsecs = (clock period)/2 */
+ if (!hz)
+ hz = spi->max_speed_hz;
+ if (hz) {
+ cs->nsecs = (1000000000/2) / hz;
+ if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer);
+
/**
* spi_bitbang_setup - default setup for per-word I/O loops
*/
@@ -145,8 +184,16 @@ int spi_bitbang_setup(struct spi_device *spi)
{
struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang;
+ int retval;
- if (!spi->max_speed_hz)
+ bitbang = spi_master_get_devdata(spi->master);
+
+ /* REVISIT: some systems will want to support devices using lsb-first
+ * bit encodings on the wire. In pure software that would be trivial,
+ * just bitbang_txrx_le_cphaX() routines shifting the other way, and
+ * some hardware controllers also have this support.
+ */
+ if ((spi->mode & SPI_LSB_FIRST) != 0)
return -EINVAL;
if (!cs) {
@@ -155,32 +202,20 @@ int spi_bitbang_setup(struct spi_device *spi)
return -ENOMEM;
spi->controller_state = cs;
}
- bitbang = spi_master_get_devdata(spi->master);
if (!spi->bits_per_word)
spi->bits_per_word = 8;
- /* spi_transfer level calls that work per-word */
- if (spi->bits_per_word <= 8)
- cs->txrx_bufs = bitbang_txrx_8;
- else if (spi->bits_per_word <= 16)
- cs->txrx_bufs = bitbang_txrx_16;
- else if (spi->bits_per_word <= 32)
- cs->txrx_bufs = bitbang_txrx_32;
- else
- return -EINVAL;
-
/* per-word shift register access, in hardware or bitbanging */
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
if (!cs->txrx_word)
return -EINVAL;
- /* nsecs = (clock period)/2 */
- cs->nsecs = (1000000000/2) / (spi->max_speed_hz);
- if (cs->nsecs > MAX_UDELAY_MS * 1000)
- return -EINVAL;
+ retval = spi_bitbang_setup_transfer(spi, NULL);
+ if (retval < 0)
+ return retval;
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
__FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
spi->bits_per_word, 2 * cs->nsecs);
@@ -246,6 +281,8 @@ static void bitbang_work(void *_bitbang)
unsigned tmp;
unsigned cs_change;
int status;
+ int (*setup_transfer)(struct spi_device *,
+ struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message,
queue);
@@ -262,6 +299,7 @@ static void bitbang_work(void *_bitbang)
tmp = 0;
cs_change = 1;
status = 0;
+ setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) {
if (bitbang->shutdown) {
@@ -269,6 +307,20 @@ static void bitbang_work(void *_bitbang)
break;
}
+ /* override or restore speed and wordsize */
+ if (t->speed_hz || t->bits_per_word) {
+ setup_transfer = bitbang->setup_transfer;
+ if (!setup_transfer) {
+ status = -ENOPROTOOPT;
+ break;
+ }
+ }
+ if (setup_transfer) {
+ status = setup_transfer(spi, t);
+ if (status < 0)
+ break;
+ }
+
/* set up default clock polarity, and activate chip;
* this implicitly updates clock and spi modes as
* previously recorded for this device via setup().
@@ -325,6 +377,10 @@ static void bitbang_work(void *_bitbang)
m->status = status;
m->complete(m->context);
+ /* restore speed and wordsize */
+ if (setup_transfer)
+ setup_transfer(spi, NULL);
+
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
* be for this chip too.
@@ -348,6 +404,7 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
{
struct spi_bitbang *bitbang;
unsigned long flags;
+ int status = 0;
m->actual_length = 0;
m->status = -EINPROGRESS;
@@ -357,11 +414,15 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
return -ESHUTDOWN;
spin_lock_irqsave(&bitbang->lock, flags);
- list_add_tail(&m->queue, &bitbang->queue);
- queue_work(bitbang->workqueue, &bitbang->work);
+ if (!spi->max_speed_hz)
+ status = -ENETDOWN;
+ else {
+ list_add_tail(&m->queue, &bitbang->queue);
+ queue_work(bitbang->workqueue, &bitbang->work);
+ }
spin_unlock_irqrestore(&bitbang->lock, flags);
- return 0;
+ return status;
}
EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
@@ -406,6 +467,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) {
+ if (!bitbang->setup_transfer)
+ bitbang->setup_transfer =
+ spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup;
}
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
index ff9e5faa4dc9..a006a1ee27ac 100644
--- a/drivers/spi/spi_butterfly.c
+++ b/drivers/spi/spi_butterfly.c
@@ -321,6 +321,7 @@ static void butterfly_attach(struct parport *p)
* (firmware resets at45, acts as spi slave) or neither (we ignore
* both, AVR uses AT45). Here we expect firmware for the first option.
*/
+
pp->info[0].max_speed_hz = 15 * 1000 * 1000;
strcpy(pp->info[0].modalias, "mtd_dataflash");
pp->info[0].platform_data = &flash;
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
new file mode 100644
index 000000000000..5d92a7e5cb41
--- /dev/null
+++ b/drivers/spi/spi_mpc83xx.c
@@ -0,0 +1,483 @@
+/*
+ * MPC83xx SPI controller driver.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/* SPI Controller registers */
+struct mpc83xx_spi_reg {
+ u8 res1[0x20];
+ __be32 mode;
+ __be32 event;
+ __be32 mask;
+ __be32 command;
+ __be32 transmit;
+ __be32 receive;
+};
+
+/* SPI Controller mode register definitions */
+#define SPMODE_CI_INACTIVEHIGH (1 << 29)
+#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
+#define SPMODE_DIV16 (1 << 27)
+#define SPMODE_REV (1 << 26)
+#define SPMODE_MS (1 << 25)
+#define SPMODE_ENABLE (1 << 24)
+#define SPMODE_LEN(x) ((x) << 20)
+#define SPMODE_PM(x) ((x) << 16)
+
+/*
+ * Default for SPI Mode:
+ * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
+ */
+#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
+ SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
+
+/* SPIE register values */
+#define SPIE_NE 0x00000200 /* Not empty */
+#define SPIE_NF 0x00000100 /* Not full */
+
+/* SPIM register values */
+#define SPIM_NE 0x00000200 /* Not empty */
+#define SPIM_NF 0x00000100 /* Not full */
+
+/* SPI Controller driver's private data. */
+struct mpc83xx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ struct mpc83xx_spi_reg __iomem *base;
+
+ /* rx & tx bufs from the spi_transfer */
+ const void *tx;
+ void *rx;
+
+ /* functions to deal with different sized buffers */
+ void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
+ u32(*get_tx) (struct mpc83xx_spi *);
+
+ unsigned int count;
+ u32 irq;
+
+ unsigned nsecs; /* (clock cycle time)/2 */
+
+ u32 sysclk;
+ void (*activate_cs) (u8 cs, u8 polarity);
+ void (*deactivate_cs) (u8 cs, u8 polarity);
+};
+
+static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
+{
+ out_be32(reg, val);
+}
+
+static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
+{
+ return in_be32(reg);
+}
+
+#define MPC83XX_SPI_RX_BUF(type) \
+void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
+{ \
+ type * rx = mpc83xx_spi->rx; \
+ *rx++ = (type)data; \
+ mpc83xx_spi->rx = rx; \
+}
+
+#define MPC83XX_SPI_TX_BUF(type) \
+u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
+{ \
+ u32 data; \
+ const type * tx = mpc83xx_spi->tx; \
+ data = *tx++; \
+ mpc83xx_spi->tx = tx; \
+ return data; \
+}
+
+MPC83XX_SPI_RX_BUF(u8)
+MPC83XX_SPI_RX_BUF(u16)
+MPC83XX_SPI_RX_BUF(u32)
+MPC83XX_SPI_TX_BUF(u8)
+MPC83XX_SPI_TX_BUF(u16)
+MPC83XX_SPI_TX_BUF(u32)
+
+static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
+{
+ struct mpc83xx_spi *mpc83xx_spi;
+ u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+
+ mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+ if (value == BITBANG_CS_INACTIVE) {
+ if (mpc83xx_spi->deactivate_cs)
+ mpc83xx_spi->deactivate_cs(spi->chip_select, pol);
+ }
+
+ if (value == BITBANG_CS_ACTIVE) {
+ u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ u32 len = spi->bits_per_word;
+ if (len == 32)
+ len = 0;
+ else
+ len = len - 1;
+
+ /* mask out bits we are going to set */
+ regval &= ~0x38ff0000;
+
+ if (spi->mode & SPI_CPHA)
+ regval |= SPMODE_CP_BEGIN_EDGECLK;
+ if (spi->mode & SPI_CPOL)
+ regval |= SPMODE_CI_INACTIVEHIGH;
+
+ regval |= SPMODE_LEN(len);
+
+ if ((mpc83xx_spi->sysclk / spi->max_speed_hz) >= 64) {
+ u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64);
+ regval |= SPMODE_PM(pm) | SPMODE_DIV16;
+ } else {
+ u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4);
+ regval |= SPMODE_PM(pm);
+ }
+
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+ if (mpc83xx_spi->activate_cs)
+ mpc83xx_spi->activate_cs(spi->chip_select, pol);
+ }
+}
+
+static
+int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct mpc83xx_spi *mpc83xx_spi;
+ u32 regval;
+ u8 bits_per_word;
+ u32 hz;
+
+ mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+ if (t) {
+ bits_per_word = t->bits_per_word;
+ hz = t->speed_hz;
+ } else {
+ bits_per_word = 0;
+ hz = 0;
+ }
+
+ /* spi_transfer level calls that work per-word */
+ if (!bits_per_word)
+ bits_per_word = spi->bits_per_word;
+
+ /* Make sure its a bit width we support [4..16, 32] */
+ if ((bits_per_word < 4)
+ || ((bits_per_word > 16) && (bits_per_word != 32)))
+ return -EINVAL;
+
+ if (bits_per_word <= 8) {
+ mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
+ mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+ } else if (bits_per_word <= 16) {
+ mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16;
+ mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16;
+ } else if (bits_per_word <= 32) {
+ mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32;
+ mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32;
+ } else
+ return -EINVAL;
+
+ /* nsecs = (clock period)/2 */
+ if (!hz)
+ hz = spi->max_speed_hz;
+ mpc83xx_spi->nsecs = (1000000000 / 2) / hz;
+ if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000)
+ return -EINVAL;
+
+ if (bits_per_word == 32)
+ bits_per_word = 0;
+ else
+ bits_per_word = bits_per_word - 1;
+
+ regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+
+ /* Mask out bits_per_wordgth */
+ regval &= 0xff0fffff;
+ regval |= SPMODE_LEN(bits_per_word);
+
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+
+ return 0;
+}
+
+static int mpc83xx_spi_setup(struct spi_device *spi)
+{
+ struct spi_bitbang *bitbang;
+ struct mpc83xx_spi *mpc83xx_spi;
+ int retval;
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ bitbang = spi_master_get_devdata(spi->master);
+ mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ retval = mpc83xx_spi_setup_transfer(spi, NULL);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+ __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+ spi->bits_per_word, 2 * mpc83xx_spi->nsecs);
+
+ /* NOTE we _need_ to call chipselect() early, ideally with adapter
+ * setup, unless the hardware defaults cooperate to avoid confusion
+ * between normal (active low) and inverted chipselects.
+ */
+
+ /* deselect chip (low or high) */
+ spin_lock(&bitbang->lock);
+ if (!bitbang->busy) {
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(mpc83xx_spi->nsecs);
+ }
+ spin_unlock(&bitbang->lock);
+
+ return 0;
+}
+
+static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct mpc83xx_spi *mpc83xx_spi;
+ u32 word;
+
+ mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+ mpc83xx_spi->tx = t->tx_buf;
+ mpc83xx_spi->rx = t->rx_buf;
+ mpc83xx_spi->count = t->len;
+ INIT_COMPLETION(mpc83xx_spi->done);
+
+ /* enable rx ints */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
+
+ /* transmit word */
+ word = mpc83xx_spi->get_tx(mpc83xx_spi);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
+
+ wait_for_completion(&mpc83xx_spi->done);
+
+ /* disable rx ints */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
+
+ return t->len - mpc83xx_spi->count;
+}
+
+irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data,
+ struct pt_regs * ptregs)
+{
+ struct mpc83xx_spi *mpc83xx_spi = context_data;
+ u32 event;
+ irqreturn_t ret = IRQ_NONE;
+
+ /* Get interrupt events(tx/rx) */
+ event = mpc83xx_spi_read_reg(&mpc83xx_spi->base->event);
+
+ /* We need handle RX first */
+ if (event & SPIE_NE) {
+ u32 rx_data = mpc83xx_spi_read_reg(&mpc83xx_spi->base->receive);
+
+ if (mpc83xx_spi->rx)
+ mpc83xx_spi->get_rx(rx_data, mpc83xx_spi);
+
+ ret = IRQ_HANDLED;
+ }
+
+ if ((event & SPIE_NF) == 0)
+ /* spin until TX is done */
+ while (((event =
+ mpc83xx_spi_read_reg(&mpc83xx_spi->base->event)) &
+ SPIE_NF) == 0)
+ cpu_relax();
+
+ mpc83xx_spi->count -= 1;
+ if (mpc83xx_spi->count) {
+ if (mpc83xx_spi->tx) {
+ u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit,
+ word);
+ }
+ } else {
+ complete(&mpc83xx_spi->done);
+ }
+
+ /* Clear the events */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, event);
+
+ return ret;
+}
+
+static int __init mpc83xx_spi_probe(struct platform_device *dev)
+{
+ struct spi_master *master;
+ struct mpc83xx_spi *mpc83xx_spi;
+ struct fsl_spi_platform_data *pdata;
+ struct resource *r;
+ u32 regval;
+ int ret = 0;
+
+ /* Get resources(memory, IRQ) associated with the device */
+ master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi));
+
+ if (master == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(dev, master);
+ pdata = dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ ret = -ENODEV;
+ goto free_master;
+ }
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENODEV;
+ goto free_master;
+ }
+
+ mpc83xx_spi = spi_master_get_devdata(master);
+ mpc83xx_spi->bitbang.master = spi_master_get(master);
+ mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
+ mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
+ mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
+ mpc83xx_spi->sysclk = pdata->sysclk;
+ mpc83xx_spi->activate_cs = pdata->activate_cs;
+ mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
+ mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
+ mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+
+ mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
+ init_completion(&mpc83xx_spi->done);
+
+ mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
+ if (mpc83xx_spi->base == NULL) {
+ ret = -ENOMEM;
+ goto put_master;
+ }
+
+ mpc83xx_spi->irq = platform_get_irq(dev, 0);
+
+ if (mpc83xx_spi->irq < 0) {
+ ret = -ENXIO;
+ goto unmap_io;
+ }
+
+ /* Register for SPI Interrupt */
+ ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
+ 0, "mpc83xx_spi", mpc83xx_spi);
+
+ if (ret != 0)
+ goto unmap_io;
+
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->max_chipselect;
+
+ /* SPI controller initializations */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
+
+ /* Enable SPI interface */
+ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+
+ ret = spi_bitbang_start(&mpc83xx_spi->bitbang);
+
+ if (ret != 0)
+ goto free_irq;
+
+ printk(KERN_INFO
+ "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
+ dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
+
+ return ret;
+
+free_irq:
+ free_irq(mpc83xx_spi->irq, mpc83xx_spi);
+unmap_io:
+ iounmap(mpc83xx_spi->base);
+put_master:
+ spi_master_put(master);
+free_master:
+ kfree(master);
+err:
+ return ret;
+}
+
+static int __devexit mpc83xx_spi_remove(struct platform_device *dev)
+{
+ struct mpc83xx_spi *mpc83xx_spi;
+ struct spi_master *master;
+
+ master = platform_get_drvdata(dev);
+ mpc83xx_spi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&mpc83xx_spi->bitbang);
+ free_irq(mpc83xx_spi->irq, mpc83xx_spi);
+ iounmap(mpc83xx_spi->base);
+ spi_master_put(mpc83xx_spi->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver mpc83xx_spi_driver = {
+ .probe = mpc83xx_spi_probe,
+ .remove = __devexit_p(mpc83xx_spi_remove),
+ .driver = {
+ .name = "mpc83xx_spi",
+ },
+};
+
+static int __init mpc83xx_spi_init(void)
+{
+ return platform_driver_register(&mpc83xx_spi_driver);
+}
+
+static void __exit mpc83xx_spi_exit(void)
+{
+ platform_driver_unregister(&mpc83xx_spi_driver);
+}
+
+module_init(mpc83xx_spi_init);
+module_exit(mpc83xx_spi_exit);
+
+MODULE_AUTHOR("Kumar Gala");
+MODULE_DESCRIPTION("Simple MPC83xx SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
new file mode 100644
index 000000000000..5fc14563ee3a
--- /dev/null
+++ b/drivers/spi/spi_s3c24xx.c
@@ -0,0 +1,453 @@
+/* linux/drivers/spi/spi_s3c24xx.c
+ *
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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 DEBUG
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-spi.h>
+#include <asm/arch/spi.h>
+
+struct s3c24xx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ void __iomem *regs;
+ int irq;
+ int len;
+ int count;
+
+ /* data buffers */
+ const unsigned char *tx;
+ unsigned char *rx;
+
+ struct clk *clk;
+ struct resource *ioarea;
+ struct spi_master *master;
+ struct spi_device *curdev;
+ struct device *dev;
+ struct s3c2410_spi_info *pdata;
+};
+
+#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
+#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
+
+static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
+{
+ return spi_master_get_devdata(sdev->master);
+}
+
+static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
+{
+ struct s3c24xx_spi *hw = to_hw(spi);
+ unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ unsigned int spcon;
+
+ switch (value) {
+ case BITBANG_CS_INACTIVE:
+ if (hw->pdata->set_cs)
+ hw->pdata->set_cs(hw->pdata, value, cspol);
+ else
+ s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);
+ break;
+
+ case BITBANG_CS_ACTIVE:
+ spcon = readb(hw->regs + S3C2410_SPCON);
+
+ if (spi->mode & SPI_CPHA)
+ spcon |= S3C2410_SPCON_CPHA_FMTB;
+ else
+ spcon &= ~S3C2410_SPCON_CPHA_FMTB;
+
+ if (spi->mode & SPI_CPOL)
+ spcon |= S3C2410_SPCON_CPOL_HIGH;
+ else
+ spcon &= ~S3C2410_SPCON_CPOL_HIGH;
+
+ spcon |= S3C2410_SPCON_ENSCK;
+
+ /* write new configration */
+
+ writeb(spcon, hw->regs + S3C2410_SPCON);
+
+ if (hw->pdata->set_cs)
+ hw->pdata->set_cs(hw->pdata, value, cspol);
+ else
+ s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);
+
+ break;
+
+ }
+}
+
+static int s3c24xx_spi_setupxfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct s3c24xx_spi *hw = to_hw(spi);
+ unsigned int bpw;
+ unsigned int hz;
+ unsigned int div;
+
+ bpw = t ? t->bits_per_word : spi->bits_per_word;
+ hz = t ? t->speed_hz : spi->max_speed_hz;
+
+ if (bpw != 8) {
+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
+ return -EINVAL;
+ }
+
+ div = clk_get_rate(hw->clk) / hz;
+
+ /* is clk = pclk / (2 * (pre+1)), or is it
+ * clk = (pclk * 2) / ( pre + 1) */
+
+ div = (div / 2) - 1;
+
+ if (div < 0)
+ div = 1;
+
+ if (div > 255)
+ div = 255;
+
+ dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);
+ writeb(div, hw->regs + S3C2410_SPPRE);
+
+ spin_lock(&hw->bitbang.lock);
+ if (!hw->bitbang.busy) {
+ hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
+ /* need to ndelay for 0.5 clocktick ? */
+ }
+ spin_unlock(&hw->bitbang.lock);
+
+ return 0;
+}
+
+static int s3c24xx_spi_setup(struct spi_device *spi)
+{
+ int ret;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if ((spi->mode & SPI_LSB_FIRST) != 0)
+ return -EINVAL;
+
+ ret = s3c24xx_spi_setupxfer(spi, NULL);
+ if (ret < 0) {
+ dev_err(&spi->dev, "setupxfer returned %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
+ __FUNCTION__, spi->mode, spi->bits_per_word,
+ spi->max_speed_hz);
+
+ return 0;
+}
+
+static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
+{
+ return hw->tx ? hw->tx[count] : 0xff;
+}
+
+static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct s3c24xx_spi *hw = to_hw(spi);
+
+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
+ t->tx_buf, t->rx_buf, t->len);
+
+ hw->tx = t->tx_buf;
+ hw->rx = t->rx_buf;
+ hw->len = t->len;
+ hw->count = 0;
+
+ /* send the first byte */
+ writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
+ wait_for_completion(&hw->done);
+
+ return hw->count;
+}
+
+static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs)
+{
+ struct s3c24xx_spi *hw = dev;
+ unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
+ unsigned int count = hw->count;
+
+ if (spsta & S3C2410_SPSTA_DCOL) {
+ dev_dbg(hw->dev, "data-collision\n");
+ complete(&hw->done);
+ goto irq_done;
+ }
+
+ if (!(spsta & S3C2410_SPSTA_READY)) {
+ dev_dbg(hw->dev, "spi not ready for tx?\n");
+ complete(&hw->done);
+ goto irq_done;
+ }
+
+ hw->count++;
+
+ if (hw->rx)
+ hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
+
+ count++;
+
+ if (count < hw->len)
+ writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
+ else
+ complete(&hw->done);
+
+ irq_done:
+ return IRQ_HANDLED;
+}
+
+static int s3c24xx_spi_probe(struct platform_device *pdev)
+{
+ struct s3c24xx_spi *hw;
+ struct spi_master *master;
+ struct spi_board_info *bi;
+ struct resource *res;
+ int err = 0;
+ int i;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
+ if (master == NULL) {
+ dev_err(&pdev->dev, "No memory for spi_master\n");
+ err = -ENOMEM;
+ goto err_nomem;
+ }
+
+ hw = spi_master_get_devdata(master);
+ memset(hw, 0, sizeof(struct s3c24xx_spi));
+
+ hw->master = spi_master_get(master);
+ hw->pdata = pdev->dev.platform_data;
+ hw->dev = &pdev->dev;
+
+ if (hw->pdata == NULL) {
+ dev_err(&pdev->dev, "No platform data supplied\n");
+ err = -ENOENT;
+ goto err_no_pdata;
+ }
+
+ platform_set_drvdata(pdev, hw);
+ init_completion(&hw->done);
+
+ /* setup the state for the bitbang driver */
+
+ hw->bitbang.master = hw->master;
+ hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
+ hw->bitbang.chipselect = s3c24xx_spi_chipsel;
+ hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
+ hw->bitbang.master->setup = s3c24xx_spi_setup;
+
+ dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
+
+ /* find and map our resources */
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ err = -ENOENT;
+ goto err_no_iores;
+ }
+
+ hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,
+ pdev->name);
+
+ if (hw->ioarea == NULL) {
+ dev_err(&pdev->dev, "Cannot reserve region\n");
+ err = -ENXIO;
+ goto err_no_iores;
+ }
+
+ hw->regs = ioremap(res->start, (res->end - res->start)+1);
+ if (hw->regs == NULL) {
+ dev_err(&pdev->dev, "Cannot map IO\n");
+ err = -ENXIO;
+ goto err_no_iomap;
+ }
+
+ hw->irq = platform_get_irq(pdev, 0);
+ if (hw->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ specified\n");
+ err = -ENOENT;
+ goto err_no_irq;
+ }
+
+ err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto err_no_irq;
+ }
+
+ hw->clk = clk_get(&pdev->dev, "spi");
+ if (IS_ERR(hw->clk)) {
+ dev_err(&pdev->dev, "No clock for device\n");
+ err = PTR_ERR(hw->clk);
+ goto err_no_clk;
+ }
+
+ /* for the moment, permanently enable the clock */
+
+ clk_enable(hw->clk);
+
+ /* program defaults into the registers */
+
+ writeb(0xff, hw->regs + S3C2410_SPPRE);
+ writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
+ writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
+
+ /* setup any gpio we can */
+
+ if (!hw->pdata->set_cs) {
+ s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);
+ s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT);
+ }
+
+ /* register our spi controller */
+
+ err = spi_bitbang_start(&hw->bitbang);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register SPI master\n");
+ goto err_register;
+ }
+
+ dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);
+
+ /* register all the devices associated */
+
+ bi = &hw->pdata->board_info[0];
+ for (i = 0; i < hw->pdata->board_size; i++, bi++) {
+ dev_info(hw->dev, "registering %s\n", bi->modalias);
+
+ bi->controller_data = hw;
+ spi_new_device(master, bi);
+ }
+
+ return 0;
+
+ err_register:
+ clk_disable(hw->clk);
+ clk_put(hw->clk);
+
+ err_no_clk:
+ free_irq(hw->irq, hw);
+
+ err_no_irq:
+ iounmap(hw->regs);
+
+ err_no_iomap:
+ release_resource(hw->ioarea);
+ kfree(hw->ioarea);
+
+ err_no_iores:
+ err_no_pdata:
+ spi_master_put(hw->master);;
+
+ err_nomem:
+ return err;
+}
+
+static int s3c24xx_spi_remove(struct platform_device *dev)
+{
+ struct s3c24xx_spi *hw = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ spi_unregister_master(hw->master);
+
+ clk_disable(hw->clk);
+ clk_put(hw->clk);
+
+ free_irq(hw->irq, hw);
+ iounmap(hw->regs);
+
+ release_resource(hw->ioarea);
+ kfree(hw->ioarea);
+
+ spi_master_put(hw->master);
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
+
+ clk_disable(hw->clk);
+ return 0;
+}
+
+static int s3c24xx_spi_resume(struct platform_device *pdev)
+{
+ struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
+
+ clk_enable(hw->clk);
+ return 0;
+}
+
+#else
+#define s3c24xx_spi_suspend NULL
+#define s3c24xx_spi_resume NULL
+#endif
+
+static struct platform_driver s3c24xx_spidrv = {
+ .probe = s3c24xx_spi_probe,
+ .remove = s3c24xx_spi_remove,
+ .suspend = s3c24xx_spi_suspend,
+ .resume = s3c24xx_spi_resume,
+ .driver = {
+ .name = "s3c2410-spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c24xx_spi_init(void)
+{
+ return platform_driver_register(&s3c24xx_spidrv);
+}
+
+static void __exit s3c24xx_spi_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_spidrv);
+}
+
+module_init(s3c24xx_spi_init);
+module_exit(s3c24xx_spi_exit);
+
+MODULE_DESCRIPTION("S3C24XX SPI Driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
new file mode 100644
index 000000000000..aacdceb8f44b
--- /dev/null
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -0,0 +1,188 @@
+/* linux/drivers/spi/spi_s3c24xx_gpio.c
+ *
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ *
+ * S3C24XX GPIO based SPI driver
+ *
+ * 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/spi-gpio.h>
+#include <asm/arch/hardware.h>
+
+struct s3c2410_spigpio {
+ struct spi_bitbang bitbang;
+
+ struct s3c2410_spigpio_info *info;
+ struct platform_device *dev;
+};
+
+static inline struct s3c2410_spigpio *spidev_to_sg(struct spi_device *spi)
+{
+ return spi->controller_data;
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+ struct s3c2410_spigpio *sg = spidev_to_sg(dev);
+ s3c2410_gpio_setpin(sg->info->pin_clk, on ? 1 : 0);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+ struct s3c2410_spigpio *sg = spidev_to_sg(dev);
+ s3c2410_gpio_setpin(sg->info->pin_mosi, on ? 1 : 0);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+ struct s3c2410_spigpio *sg = spidev_to_sg(dev);
+ return s3c2410_gpio_getpin(sg->info->pin_miso) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+
+static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
+{
+ struct s3c2410_spigpio *sg = spidev_to_sg(dev);
+
+ if (sg->info && sg->info->chip_select)
+ (sg->info->chip_select)(sg->info, value);
+}
+
+static int s3c2410_spigpio_probe(struct platform_device *dev)
+{
+ struct spi_master *master;
+ struct s3c2410_spigpio *sp;
+ int ret;
+ int i;
+
+ master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
+ if (master == NULL) {
+ dev_err(&dev->dev, "failed to allocate spi master\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sp = spi_master_get_devdata(master);
+
+ platform_set_drvdata(dev, sp);
+
+ /* copy in the plkatform data */
+ sp->info = dev->dev.platform_data;
+
+ /* setup spi bitbang adaptor */
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
+
+ sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
+ sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
+
+ /* set state of spi pins */
+ s3c2410_gpio_setpin(sp->info->pin_clk, 0);
+ s3c2410_gpio_setpin(sp->info->pin_mosi, 0);
+
+ s3c2410_gpio_cfgpin(sp->info->pin_clk, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_cfgpin(sp->info->pin_mosi, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_cfgpin(sp->info->pin_miso, S3C2410_GPIO_INPUT);
+
+ ret = spi_bitbang_start(&sp->bitbang);
+ if (ret)
+ goto err_no_bitbang;
+
+ /* register the chips to go with the board */
+
+ for (i = 0; i < sp->info->board_size; i++) {
+ dev_info(&dev->dev, "registering %p: %s\n",
+ &sp->info->board_info[i],
+ sp->info->board_info[i].modalias);
+
+ sp->info->board_info[i].controller_data = sp;
+ spi_new_device(master, sp->info->board_info + i);
+ }
+
+ return 0;
+
+ err_no_bitbang:
+ spi_master_put(sp->bitbang.master);
+ err:
+ return ret;
+
+}
+
+static int s3c2410_spigpio_remove(struct platform_device *dev)
+{
+ struct s3c2410_spigpio *sp = platform_get_drvdata(dev);
+
+ spi_bitbang_stop(&sp->bitbang);
+ spi_master_put(sp->bitbang.master);
+
+ return 0;
+}
+
+/* all gpio should be held over suspend/resume, so we should
+ * not need to deal with this
+*/
+
+#define s3c2410_spigpio_suspend NULL
+#define s3c2410_spigpio_resume NULL
+
+
+static struct platform_driver s3c2410_spigpio_drv = {
+ .probe = s3c2410_spigpio_probe,
+ .remove = s3c2410_spigpio_remove,
+ .suspend = s3c2410_spigpio_suspend,
+ .resume = s3c2410_spigpio_resume,
+ .driver = {
+ .name = "s3c24xx-spi-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c2410_spigpio_init(void)
+{
+ return platform_driver_register(&s3c2410_spigpio_drv);
+}
+
+static void __exit s3c2410_spigpio_exit(void)
+{
+ platform_driver_unregister(&s3c2410_spigpio_drv);
+}
+
+module_init(s3c2410_spigpio_init);
+module_exit(s3c2410_spigpio_exit);
+
+MODULE_DESCRIPTION("S3C24XX SPI Driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 7860c8a5800d..956b7a1e8af9 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -69,7 +69,7 @@ static const char speedtch_driver_name[] = "speedtch";
#define RESUBMIT_DELAY 1000 /* milliseconds */
#define DEFAULT_BULK_ALTSETTING 1
-#define DEFAULT_ISOC_ALTSETTING 2
+#define DEFAULT_ISOC_ALTSETTING 3
#define DEFAULT_DL_512_FIRST 0
#define DEFAULT_ENABLE_ISOC 0
#define DEFAULT_SW_BUFFERING 0
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index c1211fc037d9..546249843b8e 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -99,11 +99,11 @@ static const char usbatm_driver_name[] = "usbatm";
#define UDSL_MAX_RCV_URBS 16
#define UDSL_MAX_SND_URBS 16
-#define UDSL_MAX_BUF_SIZE 64 * 1024 /* bytes */
+#define UDSL_MAX_BUF_SIZE 65536
#define UDSL_DEFAULT_RCV_URBS 4
#define UDSL_DEFAULT_SND_URBS 4
-#define UDSL_DEFAULT_RCV_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */
-#define UDSL_DEFAULT_SND_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */
+#define UDSL_DEFAULT_RCV_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */
+#define UDSL_DEFAULT_SND_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
@@ -135,7 +135,7 @@ MODULE_PARM_DESC(rcv_buf_bytes,
module_param(snd_buf_bytes, uint, S_IRUGO);
MODULE_PARM_DESC(snd_buf_bytes,
"Size of the buffers used for transmission, in bytes (range: 1-"
- __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
+ __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: "
__MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index fbd938d4ea58..e2e00ba4e1e6 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1805,6 +1805,12 @@ int usb_add_hcd(struct usb_hcd *hcd,
USB_SPEED_FULL;
hcd->self.root_hub = rhdev;
+ /* wakeup flag init defaults to "everything works" for root hubs,
+ * but drivers can override it in reset() if needed, along with
+ * recording the overall controller's system wakeup capability.
+ */
+ device_init_wakeup(&rhdev->dev, 1);
+
/* "reset" is misnamed; its role is now one-time init. the controller
* should already have been reset (and boot firmware kicked off etc).
*/
@@ -1813,13 +1819,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
goto err_hcd_driver_setup;
}
- /* wakeup flag init is in transition; for now we can't rely on PCI to
- * initialize these bits properly, so we let reset() override it.
- * This init should _precede_ the reset() once PCI behaves.
- */
- device_init_wakeup(&rhdev->dev,
- device_can_wakeup(hcd->self.controller));
-
/* NOTE: root hub and controller capabilities may not be the same */
if (device_can_wakeup(hcd->self.controller)
&& device_can_wakeup(&hcd->self.root_hub->dev))
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0c87f73f2933..90b8d43c6b33 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1168,19 +1168,9 @@ static inline const char *plural(int n)
static int choose_configuration(struct usb_device *udev)
{
int i;
- u16 devstatus;
- int bus_powered;
int num_configs;
struct usb_host_config *c, *best;
- /* If this fails, assume the device is bus-powered */
- devstatus = 0;
- usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
- le16_to_cpus(&devstatus);
- bus_powered = ((devstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0);
- dev_dbg(&udev->dev, "device is %s-powered\n",
- bus_powered ? "bus" : "self");
-
best = NULL;
c = udev->config;
num_configs = udev->descriptor.bNumConfigurations;
@@ -1197,6 +1187,19 @@ static int choose_configuration(struct usb_device *udev)
* similar errors in their descriptors. If the next test
* were allowed to execute, such configurations would always
* be rejected and the devices would not work as expected.
+ * In the meantime, we run the risk of selecting a config
+ * that requires external power at a time when that power
+ * isn't available. It seems to be the lesser of two evils.
+ *
+ * Bugzilla #6448 reports a device that appears to crash
+ * when it receives a GET_DEVICE_STATUS request! We don't
+ * have any other way to tell whether a device is self-powered,
+ * but since we don't use that information anywhere but here,
+ * the call has been removed.
+ *
+ * Maybe the GET_DEVICE_STATUS call and the test below can
+ * be reinstated when device firmwares become more reliable.
+ * Don't hold your breath.
*/
#if 0
/* Rule out self-powered configs for a bus-powered device */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 42b457030b03..0eb010a3f5bc 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1614,6 +1614,7 @@ static int activate_ep_files (struct dev_data *dev)
data, &ep_config_operations,
&data->dentry);
if (!data->inode) {
+ usb_ep_free_request(ep, data->req);
kfree (data);
goto enomem;
}
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 6a4b93ad1082..0b9293493957 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2166,7 +2166,7 @@ static void handle_ep_small (struct net2280_ep *ep)
ep->stopped = 1;
set_halt (ep);
mode = 2;
- } else if (!req && ep->stopped)
+ } else if (!req && !ep->stopped)
write_fifo (ep, NULL);
}
} else {
@@ -2280,9 +2280,7 @@ static void handle_ep_small (struct net2280_ep *ep)
/* if we wrote it all, we're usually done */
if (req->req.actual == req->req.length) {
if (ep->num == 0) {
- /* wait for control status */
- if (mode != 2)
- req = NULL;
+ /* send zlps until the status stage */
} else if (!req->req.zero || len != ep->ep.maxpacket)
mode = 2;
}
@@ -2744,6 +2742,10 @@ static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
{
struct net2280 *dev = _dev;
+ /* shared interrupt, not ours */
+ if (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED)))
+ return IRQ_NONE;
+
spin_lock (&dev->lock);
/* handle disconnect, dma, and more */
@@ -2831,13 +2833,13 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
}
/* alloc, and start init */
- dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+ dev = kzalloc (sizeof *dev, SLAB_KERNEL);
if (dev == NULL){
retval = -ENOMEM;
goto done;
}
- memset (dev, 0, sizeof *dev);
+ pci_set_drvdata (pdev, dev);
spin_lock_init (&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &net2280_ops;
@@ -2950,7 +2952,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
/* done */
- pci_set_drvdata (pdev, dev);
INFO (dev, "%s\n", driver_desc);
INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
bufp, base, dev->chiprev);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1e03f1a5a5fd..a1bd2bea6deb 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -350,7 +350,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
- PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
+ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
.driver_data = (unsigned long) &ehci_pci_hc_driver,
},
{ /* end: all zeroes */ }
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 544f7589912f..73f5a379d9b3 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -863,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
i = ohci->num_ports;
while (i--)
ohci_writel (ohci, RH_PS_PSS,
- &ohci->regs->roothub.portstatus [temp]);
+ &ohci->regs->roothub.portstatus [i]);
ohci_dbg (ohci, "restart complete\n");
}
return 0;
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 1bfe96f4d045..b268537e389e 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -206,7 +206,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
static const struct pci_device_id pci_ids [] = { {
/* handle any USB OHCI controller */
- PCI_DEVICE_CLASS((PCI_CLASS_SERIAL_USB << 8) | 0x10, ~0),
+ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0),
.driver_data = (unsigned long) &ohci_pci_hc_driver,
}, { /* end: all zeroes */ }
};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index acde8868da21..fafe7c1265b3 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -185,6 +185,9 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
/* Select Power Management Mode */
pxa27x_ohci_select_pmm(inf->port_mode);
+ if (inf->power_budget)
+ hcd->power_budget = inf->power_budget;
+
ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index c0c4db78b590..d225e11f4055 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -858,7 +858,7 @@ static const struct hc_driver uhci_driver = {
static const struct pci_device_id uhci_pci_ids[] = { {
/* handle any USB UHCI controller */
- PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x00), ~0),
+ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),
.driver_data = (unsigned long) &uhci_driver,
}, { /* end: all zeroes */ }
};
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index f419bd82ab7f..435273e7c85c 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1557,6 +1557,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_HP 0x03f0
#define USB_DEVICE_ID_HP_USBHUB_KB 0x020c
+#define USB_VENDOR_ID_IBM 0x04b3
+#define USB_DEVICE_ID_IBM_USBHUB_KB 0x3005
+
#define USB_VENDOR_ID_CREATIVELABS 0x062a
#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201
@@ -1681,6 +1684,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_USBHUB_KB, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET },
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 6dd666696178..c4670e1d4654 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -317,6 +317,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
}
schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index 3824df33094e..1fd9cb85f4ca 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
+#include <linux/delay.h>
#define MAX_INTEL_HEX_RECORD_LENGTH 16
typedef struct _INTEL_HEX_RECORD
@@ -114,6 +115,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
+ msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
* Note: collect up to 1023 (yes!) bytes and send them with
@@ -150,6 +152,7 @@ static int emi26_load_firmware (struct usb_device *dev)
goto wraperr;
}
}
+ msleep(250); /* let device settle */
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
@@ -192,6 +195,7 @@ static int emi26_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
goto wraperr;
}
+ msleep(250); /* let device settle */
/* return 1 to fail the driver inialization
* and give real driver change to load */
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 52fea2e08db8..fe351371f274 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/delay.h>
#define MAX_INTEL_HEX_RECORD_LENGTH 16
typedef struct _INTEL_HEX_RECORD
@@ -123,6 +124,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
+ msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
* Note: collect up to 1023 (yes!) bytes and send them with
@@ -166,6 +168,7 @@ static int emi62_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
goto wraperr;
}
+ msleep(250); /* let device settle */
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -228,6 +231,7 @@ static int emi62_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __FUNCTION__, err);
goto wraperr;
}
+ msleep(250); /* let device settle */
kfree(buf);
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index efd6ca7e4ac5..054059632a21 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -301,21 +301,4 @@ config USB_NET_ZAURUS
some cases CDC MDLM) protocol, not "g_ether".
-config USB_ZD1201
- tristate "USB ZD1201 based Wireless device support"
- depends on NET_RADIO
- select FW_LOADER
- ---help---
- Say Y if you want to use wireless LAN adapters based on the ZyDAS
- ZD1201 chip.
-
- This driver makes the adapter appear as a normal Ethernet interface,
- typically on wlan0.
-
- The zd1201 device requires external firmware to be loaded.
- This can be found at http://linux-lc100020.sourceforge.net/
-
- To compile this driver as a module, choose M here: the
- module will be called zd1201.
-
endmenu
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index a21e6eaabaf6..160f19dbdf12 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
-obj-$(CONFIG_USB_ZD1201) += zd1201.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 2deb4c01539e..7683926a1b6f 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -318,6 +318,8 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
set_register(pegasus, PhyCtrl, (indx | PHY_READ));
for (i = 0; i < REG_TIMEOUT; i++) {
ret = get_registers(pegasus, PhyCtrl, 1, data);
+ if (ret == -ESHUTDOWN)
+ goto fail;
if (data[0] & PHY_DONE)
break;
}
@@ -326,6 +328,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
*regd = le16_to_cpu(regdi);
return ret;
}
+fail:
if (netif_msg_drv(pegasus))
dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
@@ -354,12 +357,15 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
for (i = 0; i < REG_TIMEOUT; i++) {
ret = get_registers(pegasus, PhyCtrl, 1, data);
+ if (ret == -ESHUTDOWN)
+ goto fail;
if (data[0] & PHY_DONE)
break;
}
if (i < REG_TIMEOUT)
return ret;
+fail:
if (netif_msg_drv(pegasus))
dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -387,6 +393,8 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
if (tmp & EPROM_DONE)
break;
+ if (ret == -ESHUTDOWN)
+ goto fail;
}
if (i < REG_TIMEOUT) {
ret = get_registers(pegasus, EpromData, 2, &retdatai);
@@ -394,6 +402,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
return ret;
}
+fail:
if (netif_msg_drv(pegasus))
dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -433,12 +442,15 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
for (i = 0; i < REG_TIMEOUT; i++) {
ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
+ if (ret == -ESHUTDOWN)
+ goto fail;
if (tmp & EPROM_DONE)
break;
}
disable_eprom_write(pegasus);
if (i < REG_TIMEOUT)
return ret;
+fail:
if (netif_msg_drv(pegasus))
dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -1378,9 +1390,8 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
struct pegasus *pegasus = usb_get_intfdata(intf);
netif_device_detach (pegasus->net);
+ cancel_delayed_work(&pegasus->carrier_check);
if (netif_running(pegasus->net)) {
- cancel_delayed_work(&pegasus->carrier_check);
-
usb_kill_urb(pegasus->rx_urb);
usb_kill_urb(pegasus->intr_urb);
}
@@ -1400,10 +1411,9 @@ static int pegasus_resume (struct usb_interface *intf)
pegasus->intr_urb->status = 0;
pegasus->intr_urb->actual_length = 0;
intr_callback(pegasus->intr_urb, NULL);
-
- queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
- CARRIER_CHECK_DELAY);
}
+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+ CARRIER_CHECK_DELAY);
return 0;
}
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index f96b73f54bf1..5c60be521561 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -71,6 +71,16 @@ config USB_SERIAL_ANYDATA
To compile this driver as a module, choose M here: the
module will be called anydata.
+config USB_SERIAL_ARK3116
+ tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)"
+ depends on USB_SERIAL && EXPERIMENTAL
+ help
+ Say Y here if you want to use a ARK Micro 3116 USB to Serial
+ device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ark3116
+
config USB_SERIAL_BELKIN
tristate "USB Belkin and Peracom Single Port Serial Driver"
depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 93c21245b1af..5a0960fc9d3e 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -13,6 +13,7 @@ usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o
+obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index dbf1f063098c..694b205f9b73 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -18,6 +18,7 @@
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
new file mode 100644
index 000000000000..8dec796222a0
--- /dev/null
+++ b/drivers/usb/serial/ark3116.c
@@ -0,0 +1,465 @@
+/*
+ * ark3116
+ * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
+ * productid=0x0232) (used in a datacable called KQ-U8A)
+ *
+ * - based on code by krisfx -> thanks !!
+ * (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457)
+ *
+ * - based on logs created by usbsnoopy
+ *
+ * Author : Simon Schulz [ark3116_driver<AT>auctionant.de]
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x6547, 0x0232) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ark3116_private {
+ spinlock_t lock;
+ u8 termios_initialized;
+};
+
+static inline void ARK3116_SND(struct usb_serial *serial, int seq,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index)
+{
+ int result;
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev,0),
+ request, requesttype, value, index,
+ NULL,0x00, 1000);
+ dbg("%03d > ok",seq);
+}
+
+static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index, __u8 expected,
+ char *buf)
+{
+ int result;
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev,0),
+ request, requesttype, value, index,
+ buf, 0x0000001, 1000);
+ if (result)
+ dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]);
+ else
+ dbg("%03d < 0 bytes", seq);
+}
+
+
+static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index, char *buf)
+{
+ usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev,0),
+ request, requesttype, value, index,
+ buf, 0x0000001, 1000);
+}
+
+
+static int ark3116_attach(struct usb_serial *serial)
+{
+ char *buf;
+ struct ark3116_private *priv;
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL);
+ if (!priv)
+ goto cleanup;
+ memset (priv, 0x00, sizeof (struct ark3116_private));
+ spin_lock_init(&priv->lock);
+
+ usb_set_serial_port_data(serial->port[i], priv);
+ }
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ dbg("error kmalloc -> out of mem ?");
+ goto cleanup;
+ }
+
+ /* 3 */
+ ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002);
+ ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001);
+ ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008);
+ ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B);
+
+ /* <-- seq7 */
+ ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf);
+ ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003);
+ ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000);
+ ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001);
+ ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003);
+
+ /* <-- seq12 */
+ ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004);
+
+ /* 14 */
+ ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004);
+
+ /* 16 */
+ ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ /* --> seq17 */
+ ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004);
+
+ /* <-- seq18 */
+ ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+
+ /* --> seq19 */
+ ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004);
+
+
+ /* <-- seq20 */
+ /* seems like serial port status info (RTS, CTS,...) */
+ /* returns modem control line status ?! */
+ ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
+
+ /* set 9600 baud & do some init ?! */
+ ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
+ ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000);
+ ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001);
+ ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
+ ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
+ ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
+ ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
+ ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003);
+
+ kfree(buf);
+ return(0);
+
+cleanup:
+ for (--i; i>=0; --i)
+ usb_set_serial_port_data(serial->port[i], NULL);
+ return -ENOMEM;
+}
+
+static void ark3116_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ struct ark3116_private *priv = usb_get_serial_port_data(port);
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned long flags;
+ int baud;
+ int ark3116_baud;
+ char *buf;
+ char config;
+
+ config = 0;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg("%s - no tty structures", __FUNCTION__);
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ priv->termios_initialized = 1;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ cflag = port->tty->termios->c_cflag;
+
+ /* check that they really want us to change something: */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s - nothing to change...", __FUNCTION__);
+ return;
+ }
+ }
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ dbg("error kmalloc");
+ return;
+ }
+
+ /* set data bit count (8/7/6/5) */
+ if (cflag & CSIZE){
+ switch (cflag & CSIZE){
+ case CS5:
+ config |= 0x00;
+ dbg("setting CS5");
+ break;
+ case CS6:
+ config |= 0x01;
+ dbg("setting CS6");
+ break;
+ case CS7:
+ config |= 0x02;
+ dbg("setting CS7");
+ break;
+ default:
+ err ("CSIZE was set but not CS5-CS8, using CS8!");
+ case CS8:
+ config |= 0x03;
+ dbg("setting CS8");
+ break;
+ }
+ }
+
+ /* set parity (NONE,EVEN,ODD) */
+ if (cflag & PARENB){
+ if (cflag & PARODD) {
+ config |= 0x08;
+ dbg("setting parity to ODD");
+ } else {
+ config |= 0x18;
+ dbg("setting parity to EVEN");
+ }
+ } else {
+ dbg("setting parity to NONE");
+ }
+
+ /* SET STOPBIT (1/2) */
+ if (cflag & CSTOPB) {
+ config |= 0x04;
+ dbg ("setting 2 stop bits");
+ } else {
+ dbg ("setting 1 stop bit");
+ }
+
+
+ /* set baudrate: */
+ baud = 0;
+ switch (cflag & CBAUD){
+ case B0:
+ err("can't set 0baud, using 9600 instead");
+ break;
+ case B75: baud = 75; break;
+ case B150: baud = 150; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ default:
+ dbg("does not support the baudrate requested (fix it)");
+ break;
+ }
+
+ /* set 9600 as default (if given baudrate is invalid for example) */
+ if (baud == 0)
+ baud = 9600;
+
+ /*
+ * found by try'n'error, be careful, maybe there are other options
+ * for multiplicator etc!
+ */
+ if (baud == 460800)
+ /* strange, for 460800 the formula is wrong
+ * (dont use round(), then 9600baud is wrong) */
+ ark3116_baud = 7;
+ else
+ ark3116_baud = 3000000 / baud;
+
+ /* ? */
+ ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf);
+ /* offset = buf[0]; */
+ /* offset = 0x03; */
+ /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */
+
+
+ /* set baudrate */
+ dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud);
+ ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
+ ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000);
+ ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001);
+ ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
+
+ /* ? */
+ ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
+ ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
+
+ /* set data bit count, stop bit count & parity: */
+ dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
+ ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
+ ARK3116_SND(serial,154,0xFE,0x40,config,0x0003);
+
+ if (cflag & CRTSCTS)
+ dbg("CRTSCTS not supported by chipset ?!");
+
+ /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */
+
+ kfree(buf);
+ return;
+}
+
+static int ark3116_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct termios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ char *buf;
+ int result = 0;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ dbg("error kmalloc -> out of mem ?");
+ return -ENOMEM;
+ }
+
+ result = usb_serial_generic_open(port, filp);
+ if (result)
+ return result;
+
+ /* open */
+ ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf);
+
+ ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003);
+ ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000);
+ ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001);
+ ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003);
+
+ ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf);
+ ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004);
+
+ ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf);
+ ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004);
+
+ ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+
+ ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004);
+
+ ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+
+ ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004);
+
+ /* returns different values (control lines ?!) */
+ ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
+
+ /* initialise termios: */
+ if (port->tty)
+ ark3116_set_termios(port, &tmp_termios);
+
+ kfree(buf);
+
+ return result;
+
+}
+
+static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ dbg("ioctl not supported yet...");
+ return -ENOIOCTLCMD;
+}
+
+static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct usb_serial *serial = port->serial;
+ char *buf;
+ char temp;
+
+ /* seems like serial port status info (RTS, CTS,...) is stored
+ * in reg(?) 0x0006
+ * pcb connection point 11 = GND -> sets bit4 of response
+ * pcb connection point 7 = GND -> sets bit6 of response
+ */
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ dbg("error kmalloc");
+ return -ENOMEM;
+ }
+
+ /* read register: */
+ ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf);
+ temp = buf[0];
+ kfree(buf);
+
+ /* i do not really know if bit4=CTS and bit6=DSR... was just a
+ * quick guess !!
+ */
+ return (temp & (1<<4) ? TIOCM_CTS : 0) |
+ (temp & (1<<6) ? TIOCM_DSR : 0);
+}
+
+static struct usb_driver ark3116_driver = {
+ .name = "ark3116",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static struct usb_serial_driver ark3116_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ark3116",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .attach = ark3116_attach,
+ .set_termios = ark3116_set_termios,
+ .ioctl = ark3116_ioctl,
+ .tiocmget = ark3116_tiocmget,
+ .open = ark3116_open,
+};
+
+static int __init ark3116_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&ark3116_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&ark3116_driver);
+ if (retval)
+ usb_serial_deregister(&ark3116_device);
+ return retval;
+}
+
+static void __exit ark3116_exit(void)
+{
+ usb_deregister(&ark3116_driver);
+ usb_serial_deregister(&ark3116_device);
+}
+
+module_init(ark3116_init);
+module_exit(ark3116_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f5851db67f5b..986d7622273d 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -307,7 +307,9 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static struct usb_device_id id_table_combined [] = {
+ { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
@@ -493,8 +495,11 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
{ USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 2155f0e4a378..d69a917e768f 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -32,6 +32,10 @@
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
+/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
+#define FTDI_ACTZWAVE_PID 0xF2D0
+
+
/* www.irtrans.de device */
#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
@@ -39,6 +43,9 @@
/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
+/* iPlus device */
+#define FTDI_IPLUS_PID 0xD070 /* Product Id */
+
/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
/* they use the ftdi chipset for the USB interface and the vendor id is the same */
#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
@@ -153,6 +160,11 @@
#define ICOM_ID1_PID 0x0004
/*
+ * ASK.fr devices
+ */
+#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
+
+/*
* DSS-20 Sync Station for Sony Ericsson P800
*/
@@ -400,6 +412,11 @@
#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
/*
+ * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
+ */
+#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */
+
+/*
* Eclo (http://www.eclo.pt/) product IDs.
* PID 0xEA90 submitted by Martin Grill.
*/
@@ -413,6 +430,11 @@
#define PAPOUCH_VID 0x5050 /* Vendor ID */
#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
+/*
+ * ACG Identification Technologies GmbH products (http://www.acg.de/).
+ * Submitted by anton -at- goto10 -dot- org.
+ */
+#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 476cda107f4f..c62cc2876519 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -138,6 +138,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
return result;
}
+EXPORT_SYMBOL_GPL(usb_serial_generic_open);
static void generic_cleanup (struct usb_serial_port *port)
{
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 4d40704dea2c..238033a87092 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -257,14 +257,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
return (0);
}
- spin_lock(&port->lock);
- if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_lock(&wport->lock);
+ if (wport->write_urb_busy) {
+ spin_unlock(&wport->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
- port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ wport->write_urb_busy = 1;
+ spin_unlock(&wport->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@@ -283,7 +283,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
wport->write_urb->dev = serial->dev;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
- port->write_urb_busy = 0;
+ wport->write_urb_busy = 0;
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
} else
result = count;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index ccf746b27d4e..c96714bb1cb8 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -61,6 +61,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
+ { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 09f379b19e98..7f29e81d3e35 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -26,6 +26,7 @@
#define ITEGNO_VENDOR_ID 0x0eba
#define ITEGNO_PRODUCT_ID 0x1080
+#define ITEGNO_PRODUCT_ID_2080 0x2080
#define MA620_VENDOR_ID 0x0df7
#define MA620_PRODUCT_ID 0x0620
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 071f86a59c08..9c36f0ece20f 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -189,11 +189,15 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
portNumber = tty->index - serial->minor;
port = serial->port[portNumber];
- if (!port)
- return -ENODEV;
+ if (!port) {
+ retval = -ENODEV;
+ goto bailout_kref_put;
+ }
- if (mutex_lock_interruptible(&port->mutex))
- return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&port->mutex)) {
+ retval = -ERESTARTSYS;
+ goto bailout_kref_put;
+ }
++port->open_count;
@@ -209,7 +213,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
* safe because we are called with BKL held */
if (!try_module_get(serial->type->driver.owner)) {
retval = -ENODEV;
- goto bailout_kref_put;
+ goto bailout_mutex_unlock;
}
/* only call the device specific open if this
@@ -224,10 +228,11 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
bailout_module_put:
module_put(serial->type->driver.owner);
-bailout_kref_put:
- kref_put(&serial->kref, destroy_serial);
+bailout_mutex_unlock:
port->open_count = 0;
mutex_unlock(&port->mutex);
+bailout_kref_put:
+ kref_put(&serial->kref, destroy_serial);
return retval;
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 557411c6e7c7..f806553cd9a4 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -508,6 +508,7 @@ no_firmware:
err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description);
err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description);
err("%s: please contact support@connecttech.com\n", serial->type->description);
+ kfree(result);
return -ENODEV;
no_command_private:
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index c4a9dcff5f2b..aec5ea8682d5 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -411,7 +411,7 @@ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
"Iomega",
"USB Clik! 40",
- US_SC_8070, US_PR_BULK, NULL,
+ US_SC_8070, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* Yakumo Mega Image 37
@@ -773,6 +773,13 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Olivier Blondeau <zeitoun@gmail.com> */
+UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100,
+ "ATMEL",
+ "SND1 Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
/* Submitted by Roman Hodek <roman@hodek.net> */
UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9060e7137441..5a2840aeb547 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -167,6 +167,69 @@ config FB_ARMCLCD
here and read <file:Documentation/modules.txt>. The module
will be called amba-clcd.
+choice
+
+ depends on FB_ARMCLCD && (ARCH_LH7A40X || ARCH_LH7952X)
+ prompt "LCD Panel"
+ default FB_ARMCLCD_SHARP_LQ035Q7DB02
+
+config FB_ARMCLCD_SHARP_LQ035Q7DB02_HRTFT
+ bool "LogicPD LCD 3.5\" QVGA w/HRTFT IC"
+ help
+ This is an implementation of the Sharp LQ035Q7DB02, a 3.5"
+ color QVGA, HRTFT panel. The LogicPD device includes an
+ an integrated HRTFT controller IC.
+ The native resolution is 240x320.
+
+config FB_ARMCLCD_SHARP_LQ057Q3DC02
+ bool "LogicPD LCD 5.7\" QVGA"
+ help
+ This is an implementation of the Sharp LQ057Q3DC02, a 5.7"
+ color QVGA, TFT panel. The LogicPD device includes an
+ The native resolution is 320x240.
+
+config FB_ARMCLCD_SHARP_LQ64D343
+ bool "LogicPD LCD 6.4\" VGA"
+ help
+ This is an implementation of the Sharp LQ64D343, a 6.4"
+ color VGA, TFT panel. The LogicPD device includes an
+ The native resolution is 640x480.
+
+config FB_ARMCLCD_SHARP_LQ10D368
+ bool "LogicPD LCD 10.4\" VGA"
+ help
+ This is an implementation of the Sharp LQ10D368, a 10.4"
+ color VGA, TFT panel. The LogicPD device includes an
+ The native resolution is 640x480.
+
+
+config FB_ARMCLCD_SHARP_LQ121S1DG41
+ bool "LogicPD LCD 12.1\" SVGA"
+ help
+ This is an implementation of the Sharp LQ121S1DG41, a 12.1"
+ color SVGA, TFT panel. The LogicPD device includes an
+ The native resolution is 800x600.
+
+ This panel requires a clock rate may be an integer fraction
+ of the base LCDCLK frequency. The driver will select the
+ highest frequency available that is lower than the maximum
+ allowed. The panel may flicker if the clock rate is
+ slower than the recommended minimum.
+
+config FB_ARMCLCD_AUO_A070VW01_WIDE
+ bool "AU Optronics A070VW01 LCD 7.0\" WIDE"
+ help
+ This is an implementation of the AU Optronics, a 7.0"
+ WIDE Color. The native resolution is 234x480.
+
+config FB_ARMCLCD_HITACHI
+ bool "Hitachi Wide Screen 800x480"
+ help
+ This is an implementation of the Hitachi 800x480.
+
+endchoice
+
+
config FB_ACORN
bool "Acorn VIDC support"
depends on (FB = y) && ARM && (ARCH_ACORN || ARCH_CLPS7500)
@@ -400,6 +463,8 @@ config FB_ASILIANT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ help
+ This is the frame buffer device driver for the Asiliant 69030 chipset
config FB_IMSTT
bool "IMS Twin Turbo display support"
@@ -741,7 +806,7 @@ config FB_I810_I2C
config FB_INTEL
tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
- depends on FB && EXPERIMENTAL && PCI && X86_32
+ depends on FB && EXPERIMENTAL && PCI && X86
select AGP
select AGP_INTEL
select FB_MODE_HELPERS
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 3d04b2def0f1..789450bb0bc9 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -214,10 +214,13 @@ int au1100fb_setmode(struct au1100fb_device *fbdev)
*/
int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
{
- struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
- u32 *palette = fbdev->regs->lcd_pallettebase;
+ struct au1100fb_device *fbdev;
+ u32 *palette;
u32 value;
+ fbdev = to_au1100fb_device(fbi);
+ palette = fbdev->regs->lcd_pallettebase;
+
if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1))
return -EINVAL;
@@ -316,9 +319,11 @@ int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
*/
int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
{
- struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+ struct au1100fb_device *fbdev;
int dy;
+ fbdev = to_au1100fb_device(fbi);
+
print_dbg("fb_pan_display %p %p", var, fbi);
if (!var || !fbdev) {
@@ -382,10 +387,12 @@ void au1100fb_fb_rotate(struct fb_info *fbi, int angle)
*/
int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{
- struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+ struct au1100fb_device *fbdev;
unsigned int len;
unsigned long start=0, off;
+ fbdev = to_au1100fb_device(fbi);
+
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
return -EINVAL;
}
@@ -467,7 +474,7 @@ int au1100fb_drv_probe(struct device *dev)
if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,
DRIVER_NAME)) {
- print_err("fail to lock memory region at 0x%08x",
+ print_err("fail to lock memory region at 0x%08lx",
au1100fb_fix.mmio_start);
return -EBUSY;
}
@@ -595,13 +602,13 @@ int au1100fb_drv_remove(struct device *dev)
return 0;
}
-int au1100fb_drv_suspend(struct device *dev, u32 state, u32 level)
+int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
{
/* TODO */
return 0;
}
-int au1100fb_drv_resume(struct device *dev, u32 level)
+int au1100fb_drv_resume(struct device *dev)
{
/* TODO */
return 0;
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index b367de30b98c..600d3e0e08b7 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1920,1925 +1920,3 @@ module_exit(au1200fb_cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1200 LCD Driver.
- *
- * Copyright 2004-2005 AMD
- * Author: AMD
- *
- * Based on:
- * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
- * Created 28 Dec 1997 by Geert Uytterhoeven
- *
- * 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 <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ctype.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include "au1200fb.h"
-
-#ifdef CONFIG_PM
-#include <asm/mach-au1x00/au1xxx_pm.h>
-#endif
-
-#ifndef CONFIG_FB_AU1200_DEVS
-#define CONFIG_FB_AU1200_DEVS 4
-#endif
-
-#define DRIVER_NAME "au1200fb"
-#define DRIVER_DESC "LCD controller driver for AU1200 processors"
-
-#define DEBUG 1
-
-#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
-#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
-#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
-
-#if DEBUG
-#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
-#else
-#define print_dbg(f, arg...) do {} while (0)
-#endif
-
-
-#define AU1200_LCD_FB_IOCTL 0x46FF
-
-#define AU1200_LCD_SET_SCREEN 1
-#define AU1200_LCD_GET_SCREEN 2
-#define AU1200_LCD_SET_WINDOW 3
-#define AU1200_LCD_GET_WINDOW 4
-#define AU1200_LCD_SET_PANEL 5
-#define AU1200_LCD_GET_PANEL 6
-
-#define SCREEN_SIZE (1<< 1)
-#define SCREEN_BACKCOLOR (1<< 2)
-#define SCREEN_BRIGHTNESS (1<< 3)
-#define SCREEN_COLORKEY (1<< 4)
-#define SCREEN_MASK (1<< 5)
-
-struct au1200_lcd_global_regs_t {
- unsigned int flags;
- unsigned int xsize;
- unsigned int ysize;
- unsigned int backcolor;
- unsigned int brightness;
- unsigned int colorkey;
- unsigned int mask;
- unsigned int panel_choice;
- char panel_desc[80];
-
-};
-
-#define WIN_POSITION (1<< 0)
-#define WIN_ALPHA_COLOR (1<< 1)
-#define WIN_ALPHA_MODE (1<< 2)
-#define WIN_PRIORITY (1<< 3)
-#define WIN_CHANNEL (1<< 4)
-#define WIN_BUFFER_FORMAT (1<< 5)
-#define WIN_COLOR_ORDER (1<< 6)
-#define WIN_PIXEL_ORDER (1<< 7)
-#define WIN_SIZE (1<< 8)
-#define WIN_COLORKEY_MODE (1<< 9)
-#define WIN_DOUBLE_BUFFER_MODE (1<< 10)
-#define WIN_RAM_ARRAY_MODE (1<< 11)
-#define WIN_BUFFER_SCALE (1<< 12)
-#define WIN_ENABLE (1<< 13)
-
-struct au1200_lcd_window_regs_t {
- unsigned int flags;
- unsigned int xpos;
- unsigned int ypos;
- unsigned int alpha_color;
- unsigned int alpha_mode;
- unsigned int priority;
- unsigned int channel;
- unsigned int buffer_format;
- unsigned int color_order;
- unsigned int pixel_order;
- unsigned int xsize;
- unsigned int ysize;
- unsigned int colorkey_mode;
- unsigned int double_buffer_mode;
- unsigned int ram_array_mode;
- unsigned int xscale;
- unsigned int yscale;
- unsigned int enable;
-};
-
-
-struct au1200_lcd_iodata_t {
- unsigned int subcmd;
- struct au1200_lcd_global_regs_t global;
- struct au1200_lcd_window_regs_t window;
-};
-
-#if defined(__BIG_ENDIAN)
-#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
-#else
-#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
-#endif
-#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
-
-/* Private, per-framebuffer management information (independent of the panel itself) */
-struct au1200fb_device {
- struct fb_info fb_info; /* FB driver info record */
-
- int plane;
- unsigned char* fb_mem; /* FrameBuffer memory map */
- unsigned int fb_len;
- dma_addr_t fb_phys;
-};
-
-static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
-/********************************************************************/
-
-/* LCD controller restrictions */
-#define AU1200_LCD_MAX_XRES 1280
-#define AU1200_LCD_MAX_YRES 1024
-#define AU1200_LCD_MAX_BPP 32
-#define AU1200_LCD_MAX_CLK 96000000 /* fixme: this needs to go away ? */
-#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
-
-/* Default number of visible screen buffer to allocate */
-#define AU1200FB_NBR_VIDEO_BUFFERS 1
-
-/********************************************************************/
-
-static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
-static int window_index = 2; /* default is zero */
-static int panel_index = 2; /* default is zero */
-static struct window_settings *win;
-static struct panel_settings *panel;
-static int noblanking = 1;
-static int nohwcursor = 0;
-
-struct window_settings {
- unsigned char name[64];
- uint32 mode_backcolor;
- uint32 mode_colorkey;
- uint32 mode_colorkeymsk;
- struct {
- int xres;
- int yres;
- int xpos;
- int ypos;
- uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
- uint32 mode_winenable;
- } w[4];
-};
-
-#if defined(__BIG_ENDIAN)
-#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
-#else
-#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
-#endif
-
-extern int board_au1200fb_panel_init (void);
-extern int board_au1200fb_panel_shutdown (void);
-
-#ifdef CONFIG_PM
-int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
- au1xxx_request_t request, void *data);
-au1xxx_power_dev_t *LCD_pm_dev;
-#endif
-
-/*
- * Default window configurations
- */
-static struct window_settings windows[] = {
- { /* Index 0 */
- "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
- /* mode_backcolor */ 0x006600ff,
- /* mode_colorkey,msk*/ 0, 0,
- {
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP,
- /* mode_winenable*/ LCD_WINENABLE_WEN0,
- },
- {
- /* xres, yres, xpos, ypos */ 100, 100, 100, 100,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP |
- LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ LCD_WINENABLE_WEN1,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP,
- /* mode_winenable*/ 0,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP |
- LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ 0,
- },
- },
- },
-
- { /* Index 1 */
- "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
- /* mode_backcolor */ 0x006600ff,
- /* mode_colorkey,msk*/ 0, 0,
- {
- {
- /* xres, yres, xpos, ypos */ 320, 240, 5, 5,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
- LCD_WINCTRL1_PO_00,
- /* mode_winenable*/ LCD_WINENABLE_WEN0,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
- | LCD_WINCTRL1_PO_16BPP,
- /* mode_winenable*/ 0,
- },
- {
- /* xres, yres, xpos, ypos */ 100, 100, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP |
- LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
- },
- {
- /* xres, yres, xpos, ypos */ 200, 25, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP |
- LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ 0,
- },
- },
- },
- { /* Index 2 */
- "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
- /* mode_backcolor */ 0x006600ff,
- /* mode_colorkey,msk*/ 0, 0,
- {
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP,
- /* mode_winenable*/ LCD_WINENABLE_WEN0,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP,
- /* mode_winenable*/ 0,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
- LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
- },
- {
- /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
- /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
- LCD_WINCTRL1_PO_16BPP |
- LCD_WINCTRL1_PIPE,
- /* mode_winenable*/ 0,
- },
- },
- },
- /* Need VGA 640 @ 24bpp, @ 32bpp */
- /* Need VGA 800 @ 24bpp, @ 32bpp */
- /* Need VGA 1024 @ 24bpp, @ 32bpp */
-};
-
-/*
- * Controller configurations for various panels.
- */
-
-struct panel_settings
-{
- const char name[25]; /* Full name <vendor>_<model> */
-
- struct fb_monspecs monspecs; /* FB monitor specs */
-
- /* panel timings */
- uint32 mode_screen;
- uint32 mode_horztiming;
- uint32 mode_verttiming;
- uint32 mode_clkcontrol;
- uint32 mode_pwmdiv;
- uint32 mode_pwmhi;
- uint32 mode_outmask;
- uint32 mode_fifoctrl;
- uint32 mode_toyclksrc;
- uint32 mode_backlight;
- uint32 mode_auxpll;
- int (*device_init)(void);
- int (*device_shutdown)(void);
-#define Xres min_xres
-#define Yres min_yres
- u32 min_xres; /* Minimum horizontal resolution */
- u32 max_xres; /* Maximum horizontal resolution */
- u32 min_yres; /* Minimum vertical resolution */
- u32 max_yres; /* Maximum vertical resolution */
-};
-
-/********************************************************************/
-/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
-
-/* List of panels known to work with the AU1200 LCD controller.
- * To add a new panel, enter the same specifications as the
- * Generic_TFT one, and MAKE SURE that it doesn't conflicts
- * with the controller restrictions. Restrictions are:
- *
- * STN color panels: max_bpp <= 12
- * STN mono panels: max_bpp <= 4
- * TFT panels: max_bpp <= 16
- * max_xres <= 800
- * max_yres <= 600
- */
-static struct panel_settings known_lcd_panels[] =
-{
- [0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
- .name = "QVGA_320x240",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = LCD_SCREEN_SX_N(320) |
- LCD_SCREEN_SY_N(240),
- .mode_horztiming = 0x00c4623b,
- .mode_verttiming = 0x00502814,
- .mode_clkcontrol = 0x00020002, /* /4=24Mhz */
- .mode_pwmdiv = 0x00000000,
- .mode_pwmhi = 0x00000000,
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = NULL,
- .device_shutdown = NULL,
- 320, 320,
- 240, 240,
- },
-
- [1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
- .name = "VGA_640x480",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = 0x13f9df80,
- .mode_horztiming = 0x003c5859,
- .mode_verttiming = 0x00741201,
- .mode_clkcontrol = 0x00020001, /* /4=24Mhz */
- .mode_pwmdiv = 0x00000000,
- .mode_pwmhi = 0x00000000,
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = NULL,
- .device_shutdown = NULL,
- 640, 480,
- 640, 480,
- },
-
- [2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
- .name = "SVGA_800x600",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = 0x18fa5780,
- .mode_horztiming = 0x00dc7e77,
- .mode_verttiming = 0x00584805,
- .mode_clkcontrol = 0x00020000, /* /2=48Mhz */
- .mode_pwmdiv = 0x00000000,
- .mode_pwmhi = 0x00000000,
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = NULL,
- .device_shutdown = NULL,
- 800, 800,
- 600, 600,
- },
-
- [3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
- .name = "XVGA_1024x768",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = 0x1ffaff80,
- .mode_horztiming = 0x007d0e57,
- .mode_verttiming = 0x00740a01,
- .mode_clkcontrol = 0x000A0000, /* /1 */
- .mode_pwmdiv = 0x00000000,
- .mode_pwmhi = 0x00000000,
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 6, /* 72MHz AUXPLL */
- .device_init = NULL,
- .device_shutdown = NULL,
- 1024, 1024,
- 768, 768,
- },
-
- [4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
- .name = "XVGA_1280x1024",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = 0x27fbff80,
- .mode_horztiming = 0x00cdb2c7,
- .mode_verttiming = 0x00600002,
- .mode_clkcontrol = 0x000A0000, /* /1 */
- .mode_pwmdiv = 0x00000000,
- .mode_pwmhi = 0x00000000,
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 10, /* 120MHz AUXPLL */
- .device_init = NULL,
- .device_shutdown = NULL,
- 1280, 1280,
- 1024, 1024,
- },
-
- [5] = { /* Samsung 1024x768 TFT */
- .name = "Samsung_1024x768_TFT",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = 0x1ffaff80,
- .mode_horztiming = 0x018cc677,
- .mode_verttiming = 0x00241217,
- .mode_clkcontrol = 0x00000000, /* SCB 0x1 /4=24Mhz */
- .mode_pwmdiv = 0x8000063f, /* SCB 0x0 */
- .mode_pwmhi = 0x03400000, /* SCB 0x0 */
- .mode_outmask = 0x00FFFFFF,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = board_au1200fb_panel_init,
- .device_shutdown = board_au1200fb_panel_shutdown,
- 1024, 1024,
- 768, 768,
- },
-
- [6] = { /* Toshiba 640x480 TFT */
- .name = "Toshiba_640x480_TFT",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = LCD_SCREEN_SX_N(640) |
- LCD_SCREEN_SY_N(480),
- .mode_horztiming = LCD_HORZTIMING_HPW_N(96) |
- LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
- .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
- LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
- .mode_clkcontrol = 0x00000000, /* /4=24Mhz */
- .mode_pwmdiv = 0x8000063f,
- .mode_pwmhi = 0x03400000,
- .mode_outmask = 0x00fcfcfc,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = board_au1200fb_panel_init,
- .device_shutdown = board_au1200fb_panel_shutdown,
- 640, 480,
- 640, 480,
- },
-
- [7] = { /* Sharp 320x240 TFT */
- .name = "Sharp_320x240_TFT",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 12500,
- .hfmax = 20000,
- .vfmin = 38,
- .vfmax = 81,
- .dclkmin = 4500000,
- .dclkmax = 6800000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = LCD_SCREEN_SX_N(320) |
- LCD_SCREEN_SY_N(240),
- .mode_horztiming = LCD_HORZTIMING_HPW_N(60) |
- LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
- .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
- LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
- .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
- .mode_pwmdiv = 0x8000063f,
- .mode_pwmhi = 0x03400000,
- .mode_outmask = 0x00fcfcfc,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = board_au1200fb_panel_init,
- .device_shutdown = board_au1200fb_panel_shutdown,
- 320, 320,
- 240, 240,
- },
-
- [8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
- .name = "Toppoly_TD070WGCB2",
- .monspecs = {
- .modedb = NULL,
- .modedb_len = 0,
- .hfmin = 30000,
- .hfmax = 70000,
- .vfmin = 60,
- .vfmax = 60,
- .dclkmin = 6000000,
- .dclkmax = 28000000,
- .input = FB_DISP_RGB,
- },
- .mode_screen = LCD_SCREEN_SX_N(856) |
- LCD_SCREEN_SY_N(480),
- .mode_horztiming = LCD_HORZTIMING_HND2_N(43) |
- LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
- .mode_verttiming = LCD_VERTTIMING_VND2_N(20) |
- LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
- .mode_clkcontrol = 0x00020001, /* /4=24Mhz */
- .mode_pwmdiv = 0x8000063f,
- .mode_pwmhi = 0x03400000,
- .mode_outmask = 0x00fcfcfc,
- .mode_fifoctrl = 0x2f2f2f2f,
- .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
- .mode_backlight = 0x00000000,
- .mode_auxpll = 8, /* 96MHz AUXPLL */
- .device_init = board_au1200fb_panel_init,
- .device_shutdown = board_au1200fb_panel_shutdown,
- 856, 856,
- 480, 480,
- },
-};
-
-#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
-
-/********************************************************************/
-
-#ifdef CONFIG_PM
-static int set_brightness(unsigned int brightness)
-{
- unsigned int hi1, divider;
-
- /* limit brightness pwm duty to >= 30/1600 */
- if (brightness < 30) {
- brightness = 30;
- }
- divider = (lcd->pwmdiv & 0x3FFFF) + 1;
- hi1 = (lcd->pwmhi >> 16) + 1;
- hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
- lcd->pwmhi &= 0xFFFF;
- lcd->pwmhi |= (hi1 << 16);
-
- return brightness;
-}
-#endif /* CONFIG_PM */
-
-static int winbpp (unsigned int winctrl1)
-{
- int bits = 0;
-
- /* how many bits are needed for each pixel format */
- switch (winctrl1 & LCD_WINCTRL1_FRM) {
- case LCD_WINCTRL1_FRM_1BPP:
- bits = 1;
- break;
- case LCD_WINCTRL1_FRM_2BPP:
- bits = 2;
- break;
- case LCD_WINCTRL1_FRM_4BPP:
- bits = 4;
- break;
- case LCD_WINCTRL1_FRM_8BPP:
- bits = 8;
- break;
- case LCD_WINCTRL1_FRM_12BPP:
- case LCD_WINCTRL1_FRM_16BPP655:
- case LCD_WINCTRL1_FRM_16BPP565:
- case LCD_WINCTRL1_FRM_16BPP556:
- case LCD_WINCTRL1_FRM_16BPPI1555:
- case LCD_WINCTRL1_FRM_16BPPI5551:
- case LCD_WINCTRL1_FRM_16BPPA1555:
- case LCD_WINCTRL1_FRM_16BPPA5551:
- bits = 16;
- break;
- case LCD_WINCTRL1_FRM_24BPP:
- case LCD_WINCTRL1_FRM_32BPP:
- bits = 32;
- break;
- }
-
- return bits;
-}
-
-static int fbinfo2index (struct fb_info *fb_info)
-{
- int i;
-
- for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) {
- if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
- return i;
- }
- printk("au1200fb: ERROR: fbinfo2index failed!\n");
- return -1;
-}
-
-static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
- int xpos, int ypos)
-{
- uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
- int xsz, ysz;
-
- /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
-
- winctrl0 = lcd->window[plane].winctrl0;
- winctrl1 = lcd->window[plane].winctrl1;
- winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
- winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
-
- /* Check for off-screen adjustments */
- xsz = win->w[plane].xres;
- ysz = win->w[plane].yres;
- if ((xpos + win->w[plane].xres) > panel->Xres) {
- /* Off-screen to the right */
- xsz = panel->Xres - xpos; /* off by 1 ??? */
- /*printk("off screen right\n");*/
- }
-
- if ((ypos + win->w[plane].yres) > panel->Yres) {
- /* Off-screen to the bottom */
- ysz = panel->Yres - ypos; /* off by 1 ??? */
- /*printk("off screen bottom\n");*/
- }
-
- if (xpos < 0) {
- /* Off-screen to the left */
- xsz = win->w[plane].xres + xpos;
- fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
- xpos = 0;
- /*printk("off screen left\n");*/
- }
-
- if (ypos < 0) {
- /* Off-screen to the top */
- ysz = win->w[plane].yres + ypos;
- /* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
- ypos = 0;
- /*printk("off screen top\n");*/
- }
-
- /* record settings */
- win->w[plane].xpos = xpos;
- win->w[plane].ypos = ypos;
-
- xsz -= 1;
- ysz -= 1;
- winctrl0 |= (xpos << 21);
- winctrl0 |= (ypos << 10);
- winctrl1 |= (xsz << 11);
- winctrl1 |= (ysz << 0);
-
- /* Disable the window while making changes, then restore WINEN */
- winenable = lcd->winenable & (1 << plane);
- au_sync();
- lcd->winenable &= ~(1 << plane);
- lcd->window[plane].winctrl0 = winctrl0;
- lcd->window[plane].winctrl1 = winctrl1;
- lcd->window[plane].winbuf0 =
- lcd->window[plane].winbuf1 = fbdev->fb_phys;
- lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
- lcd->winenable |= winenable;
- au_sync();
-
- return 0;
-}
-
-static void au1200_setpanel (struct panel_settings *newpanel)
-{
- /*
- * Perform global setup/init of LCD controller
- */
- uint32 winenable;
-
- /* Make sure all windows disabled */
- winenable = lcd->winenable;
- lcd->winenable = 0;
- au_sync();
- /*
- * Ensure everything is disabled before reconfiguring
- */
- if (lcd->screen & LCD_SCREEN_SEN) {
- /* Wait for vertical sync period */
- lcd->intstatus = LCD_INT_SS;
- while ((lcd->intstatus & LCD_INT_SS) == 0) {
- au_sync();
- }
-
- lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/
-
- do {
- lcd->intstatus = lcd->intstatus; /*clear interrupts*/
- au_sync();
- /*wait for controller to shut down*/
- } while ((lcd->intstatus & LCD_INT_SD) == 0);
-
- /* Call shutdown of current panel (if up) */
- /* this must occur last, because if an external clock is driving
- the controller, the clock cannot be turned off before first
- shutting down the controller.
- */
- if (panel->device_shutdown != NULL)
- panel->device_shutdown();
- }
-
- /* Newpanel == NULL indicates a shutdown operation only */
- if (newpanel == NULL)
- return;
-
- panel = newpanel;
-
- printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
-
- /*
- * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
- */
- if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
- {
- uint32 sys_clksrc;
- au_writel(panel->mode_auxpll, SYS_AUXPLL);
- sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
- sys_clksrc |= panel->mode_toyclksrc;
- au_writel(sys_clksrc, SYS_CLKSRC);
- }
-
- /*
- * Configure panel timings
- */
- lcd->screen = panel->mode_screen;
- lcd->horztiming = panel->mode_horztiming;
- lcd->verttiming = panel->mode_verttiming;
- lcd->clkcontrol = panel->mode_clkcontrol;
- lcd->pwmdiv = panel->mode_pwmdiv;
- lcd->pwmhi = panel->mode_pwmhi;
- lcd->outmask = panel->mode_outmask;
- lcd->fifoctrl = panel->mode_fifoctrl;
- au_sync();
-
- /* fixme: Check window settings to make sure still valid
- * for new geometry */
-#if 0
- au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
- au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
- au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
- au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
-#endif
- lcd->winenable = winenable;
-
- /*
- * Re-enable screen now that it is configured
- */
- lcd->screen |= LCD_SCREEN_SEN;
- au_sync();
-
- /* Call init of panel */
- if (panel->device_init != NULL) panel->device_init();
-
- /* FIX!!!! not appropriate on panel change!!! Global setup/init */
- lcd->intenable = 0;
- lcd->intstatus = ~0;
- lcd->backcolor = win->mode_backcolor;
-
- /* Setup Color Key - FIX!!! */
- lcd->colorkey = win->mode_colorkey;
- lcd->colorkeymsk = win->mode_colorkeymsk;
-
- /* Setup HWCursor - FIX!!! Need to support this eventually */
- lcd->hwc.cursorctrl = 0;
- lcd->hwc.cursorpos = 0;
- lcd->hwc.cursorcolor0 = 0;
- lcd->hwc.cursorcolor1 = 0;
- lcd->hwc.cursorcolor2 = 0;
- lcd->hwc.cursorcolor3 = 0;
-
-
-#if 0
-#define D(X) printk("%25s: %08X\n", #X, X)
- D(lcd->screen);
- D(lcd->horztiming);
- D(lcd->verttiming);
- D(lcd->clkcontrol);
- D(lcd->pwmdiv);
- D(lcd->pwmhi);
- D(lcd->outmask);
- D(lcd->fifoctrl);
- D(lcd->window[0].winctrl0);
- D(lcd->window[0].winctrl1);
- D(lcd->window[0].winctrl2);
- D(lcd->window[0].winbuf0);
- D(lcd->window[0].winbuf1);
- D(lcd->window[0].winbufctrl);
- D(lcd->window[1].winctrl0);
- D(lcd->window[1].winctrl1);
- D(lcd->window[1].winctrl2);
- D(lcd->window[1].winbuf0);
- D(lcd->window[1].winbuf1);
- D(lcd->window[1].winbufctrl);
- D(lcd->window[2].winctrl0);
- D(lcd->window[2].winctrl1);
- D(lcd->window[2].winctrl2);
- D(lcd->window[2].winbuf0);
- D(lcd->window[2].winbuf1);
- D(lcd->window[2].winbufctrl);
- D(lcd->window[3].winctrl0);
- D(lcd->window[3].winctrl1);
- D(lcd->window[3].winctrl2);
- D(lcd->window[3].winbuf0);
- D(lcd->window[3].winbuf1);
- D(lcd->window[3].winbufctrl);
- D(lcd->winenable);
- D(lcd->intenable);
- D(lcd->intstatus);
- D(lcd->backcolor);
- D(lcd->winenable);
- D(lcd->colorkey);
- D(lcd->colorkeymsk);
- D(lcd->hwc.cursorctrl);
- D(lcd->hwc.cursorpos);
- D(lcd->hwc.cursorcolor0);
- D(lcd->hwc.cursorcolor1);
- D(lcd->hwc.cursorcolor2);
- D(lcd->hwc.cursorcolor3);
-#endif
-}
-
-static void au1200_setmode(struct au1200fb_device *fbdev)
-{
- int plane = fbdev->plane;
- /* Window/plane setup */
- lcd->window[plane].winctrl1 = ( 0
- | LCD_WINCTRL1_PRI_N(plane)
- | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
- ) ;
-
- au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
-
- lcd->window[plane].winctrl2 = ( 0
- | LCD_WINCTRL2_CKMODE_00
- | LCD_WINCTRL2_DBM
- | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
- | LCD_WINCTRL2_SCX_1
- | LCD_WINCTRL2_SCY_1
- ) ;
- lcd->winenable |= win->w[plane].mode_winenable;
- au_sync();
-}
-
-
-/* Inline helpers */
-
-/*#define panel_is_dual(panel) ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
-/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
-
-#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
-
-/* Bitfields format supported by the controller. */
-static struct fb_bitfield rgb_bitfields[][4] = {
- /* Red, Green, Blue, Transp */
- [LCD_WINCTRL1_FRM_16BPP655 >> 25] =
- { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPP565 >> 25] =
- { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPP556 >> 25] =
- { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
- { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
- { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
- { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
-
- [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
- { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
-
- [LCD_WINCTRL1_FRM_24BPP >> 25] =
- { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
-
- [LCD_WINCTRL1_FRM_32BPP >> 25] =
- { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Helpers */
-
-static void au1200fb_update_fbinfo(struct fb_info *fbi)
-{
- /* FIX!!!! This also needs to take the window pixel format into account!!! */
-
- /* Update var-dependent FB info */
- if (panel_is_color(panel)) {
- if (fbi->var.bits_per_pixel <= 8) {
- /* palettized */
- fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- fbi->fix.line_length = fbi->var.xres_virtual /
- (8/fbi->var.bits_per_pixel);
- } else {
- /* non-palettized */
- fbi->fix.visual = FB_VISUAL_TRUECOLOR;
- fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
- }
- } else {
- /* mono FIX!!! mono 8 and 4 bits */
- fbi->fix.visual = FB_VISUAL_MONO10;
- fbi->fix.line_length = fbi->var.xres_virtual / 8;
- }
-
- fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
- print_dbg("line length: %d\n", fbi->fix.line_length);
- print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* AU1200 framebuffer driver */
-
-/* fb_check_var
- * Validate var settings with hardware restrictions and modify it if necessary
- */
-static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *fbi)
-{
- struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
- u32 pixclock;
- int screen_size, plane;
-
- plane = fbdev->plane;
-
- /* Make sure that the mode respect all LCD controller and
- * panel restrictions. */
- var->xres = win->w[plane].xres;
- var->yres = win->w[plane].yres;
-
- /* No need for virtual resolution support */
- var->xres_virtual = var->xres;
- var->yres_virtual = var->yres;
-
- var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
-
- screen_size = var->xres_virtual * var->yres_virtual;
- if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
- else screen_size /= (8/var->bits_per_pixel);
-
- if (fbdev->fb_len < screen_size)
- return -EINVAL; /* Virtual screen is to big, abort */
-
- /* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
- /* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
- * clock can only be obtain by dividing this value by an even integer.
- * Fallback to a slower pixel clock if necessary. */
- pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
- pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
-
- if (AU1200_LCD_MAX_CLK % pixclock) {
- int diff = AU1200_LCD_MAX_CLK % pixclock;
- pixclock -= diff;
- }
-
- var->pixclock = KHZ2PICOS(pixclock/1000);
-#if 0
- if (!panel_is_active(panel)) {
- int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
-
- if (!panel_is_color(panel)
- && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
- /* STN 8bit mono panel support is up to 6MHz pixclock */
- var->pixclock = KHZ2PICOS(6000);
- } else if (!pcd) {
- /* Other STN panel support is up to 12MHz */
- var->pixclock = KHZ2PICOS(12000);
- }
- }
-#endif
- /* Set bitfield accordingly */
- switch (var->bits_per_pixel) {
- case 16:
- {
- /* 16bpp True color.
- * These must be set to MATCH WINCTRL[FORM] */
- int idx;
- idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
- var->red = rgb_bitfields[idx][0];
- var->green = rgb_bitfields[idx][1];
- var->blue = rgb_bitfields[idx][2];
- var->transp = rgb_bitfields[idx][3];
- break;
- }
-
- case 32:
- {
- /* 32bpp True color.
- * These must be set to MATCH WINCTRL[FORM] */
- int idx;
- idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
- var->red = rgb_bitfields[idx][0];
- var->green = rgb_bitfields[idx][1];
- var->blue = rgb_bitfields[idx][2];
- var->transp = rgb_bitfields[idx][3];
- break;
- }
- default:
- print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* fb_set_par
- * Set hardware with var settings. This will enable the controller with a
- * specific mode, normally validated with the fb_check_var method
- */
-static int au1200fb_fb_set_par(struct fb_info *fbi)
-{
- struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
-
- au1200fb_update_fbinfo(fbi);
- au1200_setmode(fbdev);
-
- return 0;
-}
-
-/* fb_setcolreg
- * Set color in LCD palette.
- */
-static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *fbi)
-{
- volatile u32 *palette = lcd->palette;
- u32 value;
-
- if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
- return -EINVAL;
-
- if (fbi->var.grayscale) {
- /* Convert color to grayscale */
- red = green = blue =
- (19595 * red + 38470 * green + 7471 * blue) >> 16;
- }
-
- if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
- /* Place color in the pseudopalette */
- if (regno > 16)
- return -EINVAL;
-
- palette = (u32*) fbi->pseudo_palette;
-
- red >>= (16 - fbi->var.red.length);
- green >>= (16 - fbi->var.green.length);
- blue >>= (16 - fbi->var.blue.length);
-
- value = (red << fbi->var.red.offset) |
- (green << fbi->var.green.offset)|
- (blue << fbi->var.blue.offset);
- value &= 0xFFFF;
-
- } else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
- /* COLOR TFT PALLETTIZED (use RGB 565) */
- value = (red & 0xF800)|((green >> 5) &
- 0x07E0)|((blue >> 11) & 0x001F);
- value &= 0xFFFF;
-
- } else if (0 /*panel_is_color(fbdev->panel)*/) {
- /* COLOR STN MODE */
- value = 0x1234;
- value &= 0xFFF;
- } else {
- /* MONOCHROME MODE */
- value = (green >> 12) & 0x000F;
- value &= 0xF;
- }
-
- palette[regno] = value;
-
- return 0;
-}
-
-/* fb_blank
- * Blank the screen. Depending on the mode, the screen will be
- * activated with the backlight color, or desactivated
- */
-static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
-{
- /* Short-circuit screen blanking */
- if (noblanking)
- return 0;
-
- switch (blank_mode) {
-
- case FB_BLANK_UNBLANK:
- case FB_BLANK_NORMAL:
- /* printk("turn on panel\n"); */
- au1200_setpanel(panel);
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- case FB_BLANK_POWERDOWN:
- /* printk("turn off panel\n"); */
- au1200_setpanel(NULL);
- break;
- default:
- break;
-
- }
-
- /* FB_BLANK_NORMAL is a soft blank */
- return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
-}
-
-/* fb_mmap
- * Map video memory in user space. We don't use the generic fb_mmap
- * method mainly to allow the use of the TLB streaming flag (CCA=6)
- */
-static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-
-{
- unsigned int len;
- unsigned long start=0, off;
- struct au1200fb_device *fbdev = (struct au1200fb_device *) info;
-
-#ifdef CONFIG_PM
- au1xxx_pm_access(LCD_pm_dev);
-#endif
-
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
- return -EINVAL;
- }
-
- start = fbdev->fb_phys & PAGE_MASK;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
-
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- if ((vma->vm_end - vma->vm_start + off) > len) {
- return -EINVAL;
- }
-
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
-
- vma->vm_flags |= VM_IO;
-
- return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-
- return 0;
-}
-
-static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
-{
-
- unsigned int hi1, divider;
-
- /* SCREEN_SIZE: user cannot reset size, must switch panel choice */
-
- if (pdata->flags & SCREEN_BACKCOLOR)
- lcd->backcolor = pdata->backcolor;
-
- if (pdata->flags & SCREEN_BRIGHTNESS) {
-
- // limit brightness pwm duty to >= 30/1600
- if (pdata->brightness < 30) {
- pdata->brightness = 30;
- }
- divider = (lcd->pwmdiv & 0x3FFFF) + 1;
- hi1 = (lcd->pwmhi >> 16) + 1;
- hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
- lcd->pwmhi &= 0xFFFF;
- lcd->pwmhi |= (hi1 << 16);
- }
-
- if (pdata->flags & SCREEN_COLORKEY)
- lcd->colorkey = pdata->colorkey;
-
- if (pdata->flags & SCREEN_MASK)
- lcd->colorkeymsk = pdata->mask;
- au_sync();
-}
-
-static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
-{
- unsigned int hi1, divider;
-
- pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
- pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
-
- pdata->backcolor = lcd->backcolor;
- pdata->colorkey = lcd->colorkey;
- pdata->mask = lcd->colorkeymsk;
-
- // brightness
- hi1 = (lcd->pwmhi >> 16) + 1;
- divider = (lcd->pwmdiv & 0x3FFFF) + 1;
- pdata->brightness = ((hi1 << 8) / divider) - 1;
- au_sync();
-}
-
-static void set_window(unsigned int plane,
- struct au1200_lcd_window_regs_t *pdata)
-{
- unsigned int val, bpp;
-
- /* Window control register 0 */
- if (pdata->flags & WIN_POSITION) {
- val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
- LCD_WINCTRL0_OY);
- val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
- val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
- lcd->window[plane].winctrl0 = val;
- }
- if (pdata->flags & WIN_ALPHA_COLOR) {
- val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
- val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
- lcd->window[plane].winctrl0 = val;
- }
- if (pdata->flags & WIN_ALPHA_MODE) {
- val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
- val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
- lcd->window[plane].winctrl0 = val;
- }
-
- /* Window control register 1 */
- if (pdata->flags & WIN_PRIORITY) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
- val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
- lcd->window[plane].winctrl1 = val;
- }
- if (pdata->flags & WIN_CHANNEL) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
- val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
- lcd->window[plane].winctrl1 = val;
- }
- if (pdata->flags & WIN_BUFFER_FORMAT) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
- val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
- lcd->window[plane].winctrl1 = val;
- }
- if (pdata->flags & WIN_COLOR_ORDER) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
- val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
- lcd->window[plane].winctrl1 = val;
- }
- if (pdata->flags & WIN_PIXEL_ORDER) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
- val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
- lcd->window[plane].winctrl1 = val;
- }
- if (pdata->flags & WIN_SIZE) {
- val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
- LCD_WINCTRL1_SZY);
- val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
- val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
- lcd->window[plane].winctrl1 = val;
- /* program buffer line width */
- bpp = winbpp(val) / 8;
- val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
- val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
- lcd->window[plane].winctrl2 = val;
- }
-
- /* Window control register 2 */
- if (pdata->flags & WIN_COLORKEY_MODE) {
- val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
- val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
- lcd->window[plane].winctrl2 = val;
- }
- if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
- val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
- val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
- lcd->window[plane].winctrl2 = val;
- }
- if (pdata->flags & WIN_RAM_ARRAY_MODE) {
- val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
- val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
- lcd->window[plane].winctrl2 = val;
- }
-
- /* Buffer line width programmed with WIN_SIZE */
-
- if (pdata->flags & WIN_BUFFER_SCALE) {
- val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
- LCD_WINCTRL2_SCY);
- val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
- val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
- lcd->window[plane].winctrl2 = val;
- }
-
- if (pdata->flags & WIN_ENABLE) {
- val = lcd->winenable;
- val &= ~(1<<plane);
- val |= (pdata->enable & 1) << plane;
- lcd->winenable = val;
- }
- au_sync();
-}
-
-static void get_window(unsigned int plane,
- struct au1200_lcd_window_regs_t *pdata)
-{
- /* Window control register 0 */
- pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
- pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
- pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
- pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
-
- /* Window control register 1 */
- pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
- pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
- pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
- pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
- pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
- pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
- pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
-
- /* Window control register 2 */
- pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
- pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
- pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
-
- pdata->enable = (lcd->winenable >> plane) & 1;
- au_sync();
-}
-
-static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
-{
- int plane;
- int val;
-
-#ifdef CONFIG_PM
- au1xxx_pm_access(LCD_pm_dev);
-#endif
-
- plane = fbinfo2index(info);
- print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
-
- if (cmd == AU1200_LCD_FB_IOCTL) {
- struct au1200_lcd_iodata_t iodata;
-
- if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
- return -EFAULT;
-
- print_dbg("FB IOCTL called\n");
-
- switch (iodata.subcmd) {
- case AU1200_LCD_SET_SCREEN:
- print_dbg("AU1200_LCD_SET_SCREEN\n");
- set_global(cmd, &iodata.global);
- break;
-
- case AU1200_LCD_GET_SCREEN:
- print_dbg("AU1200_LCD_GET_SCREEN\n");
- get_global(cmd, &iodata.global);
- break;
-
- case AU1200_LCD_SET_WINDOW:
- print_dbg("AU1200_LCD_SET_WINDOW\n");
- set_window(plane, &iodata.window);
- break;
-
- case AU1200_LCD_GET_WINDOW:
- print_dbg("AU1200_LCD_GET_WINDOW\n");
- get_window(plane, &iodata.window);
- break;
-
- case AU1200_LCD_SET_PANEL:
- print_dbg("AU1200_LCD_SET_PANEL\n");
- if ((iodata.global.panel_choice >= 0) &&
- (iodata.global.panel_choice <
- NUM_PANELS))
- {
- struct panel_settings *newpanel;
- panel_index = iodata.global.panel_choice;
- newpanel = &known_lcd_panels[panel_index];
- au1200_setpanel(newpanel);
- }
- break;
-
- case AU1200_LCD_GET_PANEL:
- print_dbg("AU1200_LCD_GET_PANEL\n");
- iodata.global.panel_choice = panel_index;
- break;
-
- default:
- return -EINVAL;
- }
-
- val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
- if (val) {
- print_dbg("error: could not copy %d bytes\n", val);
- return -EFAULT;
- }
- }
-
- return 0;
-}
-
-
-static struct fb_ops au1200fb_fb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = au1200fb_fb_check_var,
- .fb_set_par = au1200fb_fb_set_par,
- .fb_setcolreg = au1200fb_fb_setcolreg,
- .fb_blank = au1200fb_fb_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
- .fb_sync = NULL,
- .fb_ioctl = au1200fb_ioctl,
- .fb_mmap = au1200fb_fb_mmap,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
-{
- /* Nothing to do for now, just clear any pending interrupt */
- lcd->intstatus = lcd->intstatus;
- au_sync();
-
- return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* AU1200 LCD device probe helpers */
-
-static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
-{
- struct fb_info *fbi = &fbdev->fb_info;
- int bpp;
-
- memset(fbi, 0, sizeof(struct fb_info));
- fbi->fbops = &au1200fb_fb_ops;
-
- bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
-
- /* Copy monitor specs from panel data */
- /* fixme: we're setting up LCD controller windows, so these dont give a
- damn as to what the monitor specs are (the panel itself does, but that
- isnt done here...so maybe need a generic catchall monitor setting??? */
- memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
-
- /* We first try the user mode passed in argument. If that failed,
- * or if no one has been specified, we default to the first mode of the
- * panel list. Note that after this call, var data will be set */
- if (!fb_find_mode(&fbi->var,
- fbi,
- NULL, /* drv_info.opt_mode, */
- fbi->monspecs.modedb,
- fbi->monspecs.modedb_len,
- fbi->monspecs.modedb,
- bpp)) {
-
- print_err("Cannot find valid mode for panel %s", panel->name);
- return -EFAULT;
- }
-
- fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
- if (!fbi->pseudo_palette) {
- return -ENOMEM;
- }
- memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
-
- if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
- print_err("Fail to allocate colormap (%d entries)",
- AU1200_LCD_NBR_PALETTE_ENTRIES);
- kfree(fbi->pseudo_palette);
- return -EFAULT;
- }
-
- strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
- fbi->fix.smem_start = fbdev->fb_phys;
- fbi->fix.smem_len = fbdev->fb_len;
- fbi->fix.type = FB_TYPE_PACKED_PIXELS;
- fbi->fix.xpanstep = 0;
- fbi->fix.ypanstep = 0;
- fbi->fix.mmio_start = 0;
- fbi->fix.mmio_len = 0;
- fbi->fix.accel = FB_ACCEL_NONE;
-
- fbi->screen_base = (char __iomem *) fbdev->fb_mem;
-
- au1200fb_update_fbinfo(fbi);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* AU1200 LCD controller device driver */
-
-static int au1200fb_drv_probe(struct device *dev)
-{
- struct au1200fb_device *fbdev;
- unsigned long page;
- int bpp, plane, ret;
-
- if (!dev)
- return -EINVAL;
-
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
- bpp = winbpp(win->w[plane].mode_winctrl1);
- if (win->w[plane].xres == 0)
- win->w[plane].xres = panel->Xres;
- if (win->w[plane].yres == 0)
- win->w[plane].yres = panel->Yres;
-
- fbdev = &_au1200fb_devices[plane];
- memset(fbdev, 0, sizeof(struct au1200fb_device));
- fbdev->plane = plane;
-
- /* Allocate the framebuffer to the maximum screen size */
- fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
-
- fbdev->fb_mem = dma_alloc_noncoherent(dev,
- PAGE_ALIGN(fbdev->fb_len),
- &fbdev->fb_phys, GFP_KERNEL);
- if (!fbdev->fb_mem) {
- print_err("fail to allocate frambuffer (size: %dK))",
- fbdev->fb_len / 1024);
- return -ENOMEM;
- }
-
- /*
- * Set page reserved so that mmap will work. This is necessary
- * since we'll be remapping normal memory.
- */
- for (page = (unsigned long)fbdev->fb_phys;
- page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
- fbdev->fb_len);
- page += PAGE_SIZE) {
- SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
- }
- print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
- print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
-
- /* Init FB data */
- if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
- goto failed;
-
- /* Register new framebuffer */
- if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
- print_err("cannot register new framebuffer");
- goto failed;
- }
-
- au1200fb_fb_set_par(&fbdev->fb_info);
-
-#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
- if (plane == 0)
- if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
- /* Start display and show logo on boot */
- fb_set_cmap(&fbdev->fb_info.cmap,
- &fbdev->fb_info);
-
- fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
- }
-#endif
- }
-
- /* Now hook interrupt too */
- if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
- SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
- print_err("fail to request interrupt line %d (err: %d)",
- AU1200_LCD_INT, ret);
- goto failed;
- }
-
- return 0;
-
-failed:
- /* NOTE: This only does the current plane/window that failed; others are still active */
- if (fbdev->fb_mem)
- dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
- fbdev->fb_mem, fbdev->fb_phys);
- if (fbdev->fb_info.cmap.len != 0)
- fb_dealloc_cmap(&fbdev->fb_info.cmap);
- if (fbdev->fb_info.pseudo_palette)
- kfree(fbdev->fb_info.pseudo_palette);
- if (plane == 0)
- free_irq(AU1200_LCD_INT, (void*)dev);
- return ret;
-}
-
-static int au1200fb_drv_remove(struct device *dev)
-{
- struct au1200fb_device *fbdev;
- int plane;
-
- if (!dev)
- return -ENODEV;
-
- /* Turn off the panel */
- au1200_setpanel(NULL);
-
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
- {
- fbdev = &_au1200fb_devices[plane];
-
- /* Clean up all probe data */
- unregister_framebuffer(&fbdev->fb_info);
- if (fbdev->fb_mem)
- dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len),
- fbdev->fb_mem, fbdev->fb_phys);
- if (fbdev->fb_info.cmap.len != 0)
- fb_dealloc_cmap(&fbdev->fb_info.cmap);
- if (fbdev->fb_info.pseudo_palette)
- kfree(fbdev->fb_info.pseudo_palette);
- }
-
- free_irq(AU1200_LCD_INT, (void *)dev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
-{
- /* TODO */
- return 0;
-}
-
-static int au1200fb_drv_resume(struct device *dev, u32 level)
-{
- /* TODO */
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct device_driver au1200fb_driver = {
- .name = "au1200-lcd",
- .bus = &platform_bus_type,
- .probe = au1200fb_drv_probe,
- .remove = au1200fb_drv_remove,
-#ifdef CONFIG_PM
- .suspend = au1200fb_drv_suspend,
- .resume = au1200fb_drv_resume,
-#endif
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Kernel driver */
-
-static void au1200fb_setup(void)
-{
- char* options = NULL;
- char* this_opt;
- int num_panels = ARRAY_SIZE(known_lcd_panels);
- int panel_idx = -1;
-
- fb_get_options(DRIVER_NAME, &options);
-
- if (options) {
- while ((this_opt = strsep(&options,",")) != NULL) {
- /* Panel option - can be panel name,
- * "bs" for board-switch, or number/index */
- if (!strncmp(this_opt, "panel:", 6)) {
- int i;
- long int li;
- char *endptr;
- this_opt += 6;
- /* First check for index, which allows
- * to short circuit this mess */
- li = simple_strtol(this_opt, &endptr, 0);
- if (*endptr == '\0') {
- panel_idx = (int)li;
- }
- else if (strcmp(this_opt, "bs") == 0) {
- extern int board_au1200fb_panel(void);
- panel_idx = board_au1200fb_panel();
- }
-
- else
- for (i = 0; i < num_panels; i++) {
- if (!strcmp(this_opt, known_lcd_panels[i].name)) {
- panel_idx = i;
- break;
- }
- }
-
- if ((panel_idx < 0) || (panel_idx >= num_panels)) {
- print_warn("Panel %s not supported!", this_opt);
- }
- else
- panel_index = panel_idx;
- }
-
- else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
- nohwcursor = 1;
- }
-
- /* Unsupported option */
- else {
- print_warn("Unsupported option \"%s\"", this_opt);
- }
- }
- }
-}
-
-#ifdef CONFIG_PM
-static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
- au1xxx_request_t request, void *data) {
- int retval = -1;
- unsigned int d = 0;
- unsigned int brightness = 0;
-
- if (request == AU1XXX_PM_SLEEP) {
- board_au1200fb_panel_shutdown();
- }
- else if (request == AU1XXX_PM_WAKEUP) {
- if(dev->prev_state == SLEEP_STATE)
- {
- int plane;
- au1200_setpanel(panel);
- for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
- struct au1200fb_device *fbdev;
- fbdev = &_au1200fb_devices[plane];
- au1200fb_fb_set_par(&fbdev->fb_info);
- }
- }
-
- d = *((unsigned int*)data);
- if(d <=10) brightness = 26;
- else if(d<=20) brightness = 51;
- else if(d<=30) brightness = 77;
- else if(d<=40) brightness = 102;
- else if(d<=50) brightness = 128;
- else if(d<=60) brightness = 153;
- else if(d<=70) brightness = 179;
- else if(d<=80) brightness = 204;
- else if(d<=90) brightness = 230;
- else brightness = 255;
- set_brightness(brightness);
- } else if (request == AU1XXX_PM_GETSTATUS) {
- return dev->cur_state;
- } else if (request == AU1XXX_PM_ACCESS) {
- if (dev->cur_state != SLEEP_STATE)
- return retval;
- else {
- au1200_setpanel(panel);
- }
- } else if (request == AU1XXX_PM_IDLE) {
- } else if (request == AU1XXX_PM_CLEANUP) {
- }
-
- return retval;
-}
-#endif
-
-static int __init au1200fb_init(void)
-{
- print_info("" DRIVER_DESC "");
-
- /* Setup driver with options */
- au1200fb_setup();
-
- /* Point to the panel selected */
- panel = &known_lcd_panels[panel_index];
- win = &windows[window_index];
-
- printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
- printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
-
- /* Kickstart the panel, the framebuffers/windows come soon enough */
- au1200_setpanel(panel);
-
- #ifdef CONFIG_PM
- LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
- if ( LCD_pm_dev == NULL)
- printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
- else
- printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
- #endif
-
- return driver_register(&au1200fb_driver);
-}
-
-static void __exit au1200fb_cleanup(void)
-{
- driver_unregister(&au1200fb_driver);
-}
-
-module_init(au1200fb_init);
-module_exit(au1200fb_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 334b1db1bd7c..27597c576eff 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -29,12 +29,15 @@ static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
{
- int rc = -ENXIO, power;
+ int rc = -ENXIO;
char *endp;
struct backlight_device *bd = to_backlight_device(cdev);
+ int power = simple_strtoul(buf, &endp, 0);
+ size_t size = endp - buf;
- power = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
return -EINVAL;
down(&bd->sem);
@@ -65,12 +68,15 @@ static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
{
- int rc = -ENXIO, brightness;
+ int rc = -ENXIO;
char *endp;
struct backlight_device *bd = to_backlight_device(cdev);
+ int brightness = simple_strtoul(buf, &endp, 0);
+ size_t size = endp - buf;
- brightness = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
return -EINVAL;
down(&bd->sem);
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 86908a60c630..bc8ab005a3fb 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -31,12 +31,15 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
{
- int rc, power;
+ int rc = -ENXIO;
char *endp;
struct lcd_device *ld = to_lcd_device(cdev);
+ int power = simple_strtoul(buf, &endp, 0);
+ size_t size = endp - buf;
- power = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
return -EINVAL;
down(&ld->sem);
@@ -44,8 +47,7 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
pr_debug("lcd: set power to %d\n", power);
ld->props->set_power(ld, power);
rc = count;
- } else
- rc = -ENXIO;
+ }
up(&ld->sem);
return rc;
@@ -53,14 +55,12 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
{
- int rc;
+ int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
down(&ld->sem);
if (likely(ld->props && ld->props->get_contrast))
rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld));
- else
- rc = -ENXIO;
up(&ld->sem);
return rc;
@@ -68,12 +68,15 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
{
- int rc, contrast;
+ int rc = -ENXIO;
char *endp;
struct lcd_device *ld = to_lcd_device(cdev);
+ int contrast = simple_strtoul(buf, &endp, 0);
+ size_t size = endp - buf;
- contrast = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
return -EINVAL;
down(&ld->sem);
@@ -81,8 +84,7 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
pr_debug("lcd: set contrast to %d\n", contrast);
ld->props->set_contrast(ld, contrast);
rc = count;
- } else
- rc = -ENXIO;
+ }
up(&ld->sem);
return rc;
@@ -90,14 +92,12 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
{
- int rc;
+ int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
down(&ld->sem);
if (likely(ld->props))
rc = sprintf(buf, "%d\n", ld->props->max_contrast);
- else
- rc = -ENXIO;
up(&ld->sem);
return rc;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index ca020719d20b..47ba1a79adcd 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1745,7 +1745,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
fbcon_redraw_move(vc, p, 0, t, count);
ypan_up_redraw(vc, t, count);
if (vc->vc_rows - b > 0)
- fbcon_redraw_move(vc, p, b - count,
+ fbcon_redraw_move(vc, p, b,
vc->vc_rows - b, b);
} else
fbcon_redraw_move(vc, p, t + count, b - t - count, t);
@@ -2631,7 +2631,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
scr_memcpyw((u16 *) q, (u16 *) p,
vc->vc_size_row);
}
- softback_in = p;
+ softback_in = softback_curr = p;
update_region(vc, vc->vc_origin,
logo_lines * vc->vc_cols);
}
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index b72b05250a9d..34e07399756b 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -305,94 +305,6 @@ static ssize_t show_stride(struct class_device *class_device, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length);
}
-/* Format for cmap is "%02x%c%4x%4x%4x\n" */
-/* %02x entry %c transp %4x red %4x blue %4x green \n */
-/* 256 rows at 16 chars equals 4096, the normal page size */
-/* the code will automatically adjust for different page sizes */
-static ssize_t store_cmap(struct class_device *class_device, const char *buf,
- size_t count)
-{
- struct fb_info *fb_info = class_get_devdata(class_device);
- int rc, i, start, length, transp = 0;
-
- if ((count > PAGE_SIZE) || ((count % 16) != 0))
- return -EINVAL;
-
- if (!fb_info->fbops->fb_setcolreg && !fb_info->fbops->fb_setcmap)
- return -EINVAL;
-
- sscanf(buf, "%02x", &start);
- length = count / 16;
-
- for (i = 0; i < length; i++)
- if (buf[i * 16 + 2] != ' ')
- transp = 1;
-
- /* If we can batch, do it */
- if (fb_info->fbops->fb_setcmap && length > 1) {
- struct fb_cmap umap;
-
- memset(&umap, 0, sizeof(umap));
- if ((rc = fb_alloc_cmap(&umap, length, transp)))
- return rc;
-
- umap.start = start;
- for (i = 0; i < length; i++) {
- sscanf(&buf[i * 16 + 3], "%4hx", &umap.red[i]);
- sscanf(&buf[i * 16 + 7], "%4hx", &umap.blue[i]);
- sscanf(&buf[i * 16 + 11], "%4hx", &umap.green[i]);
- if (transp)
- umap.transp[i] = (buf[i * 16 + 2] != ' ');
- }
- rc = fb_info->fbops->fb_setcmap(&umap, fb_info);
- fb_copy_cmap(&umap, &fb_info->cmap);
- fb_dealloc_cmap(&umap);
-
- return rc ?: count;
- }
- for (i = 0; i < length; i++) {
- u16 red, blue, green, tsp;
-
- sscanf(&buf[i * 16 + 3], "%4hx", &red);
- sscanf(&buf[i * 16 + 7], "%4hx", &blue);
- sscanf(&buf[i * 16 + 11], "%4hx", &green);
- tsp = (buf[i * 16 + 2] != ' ');
- if ((rc = fb_info->fbops->fb_setcolreg(start++,
- red, green, blue, tsp, fb_info)))
- return rc;
-
- fb_info->cmap.red[i] = red;
- fb_info->cmap.blue[i] = blue;
- fb_info->cmap.green[i] = green;
- if (transp)
- fb_info->cmap.transp[i] = tsp;
- }
- return count;
-}
-
-static ssize_t show_cmap(struct class_device *class_device, char *buf)
-{
- struct fb_info *fb_info = class_get_devdata(class_device);
- unsigned int i;
-
- if (!fb_info->cmap.red || !fb_info->cmap.blue ||
- !fb_info->cmap.green)
- return -EINVAL;
-
- if (fb_info->cmap.len > PAGE_SIZE / 16)
- return -EINVAL;
-
- /* don't mess with the format, the buffer is PAGE_SIZE */
- /* 256 entries at 16 chars per line equals 4096 = PAGE_SIZE */
- for (i = 0; i < fb_info->cmap.len; i++) {
- snprintf(&buf[ i * 16], PAGE_SIZE - i * 16, "%02x%c%4x%4x%4x\n", i + fb_info->cmap.start,
- ((fb_info->cmap.transp && fb_info->cmap.transp[i]) ? '*' : ' '),
- fb_info->cmap.red[i], fb_info->cmap.blue[i],
- fb_info->cmap.green[i]);
- }
- return 16 * fb_info->cmap.len;
-}
-
static ssize_t store_blank(struct class_device *class_device, const char * buf,
size_t count)
{
@@ -502,10 +414,12 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
}
+/* When cmap is added back in it should be a binary attribute
+ * not a text one. Consideration should also be given to converting
+ * fbdev to use configfs instead of sysfs */
static struct class_device_attribute class_device_attrs[] = {
__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
- __ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 788297e9d59e..44aa2ffff973 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -76,8 +76,8 @@
*
* Experiment with v_offset to find out which works best for you.
*/
-static u32 v_offset_default __initdata; /* For 32 MiB Aper size, 8 should be the default */
-static u32 voffset __initdata = 0;
+static u32 v_offset_default __devinitdata; /* For 32 MiB Aper size, 8 should be the default */
+static u32 voffset __devinitdata;
static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
static int __devinit i810fb_init_pci (struct pci_dev *dev,
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index da29d007f215..469b06c29180 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -8,9 +8,9 @@
/*** Version/name ***/
-#define INTELFB_VERSION "0.9.2"
+#define INTELFB_VERSION "0.9.4"
#define INTELFB_MODULE_NAME "intelfb"
-#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM"
+#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM"
/*** Debug/feature defines ***/
@@ -52,11 +52,14 @@
#define PCI_DEVICE_ID_INTEL_865G 0x2572
#define PCI_DEVICE_ID_INTEL_915G 0x2582
#define PCI_DEVICE_ID_INTEL_915GM 0x2592
+#define PCI_DEVICE_ID_INTEL_945G 0x2772
+#define PCI_DEVICE_ID_INTEL_945GM 0x27A2
/* Size of MMIO region */
#define INTEL_REG_SIZE 0x80000
#define STRIDE_ALIGNMENT 16
+#define STRIDE_ALIGNMENT_I9XX 64
#define PALETTE_8_ENTRIES 256
@@ -125,7 +128,9 @@ enum intel_chips {
INTEL_855GME,
INTEL_865G,
INTEL_915G,
- INTEL_915GM
+ INTEL_915GM,
+ INTEL_945G,
+ INTEL_945GM,
};
struct intelfb_hwstate {
@@ -277,8 +282,13 @@ struct intelfb_info {
/* driver registered */
int registered;
+
+ /* index into plls */
+ int pll_index;
};
+#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+
/*** function prototypes ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 995b47c165a7..076fa56be192 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1,11 +1,12 @@
/*
* intelfb
*
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM
- * integrated graphics chips.
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
+ * 945G/945GM integrated graphics chips.
*
* Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
+ * 2006 David Airlie
*
* This driver consists of two parts. The first part (intelfbdrv.c) provides
* the basic fbdev interfaces, is derived in part from the radeonfb and
@@ -131,6 +132,7 @@
#include "intelfb.h"
#include "intelfbhw.h"
+#include "../edid.h"
static void __devinit get_initial_mode(struct intelfb_info *dinfo);
static void update_dinfo(struct intelfb_info *dinfo,
@@ -182,6 +184,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
{ 0, }
};
@@ -261,7 +265,7 @@ MODULE_PARM_DESC(mode,
#ifndef MODULE
#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
-#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)
+#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0)
#define OPT_STRVAL(opt, name) (opt + strlen(name))
static __inline__ char *
@@ -546,11 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Set base addresses. */
if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
- (ent->device == PCI_DEVICE_ID_INTEL_915GM)) {
+ (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
+ (ent->device == PCI_DEVICE_ID_INTEL_945G) ||
+ (ent->device == PCI_DEVICE_ID_INTEL_945GM)) {
aperture_bar = 2;
mmio_bar = 0;
- /* Disable HW cursor on 915G/M (not implemented yet) */
- hwcursor = 0;
}
dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
dinfo->aperture.size = pci_resource_len(pdev, aperture_bar);
@@ -584,8 +588,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get the chipset info. */
dinfo->pci_chipset = pdev->device;
- if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
- &dinfo->mobile)) {
+ if (intelfbhw_get_chipset(pdev, dinfo)) {
cleanup(dinfo);
return -ENODEV;
}
@@ -1029,17 +1032,44 @@ intelfb_init_var(struct intelfb_info *dinfo)
sizeof(struct fb_var_screeninfo));
msrc = 5;
} else {
+ const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev);
+ u8 *edid_d = NULL;
+
+ if (edid_s) {
+ edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
+
+ if (edid_d) {
+ memcpy(edid_d, edid_s, EDID_LENGTH);
+ fb_edid_to_monspecs(edid_d,
+ &dinfo->info->monspecs);
+ kfree(edid_d);
+ }
+ }
+
if (mode) {
+ printk("intelfb: Looking for mode in private "
+ "database\n");
msrc = fb_find_mode(var, dinfo->info, mode,
- vesa_modes, VESA_MODEDB_SIZE,
+ dinfo->info->monspecs.modedb,
+ dinfo->info->monspecs.modedb_len,
NULL, 0);
- if (msrc)
- msrc |= 8;
+
+ if (msrc && msrc > 1) {
+ printk("intelfb: No mode in private database, "
+ "intelfb: looking for mode in global "
+ "database ");
+ msrc = fb_find_mode(var, dinfo->info, mode,
+ NULL, 0, NULL, 0);
+
+ if (msrc)
+ msrc |= 8;
+ }
+
}
+
if (!msrc) {
msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
- vesa_modes, VESA_MODEDB_SIZE,
- NULL, 0);
+ NULL, 0, NULL, 0);
}
}
@@ -1139,7 +1169,10 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
}
/* Make sure the line length is a aligned correctly. */
- dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
+ if (IS_I9XX(dinfo))
+ dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX);
+ else
+ dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
if (FIXED_MODE(dinfo))
dinfo->pitch = dinfo->initial_pitch;
@@ -1162,16 +1195,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
struct fb_var_screeninfo v;
struct intelfb_info *dinfo;
static int first = 1;
+ int i;
+ /* Good pitches to allow tiling. Don't care about pitches < 1024. */
+ static const int pitches[] = {
+ 128 * 8,
+ 128 * 16,
+ 128 * 32,
+ 128 * 64,
+ 0
+ };
DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
dinfo = GET_DINFO(info);
+ /* update the pitch */
if (intelfbhw_validate_mode(dinfo, var) != 0)
return -EINVAL;
v = *var;
+ for (i = 0; pitches[i] != 0; i++) {
+ if (pitches[i] >= v.xres_virtual) {
+ v.xres_virtual = pitches[i];
+ break;
+ }
+ }
+
/* Check for a supported bpp. */
if (v.bits_per_pixel <= 8) {
v.bits_per_pixel = 8;
@@ -1467,7 +1517,7 @@ static int
intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct intelfb_info *dinfo = GET_DINFO(info);
-
+ u32 physical;
#if VERBOSE > 0
DBG_MSG("intelfb_cursor\n");
#endif
@@ -1478,7 +1528,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
intelfbhw_cursor_hide(dinfo);
/* If XFree killed the cursor - restore it */
- if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) {
+ physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical :
+ (dinfo->cursor.offset << 12);
+
+ if (INREG(CURSOR_A_BASEADDR) != physical) {
u32 fg, bg;
DBG_MSG("the cursor was killed - restore it !!\n");
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 624c4bc96f0d..426b7430b125 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -40,68 +40,110 @@
#include "intelfb.h"
#include "intelfbhw.h"
+struct pll_min_max {
+ int min_m, max_m, min_m1, max_m1;
+ int min_m2, max_m2, min_n, max_n;
+ int min_p, max_p, min_p1, max_p1;
+ int min_vco, max_vco, p_transition_clk, ref_clk;
+ int p_inc_lo, p_inc_hi;
+};
+
+#define PLLS_I8xx 0
+#define PLLS_I9xx 1
+#define PLLS_MAX 2
+
+static struct pll_min_max plls[PLLS_MAX] = {
+ { 108, 140, 18, 26,
+ 6, 16, 3, 16,
+ 4, 128, 0, 31,
+ 930000, 1400000, 165000, 48000,
+ 4, 2 }, //I8xx
+
+ { 75, 120, 10, 20,
+ 5, 9, 4, 7,
+ 5, 80, 1, 8,
+ 1400000, 2800000, 200000, 96000,
+ 10, 5 } //I9xx
+};
+
int
-intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
- int *mobile)
+intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
{
u32 tmp;
-
- if (!pdev || !name || !chipset || !mobile)
+ if (!pdev || !dinfo)
return 1;
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_830M:
- *name = "Intel(R) 830M";
- *chipset = INTEL_830M;
- *mobile = 1;
+ dinfo->name = "Intel(R) 830M";
+ dinfo->chipset = INTEL_830M;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_845G:
- *name = "Intel(R) 845G";
- *chipset = INTEL_845G;
- *mobile = 0;
+ dinfo->name = "Intel(R) 845G";
+ dinfo->chipset = INTEL_845G;
+ dinfo->mobile = 0;
+ dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_85XGM:
tmp = 0;
- *mobile = 1;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I8xx;
pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
INTEL_85X_VARIANT_MASK) {
case INTEL_VAR_855GME:
- *name = "Intel(R) 855GME";
- *chipset = INTEL_855GME;
+ dinfo->name = "Intel(R) 855GME";
+ dinfo->chipset = INTEL_855GME;
return 0;
case INTEL_VAR_855GM:
- *name = "Intel(R) 855GM";
- *chipset = INTEL_855GM;
+ dinfo->name = "Intel(R) 855GM";
+ dinfo->chipset = INTEL_855GM;
return 0;
case INTEL_VAR_852GME:
- *name = "Intel(R) 852GME";
- *chipset = INTEL_852GME;
+ dinfo->name = "Intel(R) 852GME";
+ dinfo->chipset = INTEL_852GME;
return 0;
case INTEL_VAR_852GM:
- *name = "Intel(R) 852GM";
- *chipset = INTEL_852GM;
+ dinfo->name = "Intel(R) 852GM";
+ dinfo->chipset = INTEL_852GM;
return 0;
default:
- *name = "Intel(R) 852GM/855GM";
- *chipset = INTEL_85XGM;
+ dinfo->name = "Intel(R) 852GM/855GM";
+ dinfo->chipset = INTEL_85XGM;
return 0;
}
break;
case PCI_DEVICE_ID_INTEL_865G:
- *name = "Intel(R) 865G";
- *chipset = INTEL_865G;
- *mobile = 0;
+ dinfo->name = "Intel(R) 865G";
+ dinfo->chipset = INTEL_865G;
+ dinfo->mobile = 0;
+ dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_915G:
- *name = "Intel(R) 915G";
- *chipset = INTEL_915G;
- *mobile = 0;
+ dinfo->name = "Intel(R) 915G";
+ dinfo->chipset = INTEL_915G;
+ dinfo->mobile = 0;
+ dinfo->pll_index = PLLS_I9xx;
return 0;
case PCI_DEVICE_ID_INTEL_915GM:
- *name = "Intel(R) 915GM";
- *chipset = INTEL_915GM;
- *mobile = 1;
+ dinfo->name = "Intel(R) 915GM";
+ dinfo->chipset = INTEL_915GM;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I9xx;
+ return 0;
+ case PCI_DEVICE_ID_INTEL_945G:
+ dinfo->name = "Intel(R) 945G";
+ dinfo->chipset = INTEL_945G;
+ dinfo->mobile = 0;
+ dinfo->pll_index = PLLS_I9xx;
+ return 0;
+ case PCI_DEVICE_ID_INTEL_945GM:
+ dinfo->name = "Intel(R) 945GM";
+ dinfo->chipset = INTEL_945GM;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I9xx;
return 0;
default:
return 1;
@@ -114,6 +156,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
{
struct pci_dev *bridge_dev;
u16 tmp;
+ int stolen_overhead;
if (!pdev || !aperture_size || !stolen_size)
return 1;
@@ -128,21 +171,41 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
tmp = 0;
pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
switch (pdev->device) {
- case PCI_DEVICE_ID_INTEL_830M:
- case PCI_DEVICE_ID_INTEL_845G:
+ case PCI_DEVICE_ID_INTEL_915G:
+ case PCI_DEVICE_ID_INTEL_915GM:
+ case PCI_DEVICE_ID_INTEL_945G:
+ case PCI_DEVICE_ID_INTEL_945GM:
+ /* 915 and 945 chipsets support a 256MB aperture.
+ Aperture size is determined by inspected the
+ base address of the aperture. */
+ if (pci_resource_start(pdev, 2) & 0x08000000)
+ *aperture_size = MB(128);
+ else
+ *aperture_size = MB(256);
+ break;
+ default:
if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
*aperture_size = MB(64);
else
*aperture_size = MB(128);
+ break;
+ }
+
+ /* Stolen memory size is reduced by the GTT and the popup.
+ GTT is 1K per MB of aperture size, and popup is 4K. */
+ stolen_overhead = (*aperture_size / MB(1)) + 4;
+ switch(pdev->device) {
+ case PCI_DEVICE_ID_INTEL_830M:
+ case PCI_DEVICE_ID_INTEL_845G:
switch (tmp & INTEL_830_GMCH_GMS_MASK) {
case INTEL_830_GMCH_GMS_STOLEN_512:
- *stolen_size = KB(512) - KB(132);
+ *stolen_size = KB(512) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_STOLEN_1024:
- *stolen_size = MB(1) - KB(132);
+ *stolen_size = MB(1) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_STOLEN_8192:
- *stolen_size = MB(8) - KB(132);
+ *stolen_size = MB(8) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_LOCAL:
ERR_MSG("only local memory found\n");
@@ -157,28 +220,27 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
}
break;
default:
- *aperture_size = MB(128);
switch (tmp & INTEL_855_GMCH_GMS_MASK) {
case INTEL_855_GMCH_GMS_STOLEN_1M:
- *stolen_size = MB(1) - KB(132);
+ *stolen_size = MB(1) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_4M:
- *stolen_size = MB(4) - KB(132);
+ *stolen_size = MB(4) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_8M:
- *stolen_size = MB(8) - KB(132);
+ *stolen_size = MB(8) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_16M:
- *stolen_size = MB(16) - KB(132);
+ *stolen_size = MB(16) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_32M:
- *stolen_size = MB(32) - KB(132);
+ *stolen_size = MB(32) - KB(stolen_overhead);
return 0;
case INTEL_915G_GMCH_GMS_STOLEN_48M:
- *stolen_size = MB(48) - KB(132);
+ *stolen_size = MB(48) - KB(stolen_overhead);
return 0;
case INTEL_915G_GMCH_GMS_STOLEN_64M:
- *stolen_size = MB(64) - KB(132);
+ *stolen_size = MB(64) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_DISABLED:
ERR_MSG("video memory is disabled\n");
@@ -529,12 +591,63 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
}
+static int calc_vclock3(int index, int m, int n, int p)
+{
+ if (p == 0 || n == 0)
+ return 0;
+ return plls[index].ref_clk * m / n / p;
+}
+
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
+{
+ struct pll_min_max *pll = &plls[index];
+ u32 m, vco, p;
+
+ m = (5 * (m1 + 2)) + (m2 + 2);
+ n += 2;
+ vco = pll->ref_clk * m / n;
+
+ if (index == PLLS_I8xx) {
+ p = ((p1 + 2) * (1 << (p2 + 1)));
+ } else {
+ p = ((p1) * (p2 ? 5 : 10));
+ }
+ return vco / p;
+}
+
+static void
+intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
+{
+ int p1, p2;
+
+ if (IS_I9XX(dinfo)) {
+ if (dpll & DPLL_P1_FORCE_DIV2)
+ p1 = 1;
+ else
+ p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
+
+ p1 = ffs(p1);
+
+ p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
+ } else {
+ if (dpll & DPLL_P1_FORCE_DIV2)
+ p1 = 0;
+ else
+ p1 = (dpll >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+ p2 = (dpll >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+ }
+
+ *o_p1 = p1;
+ *o_p2 = p2;
+}
+
+
void
intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
{
#if REGDUMP
int i, m1, m2, n, p1, p2;
-
+ int index = dinfo->pll_index;
DBG_MSG("intelfbhw_print_hw_state\n");
if (!hw || !dinfo)
@@ -547,26 +660,22 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
- p1 = 0;
- else
- p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
- p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+
+ intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
+
printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+ m1, m2, n, p1, p2);
+ printk(" VGA0: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
- p1 = 0;
- else
- p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
- p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
+
+ intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+ m1, m2, n, p1, p2);
+ printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
printk(" DPLL_A: 0x%08x\n", hw->dpll_a);
printk(" DPLL_B: 0x%08x\n", hw->dpll_b);
@@ -578,34 +687,30 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
- p1 = 0;
- else
- p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
- p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+
+ intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
+
printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+ m1, m2, n, p1, p2);
+ printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
- p1 = 0;
- else
- p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
- p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+
+ intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
+
printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+ m1, m2, n, p1, p2);
+ printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
#if 0
printk(" PALETTE_A:\n");
for (i = 0; i < PALETTE_8_ENTRIES)
- printk(" %3d: 0x%08x\n", i, hw->palette_a[i];
+ printk(" %3d: 0x%08x\n", i, hw->palette_a[i]);
printk(" PALETTE_B:\n");
for (i = 0; i < PALETTE_8_ENTRIES)
- printk(" %3d: 0x%08x\n", i, hw->palette_b[i];
+ printk(" %3d: 0x%08x\n", i, hw->palette_b[i]);
#endif
printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a);
@@ -680,11 +785,11 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
}
for (i = 0; i < 3; i++) {
printk(" SWF3%d 0x%08x\n", i,
- hw->swf3x[i]);
+ hw->swf3x[i]);
}
for (i = 0; i < 8; i++)
printk(" FENCE%d 0x%08x\n", i,
- hw->fence[i]);
+ hw->fence[i]);
printk(" INSTPM 0x%08x\n", hw->instpm);
printk(" MEM_MODE 0x%08x\n", hw->mem_mode);
@@ -695,43 +800,58 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
#endif
}
+
+
/* Split the M parameter into M1 and M2. */
static int
-splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
{
int m1, m2;
-
- m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
- if (m1 < MIN_M1)
- m1 = MIN_M1;
- if (m1 > MAX_M1)
- m1 = MAX_M1;
- m2 = m - 5 * (m1 + 2) - 2;
- if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
- return 1;
- } else {
- *retm1 = (unsigned int)m1;
- *retm2 = (unsigned int)m2;
- return 0;
+ int testm;
+ struct pll_min_max *pll = &plls[index];
+
+ /* no point optimising too much - brute force m */
+ for (m1 = pll->min_m1; m1 < pll->max_m1 + 1; m1++) {
+ for (m2 = pll->min_m2; m2 < pll->max_m2 + 1; m2++) {
+ testm = (5 * (m1 + 2)) + (m2 + 2);
+ if (testm == m) {
+ *retm1 = (unsigned int)m1;
+ *retm2 = (unsigned int)m2;
+ return 0;
+ }
+ }
}
+ return 1;
}
/* Split the P parameter into P1 and P2. */
static int
-splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
{
int p1, p2;
+ struct pll_min_max *pll = &plls[index];
+
+ if (index == PLLS_I9xx) {
+ p2 = (p % 10) ? 1 : 0;
+
+ p1 = p / (p2 ? 5 : 10);
+
+ *retp1 = (unsigned int)p1;
+ *retp2 = (unsigned int)p2;
+ return 0;
+ }
if (p % 4 == 0)
p2 = 1;
else
p2 = 0;
p1 = (p / (1 << (p2 + 1))) - 2;
- if (p % 4 == 0 && p1 < MIN_P1) {
+ if (p % 4 == 0 && p1 < pll->min_p1) {
p2 = 0;
p1 = (p / (1 << (p2 + 1))) - 2;
}
- if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+ if (p1 < pll->min_p1 || p1 > pll->max_p1 ||
+ (p1 + 2) * (1 << (p2 + 1)) != p) {
return 1;
} else {
*retp1 = (unsigned int)p1;
@@ -741,14 +861,15 @@ splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
}
static int
-calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
u32 *retp2, u32 *retclock)
{
- u32 m1, m2, n, p1, p2, n1;
- u32 f_vco, p, p_best = 0, m, f_out;
+ u32 m1, m2, n, p1, p2, n1, testm;
+ u32 f_vco, p, p_best = 0, m, f_out = 0;
u32 err_max, err_target, err_best = 10000000;
u32 n_best = 0, m_best = 0, f_best, f_err;
- u32 p_min, p_max, p_inc, div_min, div_max;
+ u32 p_min, p_max, p_inc, div_max;
+ struct pll_min_max *pll = &plls[index];
/* Accept 0.5% difference, but aim for 0.1% */
err_max = 5 * clock / 1000;
@@ -756,58 +877,56 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
DBG_MSG("Clock is %d\n", clock);
- div_max = MAX_VCO_FREQ / clock;
- div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+ div_max = pll->max_vco / clock;
- if (clock <= P_TRANSITION_CLOCK)
- p_inc = 4;
- else
- p_inc = 2;
- p_min = ROUND_UP_TO(div_min, p_inc);
+ p_inc = (clock <= pll->p_transition_clk) ? pll->p_inc_lo : pll->p_inc_hi;
+ p_min = p_inc;
p_max = ROUND_DOWN_TO(div_max, p_inc);
- if (p_min < MIN_P)
- p_min = 4;
- if (p_max > MAX_P)
- p_max = 128;
+ if (p_min < pll->min_p)
+ p_min = pll->min_p;
+ if (p_max > pll->max_p)
+ p_max = pll->max_p;
DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
p = p_min;
do {
- if (splitp(p, &p1, &p2)) {
+ if (splitp(index, p, &p1, &p2)) {
WRN_MSG("cannot split p = %d\n", p);
p += p_inc;
continue;
}
- n = MIN_N;
+ n = pll->min_n;
f_vco = clock * p;
do {
- m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
- if (m < MIN_M)
- m = MIN_M;
- if (m > MAX_M)
- m = MAX_M;
- f_out = CALC_VCLOCK3(m, n, p);
- if (splitm(m, &m1, &m2)) {
- WRN_MSG("cannot split m = %d\n", m);
- n++;
- continue;
- }
- if (clock > f_out)
- f_err = clock - f_out;
- else
- f_err = f_out - clock;
-
- if (f_err < err_best) {
- m_best = m;
- n_best = n;
- p_best = p;
- f_best = f_out;
- err_best = f_err;
+ m = ROUND_UP_TO(f_vco * n, pll->ref_clk) / pll->ref_clk;
+ if (m < pll->min_m)
+ m = pll->min_m + 1;
+ if (m > pll->max_m)
+ m = pll->max_m - 1;
+ for (testm = m - 1; testm <= m; testm++) {
+ f_out = calc_vclock3(index, m, n, p);
+ if (splitm(index, testm, &m1, &m2)) {
+ WRN_MSG("cannot split m = %d\n", m);
+ n++;
+ continue;
+ }
+ if (clock > f_out)
+ f_err = clock - f_out;
+ else/* slightly bias the error for bigger clocks */
+ f_err = f_out - clock + 1;
+
+ if (f_err < err_best) {
+ m_best = testm;
+ n_best = n;
+ p_best = p;
+ f_best = f_out;
+ err_best = f_err;
+ }
}
n++;
- } while ((n <= MAX_N) && (f_out >= clock));
+ } while ((n <= pll->max_n) && (f_out >= clock));
p += p_inc;
} while ((p <= p_max));
@@ -818,21 +937,22 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
m = m_best;
n = n_best;
p = p_best;
- splitm(m, &m1, &m2);
- splitp(p, &p1, &p2);
+ splitm(index, m, &m1, &m2);
+ splitp(index, p, &p1, &p2);
n1 = n - 2;
DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
"f: %d (%d), VCO: %d\n",
m, m1, m2, n, n1, p, p1, p2,
- CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
- CALC_VCLOCK3(m, n, p) * p);
+ calc_vclock3(index, m, n, p),
+ calc_vclock(index, m1, m2, n1, p1, p2, 0),
+ calc_vclock3(index, m, n, p) * p);
*retm1 = m1;
*retm2 = m2;
*retn = n1;
*retp1 = p1;
*retp2 = p2;
- *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+ *retclock = calc_vclock(index, m1, m2, n1, p1, p2, 0);
return 0;
}
@@ -860,6 +980,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
u32 vsync_pol, hsync_pol;
u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
+ u32 stride_alignment;
DBG_MSG("intelfbhw_mode_to_hw\n");
@@ -929,7 +1050,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
/* Desired clock in kHz */
clock_target = 1000000000 / var->pixclock;
- if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+ if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2,
+ &n, &p1, &p2, &clock)) {
WRN_MSG("calc_pll_params failed\n");
return 1;
}
@@ -949,7 +1071,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*dpll &= ~DPLL_P1_FORCE_DIV2;
*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
(DPLL_P1_MASK << DPLL_P1_SHIFT));
- *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+
+ if (IS_I9XX(dinfo)) {
+ *dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
+ *dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
+ } else {
+ *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+ }
+
*fp0 = (n << FP_N_DIVISOR_SHIFT) |
(m1 << FP_M1_DIVISOR_SHIFT) |
(m2 << FP_M2_DIVISOR_SHIFT);
@@ -1054,7 +1183,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
(vactive << SRC_SIZE_VERT_SHIFT);
- hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
+ hw->disp_a_stride = dinfo->pitch;
DBG_MSG("pitch is %d\n", hw->disp_a_stride);
hw->disp_a_base = hw->disp_a_stride * var->yoffset +
@@ -1063,9 +1192,11 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hw->disp_a_base += dinfo->fb.offset << 12;
/* Check stride alignment. */
- if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
+ stride_alignment = IS_I9XX(dinfo) ? STRIDE_ALIGNMENT_I9XX :
+ STRIDE_ALIGNMENT;
+ if (hw->disp_a_stride % stride_alignment != 0) {
WRN_MSG("display stride %d has bad alignment %d\n",
- hw->disp_a_stride, STRIDE_ALIGNMENT);
+ hw->disp_a_stride, stride_alignment);
return 1;
}
@@ -1087,6 +1218,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
u32 hsync_reg, htotal_reg, hblank_reg;
u32 vsync_reg, vtotal_reg, vblank_reg;
u32 src_size_reg;
+ u32 count, tmp_val[3];
/* Assume single pipe, display plane A, analog CRT. */
@@ -1155,6 +1287,27 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
src_size_reg = SRC_SIZE_A;
}
+ /* turn off pipe */
+ tmp = INREG(pipe_conf_reg);
+ tmp &= ~PIPECONF_ENABLE;
+ OUTREG(pipe_conf_reg, tmp);
+
+ count = 0;
+ do {
+ tmp_val[count%3] = INREG(0x70000);
+ if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+ break;
+ count++;
+ udelay(1);
+ if (count % 200 == 0) {
+ tmp = INREG(pipe_conf_reg);
+ tmp &= ~PIPECONF_ENABLE;
+ OUTREG(pipe_conf_reg, tmp);
+ }
+ } while(count < 2000);
+
+ OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
+
/* Disable planes A and B. */
tmp = INREG(DSPACNTR);
tmp &= ~DISPPLANE_PLANE_ENABLE;
@@ -1163,19 +1316,21 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
tmp &= ~DISPPLANE_PLANE_ENABLE;
OUTREG(DSPBCNTR, tmp);
- /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
+ /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
mdelay(20);
+ OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);
+ OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);
+ OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
+
/* Disable Sync */
tmp = INREG(ADPA);
tmp &= ~ADPA_DPMS_CONTROL_MASK;
tmp |= ADPA_DPMS_D3;
OUTREG(ADPA, tmp);
- /* turn off pipe */
- tmp = INREG(pipe_conf_reg);
- tmp &= ~PIPECONF_ENABLE;
- OUTREG(pipe_conf_reg, tmp);
+ /* do some funky magic - xyzzy */
+ OUTREG(0x61204, 0xabcd0000);
/* turn off PLL */
tmp = INREG(dpll_reg);
@@ -1183,30 +1338,31 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(dpll_reg, tmp);
/* Set PLL parameters */
- OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
OUTREG(fp0_reg, *fp0);
OUTREG(fp1_reg, *fp1);
- /* Set pipe parameters */
- OUTREG(hsync_reg, *hs);
- OUTREG(hblank_reg, *hb);
- OUTREG(htotal_reg, *ht);
- OUTREG(vsync_reg, *vs);
- OUTREG(vblank_reg, *vb);
- OUTREG(vtotal_reg, *vt);
- OUTREG(src_size_reg, *ss);
+ /* Enable PLL */
+ OUTREG(dpll_reg, *dpll);
/* Set DVOs B/C */
OUTREG(DVOB, hw->dvob);
OUTREG(DVOC, hw->dvoc);
+ /* undo funky magic */
+ OUTREG(0x61204, 0x00000000);
+
/* Set ADPA */
+ OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
- /* Enable PLL */
- tmp = INREG(dpll_reg);
- tmp |= DPLL_VCO_ENABLE;
- OUTREG(dpll_reg, tmp);
+ /* Set pipe parameters */
+ OUTREG(hsync_reg, *hs);
+ OUTREG(hblank_reg, *hb);
+ OUTREG(htotal_reg, *ht);
+ OUTREG(vsync_reg, *vs);
+ OUTREG(vblank_reg, *vb);
+ OUTREG(vtotal_reg, *vt);
+ OUTREG(src_size_reg, *ss);
/* Enable pipe */
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
@@ -1231,7 +1387,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(DSPACNTR,
hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
mdelay(1);
- }
+ }
}
OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
@@ -1616,7 +1772,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
DBG_MSG("intelfbhw_cursor_init\n");
#endif
- if (dinfo->mobile) {
+ if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@@ -1649,7 +1805,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
#endif
dinfo->cursor_on = 0;
- if (dinfo->mobile) {
+ if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@@ -1679,7 +1835,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
if (dinfo->cursor_blanked)
return;
- if (dinfo->mobile) {
+ if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@@ -1705,14 +1861,18 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
#endif
/*
- * Sets the position. The coordinates are assumed to already
- * have any offset adjusted. Assume that the cursor is never
+ * Sets the position. The coordinates are assumed to already
+ * have any offset adjusted. Assume that the cursor is never
* completely off-screen, and that x, y are always >= 0.
*/
tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, tmp);
+
+ if (IS_I9XX(dinfo)) {
+ OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+ }
}
void
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index ba1920159f52..10acda098b71 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -133,6 +133,7 @@
#define DPLL_VGA_MODE_DISABLE (1 << 28)
#define DPLL_P2_MASK 1
#define DPLL_P2_SHIFT 23
+#define DPLL_I9XX_P2_SHIFT 24
#define DPLL_P1_FORCE_DIV2 (1 << 21)
#define DPLL_P1_MASK 0x1f
#define DPLL_P1_SHIFT 16
@@ -155,29 +156,8 @@
/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
/* Clock values are in units of kHz */
#define PLL_REFCLK 48000
-#define MIN_VCO_FREQ 930000
-#define MAX_VCO_FREQ 1400000
#define MIN_CLOCK 25000
#define MAX_CLOCK 350000
-#define P_TRANSITION_CLOCK 165000
-#define MIN_M 108
-#define MAX_M 140
-#define MIN_M1 18
-#define MAX_M1 26
-#define MIN_M2 6
-#define MAX_M2 16
-#define MIN_P 4
-#define MAX_P 128
-#define MIN_P1 0
-#define MAX_P1 31
-#define MIN_N 3
-#define MAX_N 16
-
-#define CALC_VCLOCK(m1, m2, n, p1, p2) \
- ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
- (((p1) + 2) * (1 << (p2 + 1))))
-
-#define CALC_VCLOCK3(m, n, p) ((PLL_REFCLK * (m) / (n)) / (p))
/* Two pipes */
#define PIPE_A 0
@@ -522,8 +502,7 @@
/* function protoypes */
-extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
- int *chipset, int *mobile);
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
int *stolen_size);
extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index 4ef5cd19609d..b985dfad6c63 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -34,7 +34,7 @@ extra-y += $(call logo-cfiles,_clut224,ppm)
extra-y += $(call logo-cfiles,_gray256,pgm)
# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
-quiet_cmd_logo = LOGO $@
+quiet_cmd_logo = LOGO $@
cmd_logo = scripts/pnmtologo \
-t $(patsubst $*_%,%,$(notdir $(basename $<))) \
-n $(notdir $(basename $<)) -o $@ $<
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
index 8073a73f6f35..440272ad10e7 100644
--- a/drivers/video/matrox/g450_pll.c
+++ b/drivers/video/matrox/g450_pll.c
@@ -316,14 +316,24 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
case M_PIXEL_PLL_B:
case M_PIXEL_PLL_C:
{
- u_int8_t tmp;
+ u_int8_t tmp, xpwrctrl;
unsigned long flags;
matroxfb_DAC_lock_irqsave(flags);
+
+ xpwrctrl = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL);
+ matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl & ~M1064_XPWRCTRL_PANELPDN);
+ mga_outb(M_SEQ_INDEX, M_SEQ1);
+ mga_outb(M_SEQ_DATA, mga_inb(M_SEQ_DATA) | M_SEQ1_SCROFF);
tmp = matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL);
+ tmp |= M1064_XPIXCLKCTRL_DIS;
if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
- matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp | M1064_XPIXCLKCTRL_PLL_UP);
+ tmp |= M1064_XPIXCLKCTRL_PLL_UP;
}
+ matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp);
+ matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL, 0);
+ matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl);
+
matroxfb_DAC_unlock_irqrestore(flags);
}
{
@@ -418,6 +428,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
frequency to higher - with <= lowest wins, while
with < highest one wins */
if (delta <= deltaarray[idx-1]) {
+ /* all else being equal except VCO,
+ * choose VCO not near (within 1/16th or so) VCOmin
+ * (freqs near VCOmin aren't as stable)
+ */
+ if (delta == deltaarray[idx-1]
+ && vco != g450_mnp2vco(PMINFO mnparray[idx-1])
+ && vco < (pi->vcomin * 17 / 16)) {
+ break;
+ }
mnparray[idx] = mnparray[idx-1];
deltaarray[idx] = deltaarray[idx-1];
} else {
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
index 2e7238aa2432..56513a5d220b 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.h
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -40,6 +40,7 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XCURCOL1RED 0x0C
#define M1064_XCURCOL1GREEN 0x0D
#define M1064_XCURCOL1BLUE 0x0E
+#define M1064_XDVICLKCTRL 0x0F
#define M1064_XCURCOL2RED 0x10
#define M1064_XCURCOL2GREEN 0x11
#define M1064_XCURCOL2BLUE 0x12
@@ -144,6 +145,7 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XVIDPLLN 0x8F
#define M1064_XPWRCTRL 0xA0
+#define M1064_XPWRCTRL_PANELPDN 0x04
#define M1064_XPANMODE 0xA2
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index 3a3e1804c56a..b71737178d0d 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -672,6 +672,8 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
#define M_SEQ_INDEX 0x1FC4
#define M_SEQ_DATA 0x1FC5
+#define M_SEQ1 0x01
+#define M_SEQ1_SCROFF 0x20
#define M_MISC_REG_READ 0x1FCC
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index 743e7ad26acc..f85421bf7cb5 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -55,7 +55,7 @@ static struct fb_var_screeninfo maxinefb_defined = {
};
static struct fb_fix_screeninfo maxinefb_fix = {
- .id = "Maxine onboard graphics 1024x768x8",
+ .id = "Maxine",
.smem_len = (1024*768),
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -107,8 +107,6 @@ static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green,
static struct fb_ops maxinefb_ops = {
.owner = THIS_MODULE,
- .fb_get_fix = gen_get_fix,
- .fb_get_var = gen_get_var,
.fb_setcolreg = maxinefb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,